From fa89edd6019c3eaf11c8db98718c56297d8d5f7d Mon Sep 17 00:00:00 2001 From: Sehong Na Date: Sat, 31 May 2014 12:28:20 +0900 Subject: [PATCH 1/1] Initialize Tizen 2.3 --- COPYING | 504 + ChangeLog | 69 + INSTALL | 122 + MEMORY-LEAK | 13 + Makefile.am | 37 + Makefile.in | 745 ++ NOTES | 56 + TODO | 4 + acinclude.m4 | 24 + aclocal.m4 | 8957 ++++++++++++++++++ alsa-lib.manifest | 5 + alsalisp/Makefile.am | 8 + alsalisp/Makefile.in | 501 + alsalisp/alsalisp.c | 110 + aserver/COPYING | 340 + aserver/Makefile.am | 12 + aserver/Makefile.in | 543 ++ aserver/aserver.c | 1104 +++ autogen.sh | 7 + compile | 142 + config.guess | 1517 +++ config.sub | 1760 ++++ configure | 14772 ++++++++++++++++++++++++++++++ configure.in | 631 ++ debian/changelog | 111 + debian/compat | 1 + debian/control | 37 + debian/copyright | 30 + debian/dirs | 2 + debian/docs | 1 + debian/libasound2-dev.dirs | 3 + debian/libasound2-dev.install.in | 1 + debian/libasound2-sdk-dev.install.in | 4 + debian/libasound2.dirs | 2 + debian/libasound2.install.in | 4 + debian/rules | 140 + depcomp | 630 ++ doc/Makefile.am | 22 + doc/Makefile.in | 592 ++ doc/README.1st | 2 + doc/asoundrc.txt | 480 + doc/doxygen.cfg.in | 123 + doc/index.doxygen | 54 + doc/pictures/Makefile.am | 1 + doc/pictures/Makefile.in | 368 + doc/pictures/wave1.gif | Bin 0 -> 1715 bytes doc/pictures/wave2.gif | Bin 0 -> 1020 bytes gitcompile | 19 + include/Makefile.am | 90 + include/Makefile.in | 705 ++ include/alisp.h | 55 + include/alsa-symbols.h | 72 + include/aserver.h | 160 + include/asoundef.h | 310 + include/asoundlib-head.h | 48 + include/asoundlib-tail.h | 2 + include/conf.h | 207 + include/config.h.in | 170 + include/control.h | 588 ++ include/control_external.h | 265 + include/error.h | 78 + include/global.h | 159 + include/hwdep.h | 160 + include/iatomic.h | 1198 +++ include/input.h | 83 + include/list.h | 174 + include/local.h | 283 + include/mixer.h | 317 + include/mixer_abst.h | 112 + include/output.h | 86 + include/pcm.h | 1142 +++ include/pcm_external.h | 70 + include/pcm_extplug.h | 189 + include/pcm_ioplug.h | 217 + include/pcm_old.h | 230 + include/pcm_plugin.h | 202 + include/pcm_rate.h | 153 + include/rawmidi.h | 159 + include/search.h | 177 + include/seq.h | 737 ++ include/seq_event.h | 319 + include/seq_midi_event.h | 65 + include/seqmid.h | 490 + include/sound/Makefile.am | 6 + include/sound/Makefile.in | 470 + include/sound/asequencer.h | 678 ++ include/sound/asound.h | 957 ++ include/sound/asound_fm.h | 134 + include/sound/asoundef.h | 227 + include/sound/emu10k1.h | 349 + include/sound/hdsp.h | 112 + include/sound/hdspm.h | 229 + include/sound/sb16_csp.h | 115 + include/sound/sscape_ioctl.h | 21 + include/sound/type_compat.h | 40 + include/sys.h | 2 + include/timer.h | 259 + include/use-case.h | 381 + install-sh | 520 ++ ltconfig | 0 ltmain.sh | 8413 +++++++++++++++++ m4/attributes.m4 | 311 + m4/libtool.m4 | 7377 +++++++++++++++ m4/ltoptions.m4 | 368 + m4/ltsugar.m4 | 123 + m4/ltversion.m4 | 23 + m4/lt~obsolete.m4 | 92 + missing | 376 + modules/Makefile.am | 3 + modules/Makefile.in | 570 ++ modules/mixer/Makefile.am | 1 + modules/mixer/Makefile.in | 570 ++ modules/mixer/simple/Makefile.am | 35 + modules/mixer/simple/Makefile.in | 616 ++ modules/mixer/simple/ac97.c | 89 + modules/mixer/simple/hda.c | 90 + modules/mixer/simple/python.c | 1046 +++ modules/mixer/simple/sbase.c | 587 ++ modules/mixer/simple/sbase.h | 111 + modules/mixer/simple/sbasedl.c | 106 + packaging/alsa-lib.spec | 102 + src/Makefile.am | 93 + src/Makefile.in | 787 ++ src/Versions.in | 131 + src/alisp/Makefile.am | 11 + src/alisp/Makefile.in | 492 + src/alisp/alisp.c | 3495 +++++++ src/alisp/alisp_local.h | 151 + src/alisp/alisp_snd.c | 943 ++ src/async.c | 206 + src/compat/Makefile.am | 8 + src/compat/Makefile.in | 502 + src/compat/empty.c | 0 src/compat/hsearch_r.c | 236 + src/conf.c | 4770 ++++++++++ src/conf/Makefile.am | 15 + src/conf/Makefile.in | 624 ++ src/conf/alsa.conf | 609 ++ src/conf/cards/AACI.conf | 47 + src/conf/cards/ATIIXP-MODEM.conf | 22 + src/conf/cards/ATIIXP-SPDMA.conf | 165 + src/conf/cards/ATIIXP.conf | 184 + src/conf/cards/AU8810.conf | 38 + src/conf/cards/AU8820.conf | 14 + src/conf/cards/AU8830.conf | 42 + src/conf/cards/Audigy.conf | 318 + src/conf/cards/Audigy2.conf | 425 + src/conf/cards/Aureon51.conf | 179 + src/conf/cards/Aureon71.conf | 190 + src/conf/cards/CA0106.conf | 280 + src/conf/cards/CMI8338-SWIEC.conf | 129 + src/conf/cards/CMI8338.conf | 143 + src/conf/cards/CMI8738-MC6.conf | 161 + src/conf/cards/CMI8738-MC8.conf | 230 + src/conf/cards/CMI8788.conf | 126 + src/conf/cards/CS46xx.conf | 218 + src/conf/cards/EMU10K1.conf | 310 + src/conf/cards/EMU10K1X.conf | 201 + src/conf/cards/ENS1370.conf | 107 + src/conf/cards/ENS1371.conf | 134 + src/conf/cards/ES1968.conf | 12 + src/conf/cards/FM801.conf | 87 + src/conf/cards/GUS.conf | 19 + src/conf/cards/HDA-Intel.conf | 295 + src/conf/cards/ICE1712.conf | 141 + src/conf/cards/ICE1724.conf | 224 + src/conf/cards/ICH-MODEM.conf | 15 + src/conf/cards/ICH.conf | 222 + src/conf/cards/ICH4.conf | 213 + src/conf/cards/Maestro3.conf | 38 + src/conf/cards/Makefile.am | 74 + src/conf/cards/Makefile.in | 464 + src/conf/cards/NFORCE.conf | 295 + src/conf/cards/PC-Speaker.conf | 52 + src/conf/cards/PMac.conf | 37 + src/conf/cards/PMacToonie.conf | 51 + src/conf/cards/PS3.conf | 85 + src/conf/cards/RME9636.conf | 61 + src/conf/cards/RME9652.conf | 61 + src/conf/cards/SB-XFi.conf | 108 + src/conf/cards/SI7018.conf | 166 + src/conf/cards/SI7018/sndoc-mixer.alisp | 11 + src/conf/cards/SI7018/sndop-mixer.alisp | 11 + src/conf/cards/TRID4DWAVENX.conf | 129 + src/conf/cards/USB-Audio.conf | 375 + src/conf/cards/VIA686A.conf | 89 + src/conf/cards/VIA8233.conf | 200 + src/conf/cards/VIA8233A.conf | 204 + src/conf/cards/VIA8237.conf | 190 + src/conf/cards/VX222.conf | 61 + src/conf/cards/VXPocket.conf | 61 + src/conf/cards/VXPocket440.conf | 110 + src/conf/cards/YMF744.conf | 108 + src/conf/cards/aliases.alisp | 29 + src/conf/cards/aliases.conf | 61 + src/conf/pcm/Makefile.am | 12 + src/conf/pcm/Makefile.in | 426 + src/conf/pcm/center_lfe.conf | 58 + src/conf/pcm/default.conf | 57 + src/conf/pcm/dmix.conf | 115 + src/conf/pcm/dpl.conf | 43 + src/conf/pcm/dsnoop.conf | 115 + src/conf/pcm/front.conf | 58 + src/conf/pcm/hdmi.conf | 83 + src/conf/pcm/iec958.conf | 83 + src/conf/pcm/modem.conf | 106 + src/conf/pcm/rear.conf | 58 + src/conf/pcm/side.conf | 58 + src/conf/pcm/surround40.conf | 59 + src/conf/pcm/surround41.conf | 66 + src/conf/pcm/surround50.conf | 66 + src/conf/pcm/surround51.conf | 61 + src/conf/pcm/surround71.conf | 63 + src/conf/smixer.conf | 13 + src/conf/sndo-mixer.alisp | 115 + src/confmisc.c | 1304 +++ src/control/Makefile.am | 18 + src/control/Makefile.in | 512 ++ src/control/cards.c | 216 + src/control/control.c | 2570 ++++++ src/control/control_ext.c | 691 ++ src/control/control_hw.c | 458 + src/control/control_local.h | 100 + src/control/control_shm.c | 679 ++ src/control/control_symbols.c | 37 + src/control/ctl_symbols_list.c | 2 + src/control/ctlparse.c | 351 + src/control/hcontrol.c | 1015 ++ src/control/namehint.c | 687 ++ src/control/setup.c | 661 ++ src/control/tlv.c | 502 + src/dlmisc.c | 311 + src/error.c | 150 + src/hwdep/Makefile.am | 8 + src/hwdep/Makefile.in | 492 + src/hwdep/hwdep.c | 760 ++ src/hwdep/hwdep_hw.c | 190 + src/hwdep/hwdep_local.h | 46 + src/hwdep/hwdep_symbols.c | 34 + src/input.c | 337 + src/mixer/Makefile.am | 10 + src/mixer/Makefile.in | 496 + src/mixer/bag.c | 73 + src/mixer/mixer.c | 1083 +++ src/mixer/mixer_local.h | 82 + src/mixer/mixer_simple.h | 31 + src/mixer/simple.c | 1055 +++ src/mixer/simple_abst.c | 420 + src/mixer/simple_none.c | 1727 ++++ src/names.c | 65 + src/output.c | 380 + src/pcm/Makefile.am | 117 + src/pcm/Makefile.in | 786 ++ src/pcm/atomic.c | 43 + src/pcm/interval.c | 441 + src/pcm/interval.h | 80 + src/pcm/interval_inline.h | 157 + src/pcm/ladspa.h | 603 ++ src/pcm/mask.c | 28 + src/pcm/mask.h | 57 + src/pcm/mask_inline.h | 299 + src/pcm/pcm.c | 7524 +++++++++++++++ src/pcm/pcm_adpcm.c | 679 ++ src/pcm/pcm_alaw.c | 553 ++ src/pcm/pcm_asym.c | 119 + src/pcm/pcm_copy.c | 299 + src/pcm/pcm_direct.c | 1677 ++++ src/pcm/pcm_direct.h | 306 + src/pcm/pcm_dmix.c | 1326 +++ src/pcm/pcm_dmix_generic.c | 535 ++ src/pcm/pcm_dmix_i386.c | 133 + src/pcm/pcm_dmix_i386.h | 559 ++ src/pcm/pcm_dmix_x86_64.c | 100 + src/pcm/pcm_dmix_x86_64.h | 341 + src/pcm/pcm_dshare.c | 939 ++ src/pcm/pcm_dsnoop.c | 835 ++ src/pcm/pcm_empty.c | 110 + src/pcm/pcm_ext_parm.h | 41 + src/pcm/pcm_extplug.c | 813 ++ src/pcm/pcm_file.c | 965 ++ src/pcm/pcm_generic.c | 326 + src/pcm/pcm_generic.h | 151 + src/pcm/pcm_hooks.c | 722 ++ src/pcm/pcm_hw.c | 1570 ++++ src/pcm/pcm_iec958.c | 679 ++ src/pcm/pcm_ioplug.c | 1072 +++ src/pcm/pcm_ladspa.c | 1803 ++++ src/pcm/pcm_lfloat.c | 537 ++ src/pcm/pcm_linear.c | 582 ++ src/pcm/pcm_local.h | 972 ++ src/pcm/pcm_meter.c | 1228 +++ src/pcm/pcm_misc.c | 833 ++ src/pcm/pcm_mmap.c | 633 ++ src/pcm/pcm_mmap_emul.c | 512 ++ src/pcm/pcm_mulaw.c | 568 ++ src/pcm/pcm_multi.c | 1214 +++ src/pcm/pcm_null.c | 432 + src/pcm/pcm_params.c | 2372 +++++ src/pcm/pcm_plug.c | 1323 +++ src/pcm/pcm_plugin.c | 575 ++ src/pcm/pcm_plugin.h | 152 + src/pcm/pcm_rate.c | 1539 ++++ src/pcm/pcm_rate_linear.c | 447 + src/pcm/pcm_route.c | 1172 +++ src/pcm/pcm_share.c | 1723 ++++ src/pcm/pcm_shm.c | 956 ++ src/pcm/pcm_simple.c | 305 + src/pcm/pcm_softvol.c | 1100 +++ src/pcm/pcm_symbols.c | 64 + src/pcm/pcm_symbols_list.c | 27 + src/pcm/plugin_ops.h | 1106 +++ src/pcm/scopes/Makefile.am | 9 + src/pcm/scopes/Makefile.in | 551 ++ src/pcm/scopes/level.c | 271 + src/rawmidi/Makefile.am | 12 + src/rawmidi/Makefile.in | 500 + src/rawmidi/rawmidi.c | 1006 ++ src/rawmidi/rawmidi_hw.c | 361 + src/rawmidi/rawmidi_local.h | 61 + src/rawmidi/rawmidi_symbols.c | 36 + src/rawmidi/rawmidi_virt.c | 469 + src/seq/Makefile.am | 13 + src/seq/Makefile.in | 503 + src/seq/seq.c | 4783 ++++++++++ src/seq/seq_event.c | 49 + src/seq/seq_hw.c | 557 ++ src/seq/seq_local.h | 97 + src/seq/seq_midi_event.c | 727 ++ src/seq/seq_old.c | 222 + src/seq/seq_symbols.c | 34 + src/seq/seqmid.c | 427 + src/shmarea.c | 108 + src/socket.c | 158 + src/timer/Makefile.am | 9 + src/timer/Makefile.in | 497 + src/timer/timer.c | 959 ++ src/timer/timer_hw.c | 349 + src/timer/timer_local.h | 76 + src/timer/timer_query.c | 594 ++ src/timer/timer_query_hw.c | 146 + src/timer/timer_symbols.c | 46 + src/ucm/Makefile.am | 10 + src/ucm/Makefile.in | 499 + src/ucm/libucm.la | 41 + src/ucm/main.c | 1649 ++++ src/ucm/parser.c | 1329 +++ src/ucm/ucm_local.h | 221 + src/ucm/utils.c | 237 + src/userfile.c | 72 + test/Makefile.am | 25 + test/Makefile.in | 758 ++ test/client_event_filter.c | 46 + test/control.c | 106 + test/latency.c | 689 ++ test/lsb/Makefile.am | 7 + test/lsb/Makefile.in | 608 ++ test/lsb/config.c | 582 ++ test/lsb/midi_event.c | 371 + test/lsb/test.h | 29 + test/midifile.3 | 336 + test/midifile.c | 1173 +++ test/midifile.h | 132 + test/midiloop.c | 190 + test/namehint.c | 22 + test/oldapi.c | 42 + test/pcm.c | 925 ++ test/pcm_min.c | 51 + test/playmidi1.c | 617 ++ test/queue_timer.c | 128 + test/rawmidi.c | 241 + test/seq-decoder.c | 353 + test/seq-sender.c | 272 + test/seq.c | 233 + test/timer.c | 193 + utils/Makefile.am | 13 + utils/Makefile.in | 451 + utils/alsa-lib.spec.in | 75 + utils/alsa.m4 | 141 + utils/alsa.pc.in | 14 + utils/buildrpm | 46 + version | 1 + 381 files changed, 183672 insertions(+) create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 MEMORY-LEAK create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NOTES create mode 100644 TODO create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100755 alsa-lib.manifest create mode 100644 alsalisp/Makefile.am create mode 100644 alsalisp/Makefile.in create mode 100644 alsalisp/alsalisp.c create mode 100644 aserver/COPYING create mode 100644 aserver/Makefile.am create mode 100644 aserver/Makefile.in create mode 100644 aserver/aserver.c create mode 100755 autogen.sh create mode 100755 compile create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/libasound2-dev.dirs create mode 100644 debian/libasound2-dev.install.in create mode 100644 debian/libasound2-sdk-dev.install.in create mode 100644 debian/libasound2.dirs create mode 100644 debian/libasound2.install.in create mode 100755 debian/rules create mode 100755 depcomp create mode 100644 doc/Makefile.am create mode 100644 doc/Makefile.in create mode 100644 doc/README.1st create mode 100644 doc/asoundrc.txt create mode 100644 doc/doxygen.cfg.in create mode 100644 doc/index.doxygen create mode 100644 doc/pictures/Makefile.am create mode 100644 doc/pictures/Makefile.in create mode 100644 doc/pictures/wave1.gif create mode 100644 doc/pictures/wave2.gif create mode 100755 gitcompile create mode 100644 include/Makefile.am create mode 100644 include/Makefile.in create mode 100644 include/alisp.h create mode 100644 include/alsa-symbols.h create mode 100644 include/aserver.h create mode 100644 include/asoundef.h create mode 100644 include/asoundlib-head.h create mode 100644 include/asoundlib-tail.h create mode 100644 include/conf.h create mode 100644 include/config.h.in create mode 100644 include/control.h create mode 100644 include/control_external.h create mode 100644 include/error.h create mode 100644 include/global.h create mode 100644 include/hwdep.h create mode 100644 include/iatomic.h create mode 100644 include/input.h create mode 100644 include/list.h create mode 100644 include/local.h create mode 100644 include/mixer.h create mode 100644 include/mixer_abst.h create mode 100644 include/output.h create mode 100644 include/pcm.h create mode 100644 include/pcm_external.h create mode 100644 include/pcm_extplug.h create mode 100644 include/pcm_ioplug.h create mode 100644 include/pcm_old.h create mode 100644 include/pcm_plugin.h create mode 100644 include/pcm_rate.h create mode 100644 include/rawmidi.h create mode 100644 include/search.h create mode 100644 include/seq.h create mode 100644 include/seq_event.h create mode 100644 include/seq_midi_event.h create mode 100644 include/seqmid.h create mode 100644 include/sound/Makefile.am create mode 100644 include/sound/Makefile.in create mode 100644 include/sound/asequencer.h create mode 100644 include/sound/asound.h create mode 100644 include/sound/asound_fm.h create mode 100644 include/sound/asoundef.h create mode 100644 include/sound/emu10k1.h create mode 100644 include/sound/hdsp.h create mode 100644 include/sound/hdspm.h create mode 100644 include/sound/sb16_csp.h create mode 100644 include/sound/sscape_ioctl.h create mode 100644 include/sound/type_compat.h create mode 100644 include/sys.h create mode 100644 include/timer.h create mode 100644 include/use-case.h create mode 100755 install-sh create mode 100644 ltconfig create mode 100755 ltmain.sh create mode 100644 m4/attributes.m4 create mode 100644 m4/libtool.m4 create mode 100644 m4/ltoptions.m4 create mode 100644 m4/ltsugar.m4 create mode 100644 m4/ltversion.m4 create mode 100644 m4/lt~obsolete.m4 create mode 100755 missing create mode 100644 modules/Makefile.am create mode 100644 modules/Makefile.in create mode 100644 modules/mixer/Makefile.am create mode 100644 modules/mixer/Makefile.in create mode 100644 modules/mixer/simple/Makefile.am create mode 100644 modules/mixer/simple/Makefile.in create mode 100644 modules/mixer/simple/ac97.c create mode 100644 modules/mixer/simple/hda.c create mode 100644 modules/mixer/simple/python.c create mode 100644 modules/mixer/simple/sbase.c create mode 100644 modules/mixer/simple/sbase.h create mode 100644 modules/mixer/simple/sbasedl.c create mode 100644 packaging/alsa-lib.spec create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/Versions.in create mode 100644 src/alisp/Makefile.am create mode 100644 src/alisp/Makefile.in create mode 100644 src/alisp/alisp.c create mode 100644 src/alisp/alisp_local.h create mode 100644 src/alisp/alisp_snd.c create mode 100644 src/async.c create mode 100644 src/compat/Makefile.am create mode 100644 src/compat/Makefile.in create mode 100644 src/compat/empty.c create mode 100644 src/compat/hsearch_r.c create mode 100644 src/conf.c create mode 100644 src/conf/Makefile.am create mode 100644 src/conf/Makefile.in create mode 100644 src/conf/alsa.conf create mode 100644 src/conf/cards/AACI.conf create mode 100644 src/conf/cards/ATIIXP-MODEM.conf create mode 100644 src/conf/cards/ATIIXP-SPDMA.conf create mode 100644 src/conf/cards/ATIIXP.conf create mode 100644 src/conf/cards/AU8810.conf create mode 100644 src/conf/cards/AU8820.conf create mode 100644 src/conf/cards/AU8830.conf create mode 100644 src/conf/cards/Audigy.conf create mode 100644 src/conf/cards/Audigy2.conf create mode 100644 src/conf/cards/Aureon51.conf create mode 100644 src/conf/cards/Aureon71.conf create mode 100644 src/conf/cards/CA0106.conf create mode 100644 src/conf/cards/CMI8338-SWIEC.conf create mode 100644 src/conf/cards/CMI8338.conf create mode 100644 src/conf/cards/CMI8738-MC6.conf create mode 100644 src/conf/cards/CMI8738-MC8.conf create mode 100644 src/conf/cards/CMI8788.conf create mode 100644 src/conf/cards/CS46xx.conf create mode 100644 src/conf/cards/EMU10K1.conf create mode 100644 src/conf/cards/EMU10K1X.conf create mode 100644 src/conf/cards/ENS1370.conf create mode 100644 src/conf/cards/ENS1371.conf create mode 100644 src/conf/cards/ES1968.conf create mode 100644 src/conf/cards/FM801.conf create mode 100644 src/conf/cards/GUS.conf create mode 100644 src/conf/cards/HDA-Intel.conf create mode 100644 src/conf/cards/ICE1712.conf create mode 100644 src/conf/cards/ICE1724.conf create mode 100644 src/conf/cards/ICH-MODEM.conf create mode 100644 src/conf/cards/ICH.conf create mode 100644 src/conf/cards/ICH4.conf create mode 100644 src/conf/cards/Maestro3.conf create mode 100644 src/conf/cards/Makefile.am create mode 100644 src/conf/cards/Makefile.in create mode 100644 src/conf/cards/NFORCE.conf create mode 100644 src/conf/cards/PC-Speaker.conf create mode 100644 src/conf/cards/PMac.conf create mode 100644 src/conf/cards/PMacToonie.conf create mode 100644 src/conf/cards/PS3.conf create mode 100644 src/conf/cards/RME9636.conf create mode 100644 src/conf/cards/RME9652.conf create mode 100644 src/conf/cards/SB-XFi.conf create mode 100644 src/conf/cards/SI7018.conf create mode 100644 src/conf/cards/SI7018/sndoc-mixer.alisp create mode 100644 src/conf/cards/SI7018/sndop-mixer.alisp create mode 100644 src/conf/cards/TRID4DWAVENX.conf create mode 100644 src/conf/cards/USB-Audio.conf create mode 100644 src/conf/cards/VIA686A.conf create mode 100644 src/conf/cards/VIA8233.conf create mode 100644 src/conf/cards/VIA8233A.conf create mode 100644 src/conf/cards/VIA8237.conf create mode 100644 src/conf/cards/VX222.conf create mode 100644 src/conf/cards/VXPocket.conf create mode 100644 src/conf/cards/VXPocket440.conf create mode 100644 src/conf/cards/YMF744.conf create mode 100644 src/conf/cards/aliases.alisp create mode 100644 src/conf/cards/aliases.conf create mode 100644 src/conf/pcm/Makefile.am create mode 100644 src/conf/pcm/Makefile.in create mode 100644 src/conf/pcm/center_lfe.conf create mode 100644 src/conf/pcm/default.conf create mode 100644 src/conf/pcm/dmix.conf create mode 100644 src/conf/pcm/dpl.conf create mode 100644 src/conf/pcm/dsnoop.conf create mode 100644 src/conf/pcm/front.conf create mode 100644 src/conf/pcm/hdmi.conf create mode 100644 src/conf/pcm/iec958.conf create mode 100644 src/conf/pcm/modem.conf create mode 100644 src/conf/pcm/rear.conf create mode 100644 src/conf/pcm/side.conf create mode 100644 src/conf/pcm/surround40.conf create mode 100644 src/conf/pcm/surround41.conf create mode 100644 src/conf/pcm/surround50.conf create mode 100644 src/conf/pcm/surround51.conf create mode 100644 src/conf/pcm/surround71.conf create mode 100644 src/conf/smixer.conf create mode 100644 src/conf/sndo-mixer.alisp create mode 100644 src/confmisc.c create mode 100644 src/control/Makefile.am create mode 100644 src/control/Makefile.in create mode 100644 src/control/cards.c create mode 100644 src/control/control.c create mode 100644 src/control/control_ext.c create mode 100644 src/control/control_hw.c create mode 100644 src/control/control_local.h create mode 100644 src/control/control_shm.c create mode 100644 src/control/control_symbols.c create mode 100644 src/control/ctl_symbols_list.c create mode 100644 src/control/ctlparse.c create mode 100644 src/control/hcontrol.c create mode 100644 src/control/namehint.c create mode 100644 src/control/setup.c create mode 100644 src/control/tlv.c create mode 100644 src/dlmisc.c create mode 100644 src/error.c create mode 100644 src/hwdep/Makefile.am create mode 100644 src/hwdep/Makefile.in create mode 100644 src/hwdep/hwdep.c create mode 100644 src/hwdep/hwdep_hw.c create mode 100644 src/hwdep/hwdep_local.h create mode 100644 src/hwdep/hwdep_symbols.c create mode 100644 src/input.c create mode 100644 src/mixer/Makefile.am create mode 100644 src/mixer/Makefile.in create mode 100644 src/mixer/bag.c create mode 100644 src/mixer/mixer.c create mode 100644 src/mixer/mixer_local.h create mode 100644 src/mixer/mixer_simple.h create mode 100644 src/mixer/simple.c create mode 100644 src/mixer/simple_abst.c create mode 100644 src/mixer/simple_none.c create mode 100644 src/names.c create mode 100644 src/output.c create mode 100644 src/pcm/Makefile.am create mode 100644 src/pcm/Makefile.in create mode 100644 src/pcm/atomic.c create mode 100644 src/pcm/interval.c create mode 100644 src/pcm/interval.h create mode 100644 src/pcm/interval_inline.h create mode 100644 src/pcm/ladspa.h create mode 100644 src/pcm/mask.c create mode 100644 src/pcm/mask.h create mode 100644 src/pcm/mask_inline.h create mode 100644 src/pcm/pcm.c create mode 100644 src/pcm/pcm_adpcm.c create mode 100644 src/pcm/pcm_alaw.c create mode 100644 src/pcm/pcm_asym.c create mode 100644 src/pcm/pcm_copy.c create mode 100644 src/pcm/pcm_direct.c create mode 100644 src/pcm/pcm_direct.h create mode 100644 src/pcm/pcm_dmix.c create mode 100644 src/pcm/pcm_dmix_generic.c create mode 100644 src/pcm/pcm_dmix_i386.c create mode 100644 src/pcm/pcm_dmix_i386.h create mode 100644 src/pcm/pcm_dmix_x86_64.c create mode 100644 src/pcm/pcm_dmix_x86_64.h create mode 100644 src/pcm/pcm_dshare.c create mode 100644 src/pcm/pcm_dsnoop.c create mode 100644 src/pcm/pcm_empty.c create mode 100644 src/pcm/pcm_ext_parm.h create mode 100644 src/pcm/pcm_extplug.c create mode 100644 src/pcm/pcm_file.c create mode 100644 src/pcm/pcm_generic.c create mode 100644 src/pcm/pcm_generic.h create mode 100644 src/pcm/pcm_hooks.c create mode 100644 src/pcm/pcm_hw.c create mode 100644 src/pcm/pcm_iec958.c create mode 100644 src/pcm/pcm_ioplug.c create mode 100644 src/pcm/pcm_ladspa.c create mode 100644 src/pcm/pcm_lfloat.c create mode 100644 src/pcm/pcm_linear.c create mode 100644 src/pcm/pcm_local.h create mode 100644 src/pcm/pcm_meter.c create mode 100644 src/pcm/pcm_misc.c create mode 100644 src/pcm/pcm_mmap.c create mode 100644 src/pcm/pcm_mmap_emul.c create mode 100644 src/pcm/pcm_mulaw.c create mode 100644 src/pcm/pcm_multi.c create mode 100644 src/pcm/pcm_null.c create mode 100644 src/pcm/pcm_params.c create mode 100644 src/pcm/pcm_plug.c create mode 100644 src/pcm/pcm_plugin.c create mode 100644 src/pcm/pcm_plugin.h create mode 100644 src/pcm/pcm_rate.c create mode 100644 src/pcm/pcm_rate_linear.c create mode 100644 src/pcm/pcm_route.c create mode 100644 src/pcm/pcm_share.c create mode 100644 src/pcm/pcm_shm.c create mode 100644 src/pcm/pcm_simple.c create mode 100644 src/pcm/pcm_softvol.c create mode 100644 src/pcm/pcm_symbols.c create mode 100644 src/pcm/pcm_symbols_list.c create mode 100644 src/pcm/plugin_ops.h create mode 100644 src/pcm/scopes/Makefile.am create mode 100644 src/pcm/scopes/Makefile.in create mode 100644 src/pcm/scopes/level.c create mode 100644 src/rawmidi/Makefile.am create mode 100644 src/rawmidi/Makefile.in create mode 100644 src/rawmidi/rawmidi.c create mode 100644 src/rawmidi/rawmidi_hw.c create mode 100644 src/rawmidi/rawmidi_local.h create mode 100644 src/rawmidi/rawmidi_symbols.c create mode 100644 src/rawmidi/rawmidi_virt.c create mode 100644 src/seq/Makefile.am create mode 100644 src/seq/Makefile.in create mode 100644 src/seq/seq.c create mode 100644 src/seq/seq_event.c create mode 100644 src/seq/seq_hw.c create mode 100644 src/seq/seq_local.h create mode 100644 src/seq/seq_midi_event.c create mode 100644 src/seq/seq_old.c create mode 100644 src/seq/seq_symbols.c create mode 100644 src/seq/seqmid.c create mode 100644 src/shmarea.c create mode 100644 src/socket.c create mode 100644 src/timer/Makefile.am create mode 100644 src/timer/Makefile.in create mode 100644 src/timer/timer.c create mode 100644 src/timer/timer_hw.c create mode 100644 src/timer/timer_local.h create mode 100644 src/timer/timer_query.c create mode 100644 src/timer/timer_query_hw.c create mode 100644 src/timer/timer_symbols.c create mode 100644 src/ucm/Makefile.am create mode 100644 src/ucm/Makefile.in create mode 100644 src/ucm/libucm.la create mode 100644 src/ucm/main.c create mode 100644 src/ucm/parser.c create mode 100644 src/ucm/ucm_local.h create mode 100644 src/ucm/utils.c create mode 100644 src/userfile.c create mode 100644 test/Makefile.am create mode 100644 test/Makefile.in create mode 100644 test/client_event_filter.c create mode 100644 test/control.c create mode 100644 test/latency.c create mode 100644 test/lsb/Makefile.am create mode 100644 test/lsb/Makefile.in create mode 100644 test/lsb/config.c create mode 100644 test/lsb/midi_event.c create mode 100644 test/lsb/test.h create mode 100644 test/midifile.3 create mode 100644 test/midifile.c create mode 100644 test/midifile.h create mode 100644 test/midiloop.c create mode 100644 test/namehint.c create mode 100644 test/oldapi.c create mode 100644 test/pcm.c create mode 100644 test/pcm_min.c create mode 100644 test/playmidi1.c create mode 100644 test/queue_timer.c create mode 100644 test/rawmidi.c create mode 100644 test/seq-decoder.c create mode 100644 test/seq-sender.c create mode 100644 test/seq.c create mode 100644 test/timer.c create mode 100644 utils/Makefile.am create mode 100644 utils/Makefile.in create mode 100644 utils/alsa-lib.spec.in create mode 100644 utils/alsa.m4 create mode 100644 utils/alsa.pc.in create mode 100755 utils/buildrpm create mode 100644 version diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..22df356 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,69 @@ +* update to libtool 1.3.3 + +0.1.3 -> 0.2.0 + +* added snd_pcm_loopback_block_mode to PCM loopback interface +* fixups in header files (according to documentation) +* version is now compatible with driver + +0.1.2 -> 0.1.3 + +* added PCM loopback interface + +0.1.1 -> 0.1.2 + +* bug fixes in open() functions + +0.1.0 -> 0.1.1 + +* added more switch functions to control interface + +0.0.9 -> 0.1.0 + +* renamed soundlib.h to asoundlib.h +* renamed libraries from libsound to libasound +* big API changes + - added switches interfaces +* added RawMIDI API + +0.0.8 -> 0.0.9 + +* Makefile and configure.in changes + - added check for alsa driver package + - added spec file for RPM + +0.0.7 -> 0.0.8 + +* added LGPL notice to all source and header files + +0.0.6 -> 0.0.7 + +* added snd_cards_name function + +0.0.5 -> 0.0.6 + +* fixed SND_PCM_OPEN constants + +0.0.4 -> 0.0.5 + +* added snd_cards_mask function +* added info functions for pcm playback/record in control interface +* fixed Makefile bugs for shared library (added -fPIC) + +0.0.3 -> 0.0.4 + +* changed COPYING policy from GPL to LGPL +* fixed bug in snd_mixer_channel_read & write +* added mixer exact support +* added pcm time mode support +* 'make install' is now possible + +0.0.2 -> 0.0.3 + +* corrected documentation + +0.0.1 -> 0.0.2 + +* added file COPYING +* added documentation in sgml + plan.txt +* minor changes in API for MIXER & PCM diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..91a8648 --- /dev/null +++ b/INSTALL @@ -0,0 +1,122 @@ + + ALSA library installation + ========================= + +Installation from tarball +------------------------- + +For installation you can use these commands: + + ./configure + make install + + +Compilation from HG sources +--------------------------- + +You need also GNU packages automake and libtool installed in your system +to compile HG (Mercurial) sources of alsa-lib package. + +For compilation you can use these commands: + + libtoolize --force --copy --automake + aclocal + autoheader + automake --foreign --copy --add-missing + autoconf + ./configure + make + +The included hgcompile script does this job for you. + +Note: Some automake packages have missing aclocal program. Use newer version + in the case. + + +Compilation of static library +----------------------------- + +If you would like to use the static ALSA library, you need to use these +options for the configure script: + + ./configure --enable-shared=no --enable-static=yes + +Unfortunately, due to bug in the libtool script, the shared and static +library cannot be built together. + + +Partial Builds +-------------- + +You can choose the core components to build via --enable-* or --disable-* +configure option for reducing the size of libasound. The selectable +components are: pcm, mixer, rawmidi, hwdep, seq and instr. +For example, --disable-rawmidi will prevent to build the stuff related +with raw MIDI. As default, all components are enabled. + +The PCM plugins to build can be selected via --with-pcm-plugins +configure option. Multiple plugins can be passed by separation with +comma. For example, to select _only_ rate and linear plugins (and +disable other plugins), pass + --with-pcm-plugins=rate,linear +Note that "hw" plugin is always enabled. +Passing "all" will select all available plugins (which is the default +behavior). + +When you select "plug" plugin, copy and linear plugins will be +automatically selected, too. That is, the linear-format and +access-type conversions are always available with plug layer. +The other conversions of plug (channel shrink/expansion, rate, +non-linear and float conversions) are enabled when the corresponding +plugin is selected, too. + + +Configuration for cross-compilation +----------------------------------- + +When you would like to cross-compile ALSA library (e.g. compile on +i686 host but for arm architecture) you will need to call ./configure +script with additional parameters: + +CC=arm-linux-gcc ./configure --target=arm-linux + +In this example host where the library is build is guessed (should be +given with --host=platform) and target for which is the library build is +Linux on ARM architecture. You should omit setting 'CC' variable and +cross-compiler will be guessed too. + +So simplest version would be: + +./configure --target=arm-linux + +For platform names in the form cpu-vendor-os (or aliases for this) +you should look in 'config.guess' script. Target and all paths +used here are only examples and should not be directly applicable to +your system. + +Configuration for machines without FPU +-------------------------------------- + +If your machine does not have FP unit, you should use '--with-softfloat' +option. This option disables usage of float numbers in PCM route plugin. +ALSA could then leave much more CPU cycles for your applications, but you +could still need some floating point emulator. + +Jack plugin +----------- + +JACK plugin is moved to alsa-plugins package. + +Trouble Shooting +---------------- + +* Install path on Fedora Core 3 + + FC3 installs its system ALSA library to /lib instead of /usr/lib. + Specify --libdir=/lib to configure to overwrite it with the new library, + or run like + + # ln -sf /usr/lib/libasound.so.2.0.0 /lib/libasound.so.2.0.0 + + to make symlink to the new path. + Note that /lib might be /lib64 on 64bit architecture. diff --git a/MEMORY-LEAK b/MEMORY-LEAK new file mode 100644 index 0000000..d9677d8 --- /dev/null +++ b/MEMORY-LEAK @@ -0,0 +1,13 @@ + + + Memory leaks - really? + ---------------------- + +Note that some developers are thinking that the ALSA library has some memory +leaks. Sure, it can be truth, but before contacting us, please, be sure that +these leaks are not forced. + +The biggest reported leak is that the global configuration is cached for +next usage. If you do not want this feature, simply, call +snd_config_update_free_global() after all snd_*_open*() calls. This function +will free the cache. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..f0c39c1 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,37 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS=doc include src +if BUILD_MODULES +SUBDIRS += modules +endif +if BUILD_PCM_PLUGIN_SHM +SUBDIRS += aserver +endif +if BUILD_MIXER +if BUILD_ALISP +SUBDIRS += alsalisp +endif +endif +SUBDIRS += test utils +EXTRA_DIST=ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ + depcomp version MEMORY-LEAK m4/attributes.m4 +AUTOMAKE_OPTIONS=foreign + +INCLUDES=-I$(top_srcdir)/include + +rpm: dist + $(MAKE) -C utils rpm + +dist-hook: + -chmod -R a+r $(distdir) + @if ! test -z "$(AMTAR)"; then \ + $(AMTAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \ + else \ + $(TAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \ + fi + +doc-dummy: + +doc: doc-dummy + $(MAKE) -C include all + $(MAKE) -C doc doc diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..b0329cc --- /dev/null +++ b/Makefile.in @@ -0,0 +1,745 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_MODULES_TRUE@am__append_1 = modules +@BUILD_PCM_PLUGIN_SHM_TRUE@am__append_2 = aserver +@BUILD_ALISP_TRUE@@BUILD_MIXER_TRUE@am__append_3 = alsalisp +subdir = . +DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/configure COPYING \ + ChangeLog INSTALL TODO config.guess config.sub depcomp \ + install-sh ltconfig ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = doc include src modules aserver alsalisp test utils +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = doc include src $(am__append_1) $(am__append_2) \ + $(am__append_3) test utils +EXTRA_DIST = ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ + depcomp version MEMORY-LEAK m4/attributes.m4 + +AUTOMAKE_OPTIONS = foreign +INCLUDES = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-hook dist-lzma dist-shar dist-tarZ dist-xz \ + dist-zip distcheck distclean distclean-generic \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am + + +rpm: dist + $(MAKE) -C utils rpm + +dist-hook: + -chmod -R a+r $(distdir) + @if ! test -z "$(AMTAR)"; then \ + $(AMTAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \ + else \ + $(TAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \ + fi + +doc-dummy: + +doc: doc-dummy + $(MAKE) -C include all + $(MAKE) -C doc doc + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..b318d1f --- /dev/null +++ b/NOTES @@ -0,0 +1,56 @@ +Old versus new PCM API (values returned using indirect pointers) +================================================================ + +From the binary compatibility view, there is no change. For compilation, +1.0 ALSA applications do not need any change. The older applications must +use this include sequence: + +#define ALSA_PCM_OLD_HW_PARAMS_API +#define ALSA_PCM_OLD_SW_PARAMS_API +#include + +If you use already the new API, you may remove old defines selecting +this API, because they are no longer used: + +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API + + +Verbose Error Messages +====================== + +Since version 1.0.8, assert() for some non-fatal errors are removed +and error messages are no longer shown to stderr as default. Instead, +the error messages appear only when the environment variable +LIBASOUND_DEBUG is set (to a non-empty value). + +When LIBASOUND_DEBUG=1 is set, the errors in hw_params configuration +will be dumped to stderr. Note that this will show even the non-fatal +errors of plug layer (trial-and-error of parameters). + +This feature is disabled when --with-debug=no is passed to configure, +i.e. no strict checking is done in alsa-lib. + +In addition, when --enable-debug-assert configure option is given and +when LIBASOUND_DEBUG_ASSERT=1 is set, the default error message +handler can call assert() to catch with a debugger. This feature was +formerly activated via LIBASOUND_DEBUG=2. + + +Blocking Open Mode +================== + +The default behavior of blocking at snd_pcm_open is changed to +non-blocking since version 1.0.11. That is, snd_pcm_open() returns +-EAGAIN immediately when the device is in use and cannot be opened, +while the function was blocked in the former version. This influences +only on the opening behavior. The behavior of the further access, +read/write, poll or commit, are not changed. They follow the extra +flag argument of snd_pcm_open() as well as the former version. + +For taking back the compatible behavior of open blocking mode, set + + defaults.pcm.nonblock 0 + +in /etc/asound.conf or ~/.asoundrc file. + diff --git a/TODO b/TODO new file mode 100644 index 0000000..f4a99ff --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +H add serious PCM test application to test various period/buffer size + combinations to determine possible problems in the lowlevel drivers +M think about xrun recovery helpers +L move OSS emulation to user space? (pseudo device driver and daemon) diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..35486a0 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,24 @@ +AC_DEFUN([SAVE_LIBRARY_VERSION], [ +AC_MSG_CHECKING(for library version) +SND_LIB_VERSION=$VERSION +echo $VERSION > $srcdir/version +AC_DEFINE_UNQUOTED(VERSION, "$SND_LIB_VERSION", [sound library version string]) +AC_SUBST(SND_LIB_VERSION) +SND_LIB_MAJOR=`echo $VERSION | cut -d . -f 1` +AC_SUBST(SND_LIB_MAJOR) +SND_LIB_MINOR=`echo $VERSION | cut -d . -f 2` +AC_SUBST(SND_LIB_MINOR) +SND_LIB_SUBMINOR=`echo $VERSION | cut -d . -f 3 | sed -e 's/^\([[^[:alpha:]]]*\)\(.*\)$/\1/g'` +AC_SUBST(SND_LIB_SUBMINOR) +SND_LIB_EXTRASTR=`echo $VERSION | cut -d . -f 3 | sed -e 's/^\([[^[:alpha:]]]*\)\([[[:alpha:]]]*\)\([[[:digit:]]]*\)\(.*\)$/\2/g'` +SND_LIB_EXTRAVER=`echo $VERSION | cut -d . -f 3 | sed -e 's/^\([[^[:alpha:]]]*\)\([[[:alpha:]]]*\)\([[[:digit:]]]*\)\(.*\)$/\3/g'` +case "$SND_LIB_EXTRASTR" in + pre) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 00000` ;; + alpha) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 10000` ;; + beta) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 20000` ;; + rc) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 100000` ;; + *) SND_LIB_EXTRAVER=1000000 ;; +esac +AC_MSG_RESULT(major $SND_LIB_MAJOR minor $SND_LIB_MINOR subminor $SND_LIB_SUBMINOR extrastr $SND_LIB_EXTRASTR extraver $SND_LIB_EXTRAVER) +AC_SUBST(SND_LIB_EXTRAVER) +]) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..45d7c9b --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,8957 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],, +[m4_warning([this file was generated for autoconf 2.67. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# (`yes' being less verbose, `no' or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], +[ --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0')]) +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/alsa-lib.manifest b/alsa-lib.manifest new file mode 100755 index 0000000..a76fdba --- /dev/null +++ b/alsa-lib.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/alsalisp/Makefile.am b/alsalisp/Makefile.am new file mode 100644 index 0000000..6df915a --- /dev/null +++ b/alsalisp/Makefile.am @@ -0,0 +1,8 @@ +noinst_PROGRAMS = alsalisp + +alsalisp_SOURCES = alsalisp.c +alsalisp_LDADD = ../src/libasound.la + +all: alsalisp + +INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/src/alisp diff --git a/alsalisp/Makefile.in b/alsalisp/Makefile.in new file mode 100644 index 0000000..945277c --- /dev/null +++ b/alsalisp/Makefile.in @@ -0,0 +1,501 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = alsalisp$(EXEEXT) +subdir = alsalisp +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_alsalisp_OBJECTS = alsalisp.$(OBJEXT) +alsalisp_OBJECTS = $(am_alsalisp_OBJECTS) +alsalisp_DEPENDENCIES = ../src/libasound.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(alsalisp_SOURCES) +DIST_SOURCES = $(alsalisp_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +alsalisp_SOURCES = alsalisp.c +alsalisp_LDADD = ../src/libasound.la +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/alisp +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign alsalisp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign alsalisp/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +alsalisp$(EXEEXT): $(alsalisp_OBJECTS) $(alsalisp_DEPENDENCIES) + @rm -f alsalisp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(alsalisp_OBJECTS) $(alsalisp_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alsalisp.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +all: alsalisp + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/alsalisp/alsalisp.c b/alsalisp/alsalisp.c new file mode 100644 index 0000000..2a2a77b --- /dev/null +++ b/alsalisp/alsalisp.c @@ -0,0 +1,110 @@ +/* + * ALSA lisp implementation + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#include "asoundlib.h" +#include "alisp.h" + +static int verbose = 0; +static int warning = 0; +static int debug = 0; + +static void interpret_filename(const char *file) +{ + struct alisp_cfg cfg; + snd_input_t *in; + snd_output_t *out; + int err; + + memset(&cfg, 0, sizeof(cfg)); + if (file != NULL && strcmp(file, "-") != 0) { + if ((err = snd_input_stdio_open(&in, file, "r")) < 0) { + fprintf(stderr, "unable to open filename '%s' (%s)\n", file, snd_strerror(err)); + return; + } + } else { + if ((err = snd_input_stdio_attach(&in, stdin, 0)) < 0) { + fprintf(stderr, "unable to attach stdin '%s' (%s)\n", file, snd_strerror(err)); + return; + } + } + if (snd_output_stdio_attach(&out, stdout, 0) < 0) { + snd_input_close(in); + fprintf(stderr, "unable to attach stdout (%s)\n", strerror(errno)); + return; + } + cfg.verbose = verbose; + cfg.warning = warning; + cfg.debug = debug; + cfg.in = in; + cfg.out = cfg.eout = cfg.vout = cfg.wout = cfg.dout = out; + err = alsa_lisp(&cfg, NULL); + if (err < 0) + fprintf(stderr, "alsa lisp returned error %i (%s)\n", err, strerror(err)); + else if (verbose) + printf("file %s passed ok via alsa lisp interpreter\n", file); + snd_output_close(out); + snd_input_close(in); +} + +static void usage(void) +{ + fprintf(stderr, "usage: alsalisp [-vdw] [file...]\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + + while ((c = getopt(argc, argv, "vdw")) != -1) { + switch (c) { + case 'v': + verbose = 1; + break; + case 'd': + debug = 1; + break; + case 'w': + warning = 1; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc < 1) + interpret_filename(NULL); + else + while (*argv) + interpret_filename(*argv++); + + return 0; +} diff --git a/aserver/COPYING b/aserver/COPYING new file mode 100644 index 0000000..b07ad0d --- /dev/null +++ b/aserver/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/aserver/Makefile.am b/aserver/Makefile.am new file mode 100644 index 0000000..116f578 --- /dev/null +++ b/aserver/Makefile.am @@ -0,0 +1,12 @@ +bin_PROGRAMS = aserver +aserver_SOURCES = aserver.c +# aserver_LDADD = -lasound +aserver_LDADD = ../src/libasound.la + +all: aserver + +INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/src/pcm + +../src/libasound.la: + $(MAKE) -C ../src libasound.la + diff --git a/aserver/Makefile.in b/aserver/Makefile.in new file mode 100644 index 0000000..60210ef --- /dev/null +++ b/aserver/Makefile.in @@ -0,0 +1,543 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = aserver$(EXEEXT) +subdir = aserver +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in COPYING +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_aserver_OBJECTS = aserver.$(OBJEXT) +aserver_OBJECTS = $(am_aserver_OBJECTS) +aserver_DEPENDENCIES = ../src/libasound.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(aserver_SOURCES) +DIST_SOURCES = $(aserver_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +aserver_SOURCES = aserver.c +# aserver_LDADD = -lasound +aserver_LDADD = ../src/libasound.la +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/src/pcm +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign aserver/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign aserver/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +aserver$(EXEEXT): $(aserver_OBJECTS) $(aserver_DEPENDENCIES) + @rm -f aserver$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(aserver_OBJECTS) $(aserver_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aserver.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS + + +all: aserver + +../src/libasound.la: + $(MAKE) -C ../src libasound.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/aserver/aserver.c b/aserver/aserver.c new file mode 100644 index 0000000..73ea4e9 --- /dev/null +++ b/aserver/aserver.c @@ -0,0 +1,1104 @@ +/* + * ALSA server + * Copyright (c) by Abramo Bagnara + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aserver.h" + +char *command; + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#define ERROR(...) do {\ + fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, __VA_ARGS__); \ + putc('\n', stderr); \ +} while (0) +#else +#define ERROR(args...) do {\ + fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, ##args); \ + putc('\n', stderr); \ +} while (0) +#endif + +#define SYSERROR(string) ERROR(string ": %s", strerror(errno)) + +static int make_local_socket(const char *filename) +{ + size_t l = strlen(filename); + size_t size = offsetof(struct sockaddr_un, sun_path) + l; + struct sockaddr_un *addr = alloca(size); + int sock; + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) { + int result = -errno; + SYSERROR("socket failed"); + return result; + } + + unlink(filename); + + addr->sun_family = AF_LOCAL; + memcpy(addr->sun_path, filename, l); + + if (bind(sock, (struct sockaddr *) addr, size) < 0) { + int result = -errno; + SYSERROR("bind failed"); + return result; + } + + return sock; +} + +static int make_inet_socket(int port) +{ + struct sockaddr_in addr; + int sock; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + int result = -errno; + SYSERROR("socket failed"); + return result; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + int result = -errno; + SYSERROR("bind failed"); + return result; + } + + return sock; +} + +struct pollfd *pollfds; +unsigned int pollfds_count = 0; +typedef struct waiter waiter_t; +typedef int (*waiter_handler_t)(waiter_t *waiter, unsigned short events); +struct waiter { + int fd; + void *private_data; + waiter_handler_t handler; +}; +waiter_t *waiters; + +static void add_waiter(int fd, unsigned short events, waiter_handler_t handler, + void *data) +{ + waiter_t *w = &waiters[fd]; + struct pollfd *pfd = &pollfds[pollfds_count]; + assert(!w->handler); + pfd->fd = fd; + pfd->events = events; + pfd->revents = 0; + w->fd = fd; + w->private_data = data; + w->handler = handler; + pollfds_count++; +} + +static void del_waiter(int fd) +{ + waiter_t *w = &waiters[fd]; + unsigned int k; + assert(w->handler); + w->handler = 0; + for (k = 0; k < pollfds_count; ++k) { + if (pollfds[k].fd == fd) + break; + } + assert(k < pollfds_count); + pollfds_count--; + memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k); +} + +typedef struct client client_t; + +typedef struct { + int (*open)(client_t *client, int *cookie); + int (*cmd)(client_t *client); + int (*close)(client_t *client); +} transport_ops_t; + +struct client { + struct list_head list; + int poll_fd; + int ctrl_fd; + int local; + int transport_type; + int dev_type; + char name[256]; + int stream; + int mode; + transport_ops_t *ops; + snd_async_handler_t *async_handler; + int async_sig; + pid_t async_pid; + union { + struct { + snd_pcm_t *handle; + int fd; + } pcm; + struct { + snd_ctl_t *handle; + int fd; + } ctl; +#if 0 + struct { + snd_rawmidi_t *handle; + } rawmidi; + struct { + snd_timer_open_t *handle; + } timer; + struct { + snd_hwdep_t *handle; + } hwdep; + struct { + snd_seq_t *handle; + } seq; +#endif + } device; + int polling; + int open; + int cookie; + union { + struct { + int ctrl_id; + void *ctrl; + } shm; + } transport; +}; + +LIST_HEAD(clients); + +typedef struct { + struct list_head list; + int fd; + uint32_t cookie; +} inet_pending_t; +LIST_HEAD(inet_pendings); + +#if 0 +static int pcm_handler(waiter_t *waiter, unsigned short events) +{ + client_t *client = waiter->private_data; + char buf[1]; + ssize_t n; + if (events & POLLIN) { + n = write(client->poll_fd, buf, 1); + if (n != 1) { + SYSERROR("write failed"); + return -errno; + } + } else if (events & POLLOUT) { + n = read(client->poll_fd, buf, 1); + if (n != 1) { + SYSERROR("read failed"); + return -errno; + } + } + del_waiter(waiter->fd); + client->polling = 0; + return 0; +} +#endif + +static void pcm_shm_hw_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED) +{ + client_t *client = pcm->hw.private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; + snd_pcm_t *loop; + + ctrl->hw.changed = 1; + if (pcm->hw.fd >= 0) { + ctrl->hw.use_mmap = 1; + ctrl->hw.offset = pcm->hw.offset; + return; + } + ctrl->hw.use_mmap = 0; + ctrl->hw.ptr = pcm->hw.ptr ? *pcm->hw.ptr : 0; + for (loop = pcm->hw.master; loop; loop = loop->hw.master) + loop->hw.ptr = &ctrl->hw.ptr; + pcm->hw.ptr = &ctrl->hw.ptr; +} + +static void pcm_shm_appl_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED) +{ + client_t *client = pcm->appl.private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; + snd_pcm_t *loop; + + ctrl->appl.changed = 1; + if (pcm->appl.fd >= 0) { + ctrl->appl.use_mmap = 1; + ctrl->appl.offset = pcm->appl.offset; + return; + } + ctrl->appl.use_mmap = 0; + ctrl->appl.ptr = pcm->appl.ptr ? *pcm->appl.ptr : 0; + for (loop = pcm->appl.master; loop; loop = loop->appl.master) + loop->appl.ptr = &ctrl->appl.ptr; + pcm->appl.ptr = &ctrl->appl.ptr; +} + +static int pcm_shm_open(client_t *client, int *cookie) +{ + int shmid; + snd_pcm_t *pcm; + int err; + int result; + err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK); + if (err < 0) + return err; + client->device.pcm.handle = pcm; + client->device.pcm.fd = _snd_pcm_poll_descriptor(pcm); + pcm->hw.private_data = client; + pcm->hw.changed = pcm_shm_hw_ptr_changed; + pcm->appl.private_data = client; + pcm->appl.changed = pcm_shm_appl_ptr_changed; + + shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666); + if (shmid < 0) { + result = -errno; + SYSERROR("shmget failed"); + goto _err; + } + client->transport.shm.ctrl_id = shmid; + client->transport.shm.ctrl = shmat(shmid, 0, 0); + if (client->transport.shm.ctrl == (void*) -1) { + result = -errno; + shmctl(shmid, IPC_RMID, 0); + SYSERROR("shmat failed"); + goto _err; + } + *cookie = shmid; + return 0; + + _err: + snd_pcm_close(pcm); + return result; + +} + +static int pcm_shm_close(client_t *client) +{ + int err; + snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; + if (client->polling) { + del_waiter(client->device.pcm.fd); + client->polling = 0; + } + err = snd_pcm_close(client->device.pcm.handle); + ctrl->result = err; + if (err < 0) + ERROR("snd_pcm_close"); + if (client->transport.shm.ctrl) { + err = shmdt((void *)client->transport.shm.ctrl); + if (err < 0) + SYSERROR("shmdt failed"); + err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); + if (err < 0) + SYSERROR("shmctl IPC_RMID failed"); + client->transport.shm.ctrl = 0; + } + client->open = 0; + return 0; +} + +static int shm_ack(client_t *client) +{ + struct pollfd pfd; + int err; + char buf[1]; + pfd.fd = client->ctrl_fd; + pfd.events = POLLHUP; + if (poll(&pfd, 1, 0) == 1) + return -EBADFD; + err = write(client->ctrl_fd, buf, 1); + if (err != 1) + return -EBADFD; + return 0; +} + +static int shm_ack_fd(client_t *client, int fd) +{ + struct pollfd pfd; + int err; + char buf[1]; + pfd.fd = client->ctrl_fd; + pfd.events = POLLHUP; + if (poll(&pfd, 1, 0) == 1) + return -EBADFD; + err = snd_send_fd(client->ctrl_fd, buf, 1, fd); + if (err != 1) + return -EBADFD; + return 0; +} + +static int shm_rbptr_fd(client_t *client, snd_pcm_rbptr_t *rbptr) +{ + if (rbptr->fd < 0) + return -EINVAL; + return shm_ack_fd(client, rbptr->fd); +} + +static void async_handler(snd_async_handler_t *handler) +{ + client_t *client = snd_async_handler_get_callback_private(handler); + /* FIXME: use sigqueue */ + kill(client->async_pid, client->async_sig); +} + +static int pcm_shm_cmd(client_t *client) +{ + volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; + char buf[1]; + int err; + int cmd; + snd_pcm_t *pcm; + err = read(client->ctrl_fd, buf, 1); + if (err != 1) + return -EBADFD; + cmd = ctrl->cmd; + ctrl->cmd = 0; + pcm = client->device.pcm.handle; + switch (cmd) { + case SND_PCM_IOCTL_ASYNC: + ctrl->result = snd_pcm_async(pcm, ctrl->u.async.sig, ctrl->u.async.pid); + if (ctrl->result < 0) + break; + if (ctrl->u.async.sig >= 0) { + assert(client->async_sig < 0); + ctrl->result = snd_async_add_pcm_handler(&client->async_handler, pcm, async_handler, client); + if (ctrl->result < 0) + break; + } else { + assert(client->async_sig >= 0); + snd_async_del_handler(client->async_handler); + } + client->async_sig = ctrl->u.async.sig; + client->async_pid = ctrl->u.async.pid; + break; + case SNDRV_PCM_IOCTL_INFO: + ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info); + break; + case SNDRV_PCM_IOCTL_HW_REFINE: + ctrl->result = snd_pcm_hw_refine(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_refine); + break; + case SNDRV_PCM_IOCTL_HW_PARAMS: + ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params); + break; + case SNDRV_PCM_IOCTL_HW_FREE: + ctrl->result = snd_pcm_hw_free(pcm); + break; + case SNDRV_PCM_IOCTL_SW_PARAMS: + ctrl->result = snd_pcm_sw_params(pcm, (snd_pcm_sw_params_t *) &ctrl->u.sw_params); + break; + case SNDRV_PCM_IOCTL_STATUS: + ctrl->result = snd_pcm_status(pcm, (snd_pcm_status_t *) &ctrl->u.status); + break; + case SND_PCM_IOCTL_STATE: + ctrl->result = snd_pcm_state(pcm); + break; + case SND_PCM_IOCTL_HWSYNC: + ctrl->result = snd_pcm_hwsync(pcm); + break; + case SNDRV_PCM_IOCTL_DELAY: + ctrl->result = snd_pcm_delay(pcm, (snd_pcm_sframes_t *) &ctrl->u.delay.frames); + break; + case SND_PCM_IOCTL_AVAIL_UPDATE: + ctrl->result = snd_pcm_avail_update(pcm); + break; + case SNDRV_PCM_IOCTL_PREPARE: + ctrl->result = snd_pcm_prepare(pcm); + break; + case SNDRV_PCM_IOCTL_RESET: + ctrl->result = snd_pcm_reset(pcm); + break; + case SNDRV_PCM_IOCTL_START: + ctrl->result = snd_pcm_start(pcm); + break; + case SNDRV_PCM_IOCTL_DRAIN: + ctrl->result = snd_pcm_drain(pcm); + break; + case SNDRV_PCM_IOCTL_DROP: + ctrl->result = snd_pcm_drop(pcm); + break; + case SNDRV_PCM_IOCTL_PAUSE: + ctrl->result = snd_pcm_pause(pcm, ctrl->u.pause.enable); + break; + case SNDRV_PCM_IOCTL_CHANNEL_INFO: + ctrl->result = snd_pcm_channel_info(pcm, (snd_pcm_channel_info_t *) &ctrl->u.channel_info); + if (ctrl->result >= 0 && + ctrl->u.channel_info.type == SND_PCM_AREA_MMAP) + return shm_ack_fd(client, ctrl->u.channel_info.u.mmap.fd); + break; + case SNDRV_PCM_IOCTL_REWIND: + ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames); + break; + case SND_PCM_IOCTL_FORWARD: + ctrl->result = snd_pcm_forward(pcm, ctrl->u.forward.frames); + break; + case SNDRV_PCM_IOCTL_LINK: + { + /* FIXME */ + ctrl->result = -ENOSYS; + break; + } + case SNDRV_PCM_IOCTL_UNLINK: + ctrl->result = snd_pcm_unlink(pcm); + break; + case SNDRV_PCM_IOCTL_RESUME: + ctrl->result = snd_pcm_resume(pcm); + break; + case SND_PCM_IOCTL_MMAP: + { + ctrl->result = snd_pcm_mmap(pcm); + } + case SND_PCM_IOCTL_MUNMAP: + { + ctrl->result = snd_pcm_munmap(pcm); + break; + } + case SND_PCM_IOCTL_MMAP_COMMIT: + ctrl->result = snd_pcm_mmap_commit(pcm, + ctrl->u.mmap_commit.offset, + ctrl->u.mmap_commit.frames); + break; + case SND_PCM_IOCTL_POLL_DESCRIPTOR: + ctrl->result = 0; + return shm_ack_fd(client, _snd_pcm_poll_descriptor(pcm)); + case SND_PCM_IOCTL_CLOSE: + client->ops->close(client); + break; + case SND_PCM_IOCTL_HW_PTR_FD: + return shm_rbptr_fd(client, &pcm->hw); + case SND_PCM_IOCTL_APPL_PTR_FD: + return shm_rbptr_fd(client, &pcm->appl); + default: + ERROR("Bogus cmd: %x", ctrl->cmd); + ctrl->result = -ENOSYS; + } + return shm_ack(client); +} + +transport_ops_t pcm_shm_ops = { + .open = pcm_shm_open, + .cmd = pcm_shm_cmd, + .close = pcm_shm_close, +}; + +static int ctl_handler(waiter_t *waiter, unsigned short events) +{ + client_t *client = waiter->private_data; + char buf[1]; + ssize_t n; + if (events & POLLIN) { + n = write(client->poll_fd, buf, 1); + if (n != 1) { + SYSERROR("write failed"); + return -errno; + } + } + del_waiter(waiter->fd); + client->polling = 0; + return 0; +} + +static int ctl_shm_open(client_t *client, int *cookie) +{ + int shmid; + snd_ctl_t *ctl; + int err; + int result; + err = snd_ctl_open(&ctl, client->name, SND_CTL_NONBLOCK); + if (err < 0) + return err; + client->device.ctl.handle = ctl; + client->device.ctl.fd = _snd_ctl_poll_descriptor(ctl); + + shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666); + if (shmid < 0) { + result = -errno; + SYSERROR("shmget failed"); + goto _err; + } + client->transport.shm.ctrl_id = shmid; + client->transport.shm.ctrl = shmat(shmid, 0, 0); + if (!client->transport.shm.ctrl) { + result = -errno; + shmctl(shmid, IPC_RMID, 0); + SYSERROR("shmat failed"); + goto _err; + } + *cookie = shmid; + add_waiter(client->device.ctl.fd, POLLIN, ctl_handler, client); + client->polling = 1; + return 0; + + _err: + snd_ctl_close(ctl); + return result; + +} + +static int ctl_shm_close(client_t *client) +{ + int err; + snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; + if (client->polling) { + del_waiter(client->device.ctl.fd); + client->polling = 0; + } + err = snd_ctl_close(client->device.ctl.handle); + ctrl->result = err; + if (err < 0) + ERROR("snd_ctl_close"); + if (client->transport.shm.ctrl) { + err = shmdt((void *)client->transport.shm.ctrl); + if (err < 0) + SYSERROR("shmdt failed"); + err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); + if (err < 0) + SYSERROR("shmctl failed"); + client->transport.shm.ctrl = 0; + } + client->open = 0; + return 0; +} + +static int ctl_shm_cmd(client_t *client) +{ + snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; + char buf[1]; + int err; + int cmd; + snd_ctl_t *ctl; + err = read(client->ctrl_fd, buf, 1); + if (err != 1) + return -EBADFD; + cmd = ctrl->cmd; + ctrl->cmd = 0; + ctl = client->device.ctl.handle; + switch (cmd) { + case SND_CTL_IOCTL_ASYNC: + ctrl->result = snd_ctl_async(ctl, ctrl->u.async.sig, ctrl->u.async.pid); + if (ctrl->result < 0) + break; + if (ctrl->u.async.sig >= 0) { + assert(client->async_sig < 0); + ctrl->result = snd_async_add_ctl_handler(&client->async_handler, ctl, async_handler, client); + if (ctrl->result < 0) + break; + } else { + assert(client->async_sig >= 0); + snd_async_del_handler(client->async_handler); + } + client->async_sig = ctrl->u.async.sig; + client->async_pid = ctrl->u.async.pid; + break; + break; + case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: + ctrl->result = snd_ctl_subscribe_events(ctl, ctrl->u.subscribe_events); + break; + case SNDRV_CTL_IOCTL_CARD_INFO: + ctrl->result = snd_ctl_card_info(ctl, &ctrl->u.card_info); + break; + case SNDRV_CTL_IOCTL_ELEM_LIST: + { + size_t maxsize = CTL_SHM_DATA_MAXLEN; + if (ctrl->u.element_list.space * sizeof(*ctrl->u.element_list.pids) > maxsize) { + ctrl->result = -EFAULT; + break; + } + ctrl->u.element_list.pids = (snd_ctl_elem_id_t*) ctrl->data; + ctrl->result = snd_ctl_elem_list(ctl, &ctrl->u.element_list); + break; + } + case SNDRV_CTL_IOCTL_ELEM_INFO: + ctrl->result = snd_ctl_elem_info(ctl, &ctrl->u.element_info); + break; + case SNDRV_CTL_IOCTL_ELEM_READ: + ctrl->result = snd_ctl_elem_read(ctl, &ctrl->u.element_read); + break; + case SNDRV_CTL_IOCTL_ELEM_WRITE: + ctrl->result = snd_ctl_elem_write(ctl, &ctrl->u.element_write); + break; + case SNDRV_CTL_IOCTL_ELEM_LOCK: + ctrl->result = snd_ctl_elem_lock(ctl, &ctrl->u.element_lock); + break; + case SNDRV_CTL_IOCTL_ELEM_UNLOCK: + ctrl->result = snd_ctl_elem_unlock(ctl, &ctrl->u.element_unlock); + break; + case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE: + ctrl->result = snd_ctl_hwdep_next_device(ctl, &ctrl->u.device); + break; + case SNDRV_CTL_IOCTL_HWDEP_INFO: + ctrl->result = snd_ctl_hwdep_info(ctl, &ctrl->u.hwdep_info); + break; + case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE: + ctrl->result = snd_ctl_pcm_next_device(ctl, &ctrl->u.device); + break; + case SNDRV_CTL_IOCTL_PCM_INFO: + ctrl->result = snd_ctl_pcm_info(ctl, &ctrl->u.pcm_info); + break; + case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE: + ctrl->result = snd_ctl_pcm_prefer_subdevice(ctl, ctrl->u.pcm_prefer_subdevice); + break; + case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: + ctrl->result = snd_ctl_rawmidi_next_device(ctl, &ctrl->u.device); + break; + case SNDRV_CTL_IOCTL_RAWMIDI_INFO: + ctrl->result = snd_ctl_rawmidi_info(ctl, &ctrl->u.rawmidi_info); + break; + case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: + ctrl->result = snd_ctl_rawmidi_prefer_subdevice(ctl, ctrl->u.rawmidi_prefer_subdevice); + break; + case SNDRV_CTL_IOCTL_POWER: + ctrl->result = snd_ctl_set_power_state(ctl, ctrl->u.power_state); + break; + case SNDRV_CTL_IOCTL_POWER_STATE: + ctrl->result = snd_ctl_get_power_state(ctl, &ctrl->u.power_state); + break; + case SND_CTL_IOCTL_READ: + ctrl->result = snd_ctl_read(ctl, &ctrl->u.read); + break; + case SND_CTL_IOCTL_CLOSE: + client->ops->close(client); + break; + case SND_CTL_IOCTL_POLL_DESCRIPTOR: + ctrl->result = 0; + return shm_ack_fd(client, _snd_ctl_poll_descriptor(ctl)); + default: + ERROR("Bogus cmd: %x", ctrl->cmd); + ctrl->result = -ENOSYS; + } + return shm_ack(client); +} + +transport_ops_t ctl_shm_ops = { + .open = ctl_shm_open, + .cmd = ctl_shm_cmd, + .close = ctl_shm_close, +}; + +static int snd_client_open(client_t *client) +{ + int err; + snd_client_open_request_t req; + snd_client_open_answer_t ans; + char *name; + memset(&ans, 0, sizeof(ans)); + err = read(client->ctrl_fd, &req, sizeof(req)); + if (err < 0) { + SYSERROR("read failed"); + exit(1); + } + if (err != sizeof(req)) { + ans.result = -EINVAL; + goto _answer; + } + name = alloca(req.namelen); + err = read(client->ctrl_fd, name, req.namelen); + if (err < 0) { + SYSERROR("read failed"); + exit(1); + } + if (err != req.namelen) { + ans.result = -EINVAL; + goto _answer; + } + + switch (req.transport_type) { + case SND_TRANSPORT_TYPE_SHM: + if (!client->local) { + ans.result = -EINVAL; + goto _answer; + } + switch (req.dev_type) { + case SND_DEV_TYPE_PCM: + client->ops = &pcm_shm_ops; + break; + case SND_DEV_TYPE_CONTROL: + client->ops = &ctl_shm_ops; + break; + default: + ans.result = -EINVAL; + goto _answer; + } + break; + default: + ans.result = -EINVAL; + goto _answer; + } + + name[req.namelen] = '\0'; + + client->transport_type = req.transport_type; + strcpy(client->name, name); + client->stream = req.stream; + client->mode = req.mode; + + err = client->ops->open(client, &ans.cookie); + if (err < 0) { + ans.result = err; + } else { + client->open = 1; + ans.result = 0; + } + + _answer: + err = write(client->ctrl_fd, &ans, sizeof(ans)); + if (err != sizeof(ans)) { + SYSERROR("write failed"); + exit(1); + } + return 0; +} + +static int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) +{ + client_t *client = waiter->private_data; + if (client->open) + client->ops->close(client); + close(client->poll_fd); + close(client->ctrl_fd); + del_waiter(client->poll_fd); + del_waiter(client->ctrl_fd); + list_del(&client->list); + free(client); + return 0; +} + +static int client_ctrl_handler(waiter_t *waiter, unsigned short events) +{ + client_t *client = waiter->private_data; + if (events & POLLHUP) { + if (client->open) + client->ops->close(client); + close(client->ctrl_fd); + del_waiter(client->ctrl_fd); + list_del(&client->list); + free(client); + return 0; + } + if (client->open) + return client->ops->cmd(client); + else + return snd_client_open(client); +} + +static int inet_pending_handler(waiter_t *waiter, unsigned short events) +{ + inet_pending_t *pending = waiter->private_data; + inet_pending_t *pdata; + client_t *client; + uint32_t cookie; + struct list_head *item; + int remove = 0; + if (events & POLLHUP) + remove = 1; + else { + int err = read(waiter->fd, &cookie, sizeof(cookie)); + if (err != sizeof(cookie)) + remove = 1; + else { + err = write(waiter->fd, &cookie, sizeof(cookie)); + if (err != sizeof(cookie)) + remove = 1; + } + } + del_waiter(waiter->fd); + if (remove) { + close(waiter->fd); + list_del(&pending->list); + free(pending); + return 0; + } + + list_for_each(item, &inet_pendings) { + pdata = list_entry(item, inet_pending_t, list); + if (pdata->cookie == cookie) + goto found; + } + pending->cookie = cookie; + return 0; + + found: + client = calloc(1, sizeof(*client)); + client->local = 0; + client->poll_fd = pdata->fd; + client->ctrl_fd = waiter->fd; + add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client); + add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client); + client->open = 0; + list_add_tail(&client->list, &clients); + list_del(&pending->list); + list_del(&pdata->list); + free(pending); + free(pdata); + return 0; +} + +static int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) +{ + int sock; + sock = accept(waiter->fd, 0, 0); + if (sock < 0) { + int result = -errno; + SYSERROR("accept failed"); + return result; + } else { + client_t *client = calloc(1, sizeof(*client)); + client->ctrl_fd = sock; + client->local = 1; + client->open = 0; + add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client); + list_add_tail(&client->list, &clients); + } + return 0; +} + +static int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) +{ + int sock; + sock = accept(waiter->fd, 0, 0); + if (sock < 0) { + int result = -errno; + SYSERROR("accept failed"); + return result; + } else { + inet_pending_t *pending = calloc(1, sizeof(*pending)); + pending->fd = sock; + pending->cookie = 0; + add_waiter(sock, POLLIN, inet_pending_handler, pending); + list_add_tail(&pending->list, &inet_pendings); + } + return 0; +} + +static int server(const char *sockname, int port) +{ + int err; + unsigned int k; + long open_max; + int result; + + if (!sockname && port < 0) + return -EINVAL; + open_max = sysconf(_SC_OPEN_MAX); + if (open_max < 0) { + result = -errno; + SYSERROR("sysconf failed"); + return result; + } + pollfds = calloc((size_t) open_max, sizeof(*pollfds)); + waiters = calloc((size_t) open_max, sizeof(*waiters)); + + if (sockname) { + int sock = make_local_socket(sockname); + if (sock < 0) + return sock; + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { + result = -errno; + SYSERROR("fcntl O_NONBLOCK failed"); + goto _end; + } + if (listen(sock, 4) < 0) { + result = -errno; + SYSERROR("listen failed"); + goto _end; + } + add_waiter(sock, POLLIN, local_handler, NULL); + } + if (port >= 0) { + int sock = make_inet_socket(port); + if (sock < 0) + return sock; + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { + result = -errno; + SYSERROR("fcntl failed"); + goto _end; + } + if (listen(sock, 4) < 0) { + result = -errno; + SYSERROR("listen failed"); + goto _end; + } + add_waiter(sock, POLLIN, inet_handler, NULL); + } + + while (1) { + struct pollfd pfds[open_max]; + size_t pfds_count; + do { + err = poll(pollfds, pollfds_count, -1); + } while (err == 0); + if (err < 0) { + SYSERROR("poll failed"); + continue; + } + + pfds_count = pollfds_count; + memcpy(pfds, pollfds, sizeof(*pfds) * pfds_count); + for (k = 0; k < pfds_count; k++) { + struct pollfd *pfd = &pfds[k]; + if (pfd->revents) { + waiter_t *w = &waiters[pfd->fd]; + if (!w->handler) + continue; + err = w->handler(w, pfd->revents); + if (err < 0) + ERROR("waiter handler failed"); + } + } + } + _end: + free(pollfds); + free(waiters); + return result; +} + + +static void usage(void) +{ + fprintf(stderr, + "Usage: %s [OPTIONS] server\n" + "--help help\n", + command); +} + +int main(int argc, char **argv) +{ + static const struct option long_options[] = { + {"help", 0, 0, 'h'}, + { 0 , 0 , 0, 0 } + }; + int c; + snd_config_t *conf; + snd_config_iterator_t i, next; + const char *sockname = NULL; + const char *host = NULL; + long port = -1; + int err; + char *srvname; + struct hostent *h; + command = argv[0]; + while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) { + switch (c) { + case 'h': + usage(); + return 0; + default: + fprintf(stderr, "Try `%s --help' for more information\n", command); + return 1; + } + } + if (argc - optind != 1) { + ERROR("you need to specify server name"); + return 1; + } + err = snd_config_update(); + if (err < 0) { + ERROR("cannot read configuration file"); + return 1; + } + srvname = argv[optind]; + err = snd_config_search_definition(snd_config, "server", srvname, &conf); + if (err < 0) { + ERROR("Missing definition for server %s", srvname); + return 1; + } + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for server %s definition", srvname); + return -EINVAL; + } + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "host") == 0) { + err = snd_config_get_string(n, &host); + if (err < 0) { + ERROR("Invalid type for %s", id); + return 1; + } + continue; + } + if (strcmp(id, "socket") == 0) { + err = snd_config_get_string(n, &sockname); + if (err < 0) { + ERROR("Invalid type for %s", id); + return 1; + } + continue; + } + if (strcmp(id, "port") == 0) { + err = snd_config_get_integer(n, &port); + if (err < 0) { + ERROR("Invalid type for %s", id); + return 1; + } + continue; + } + ERROR("Unknown field %s", id); + return 1; + } + if (!host) { + ERROR("host is not defined"); + return 1; + } + h = gethostbyname(host); + if (!h) { + ERROR("Cannot resolve %s", host); + return 1; + } + if (!snd_is_local(h)) { + ERROR("%s is not the local host", host); + return 1; + } + if (!sockname && port < 0) { + ERROR("either socket or port need to be defined"); + return 1; + } + server(sockname, port); + return 0; +} diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..c9ec63e --- /dev/null +++ b/autogen.sh @@ -0,0 +1,7 @@ +#!/bin/sh +libtoolize --force --copy --automake +aclocal +autoheader +automake --foreign --copy --add-missing +autoconf + diff --git a/compile b/compile new file mode 100755 index 0000000..1b1d232 --- /dev/null +++ b/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..40eaed4 --- /dev/null +++ b/config.guess @@ -0,0 +1,1517 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011 Free Software Foundation, Inc. + +timestamp='2011-05-11' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free +Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-tilera-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..30fdca8 --- /dev/null +++ b/config.sub @@ -0,0 +1,1760 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011 Free Software Foundation, Inc. + +timestamp='2011-03-23' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free +Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile-* | tilegx-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + # This must be matched before tile*. + tilegx*) + basic_machine=tilegx-unknown + os=-linux-gnu + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..7490f18 --- /dev/null +++ b/configure @@ -0,0 +1,14772 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.67. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +$* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="src/control/control.c" +ac_default_prefix=/usr +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +BUILD_CTL_PLUGIN_EXT_FALSE +BUILD_CTL_PLUGIN_EXT_TRUE +BUILD_CTL_PLUGIN_SHM_FALSE +BUILD_CTL_PLUGIN_SHM_TRUE +BUILD_CTL_PLUGIN_FALSE +BUILD_CTL_PLUGIN_TRUE +BUILD_PCM_PLUGIN_MMAP_EMUL_FALSE +BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE +BUILD_PCM_PLUGIN_IOPLUG_FALSE +BUILD_PCM_PLUGIN_IOPLUG_TRUE +BUILD_PCM_PLUGIN_EXTPLUG_FALSE +BUILD_PCM_PLUGIN_EXTPLUG_TRUE +BUILD_PCM_PLUGIN_SOFTVOL_FALSE +BUILD_PCM_PLUGIN_SOFTVOL_TRUE +BUILD_PCM_PLUGIN_IEC958_FALSE +BUILD_PCM_PLUGIN_IEC958_TRUE +BUILD_PCM_PLUGIN_ASYM_FALSE +BUILD_PCM_PLUGIN_ASYM_TRUE +BUILD_PCM_PLUGIN_DSNOOP_FALSE +BUILD_PCM_PLUGIN_DSNOOP_TRUE +BUILD_PCM_PLUGIN_DSHARE_FALSE +BUILD_PCM_PLUGIN_DSHARE_TRUE +BUILD_PCM_PLUGIN_DMIX_FALSE +BUILD_PCM_PLUGIN_DMIX_TRUE +BUILD_PCM_PLUGIN_LADSPA_FALSE +BUILD_PCM_PLUGIN_LADSPA_TRUE +BUILD_PCM_PLUGIN_LFLOAT_FALSE +BUILD_PCM_PLUGIN_LFLOAT_TRUE +BUILD_PCM_PLUGIN_HOOKS_FALSE +BUILD_PCM_PLUGIN_HOOKS_TRUE +BUILD_PCM_PLUGIN_METER_FALSE +BUILD_PCM_PLUGIN_METER_TRUE +BUILD_PCM_PLUGIN_SHARE_FALSE +BUILD_PCM_PLUGIN_SHARE_TRUE +BUILD_PCM_PLUGIN_EMPTY_FALSE +BUILD_PCM_PLUGIN_EMPTY_TRUE +BUILD_PCM_PLUGIN_NULL_FALSE +BUILD_PCM_PLUGIN_NULL_TRUE +BUILD_PCM_PLUGIN_FILE_FALSE +BUILD_PCM_PLUGIN_FILE_TRUE +BUILD_PCM_PLUGIN_SHM_FALSE +BUILD_PCM_PLUGIN_SHM_TRUE +BUILD_PCM_PLUGIN_MULTI_FALSE +BUILD_PCM_PLUGIN_MULTI_TRUE +BUILD_PCM_PLUGIN_PLUG_FALSE +BUILD_PCM_PLUGIN_PLUG_TRUE +BUILD_PCM_PLUGIN_RATE_FALSE +BUILD_PCM_PLUGIN_RATE_TRUE +BUILD_PCM_PLUGIN_ADPCM_FALSE +BUILD_PCM_PLUGIN_ADPCM_TRUE +BUILD_PCM_PLUGIN_ALAW_FALSE +BUILD_PCM_PLUGIN_ALAW_TRUE +BUILD_PCM_PLUGIN_MULAW_FALSE +BUILD_PCM_PLUGIN_MULAW_TRUE +BUILD_PCM_PLUGIN_ROUTE_FALSE +BUILD_PCM_PLUGIN_ROUTE_TRUE +BUILD_PCM_PLUGIN_LINEAR_FALSE +BUILD_PCM_PLUGIN_LINEAR_TRUE +BUILD_PCM_PLUGIN_COPY_FALSE +BUILD_PCM_PLUGIN_COPY_TRUE +BUILD_PCM_PLUGIN_FALSE +BUILD_PCM_PLUGIN_TRUE +BUILD_PYTHON_FALSE +BUILD_PYTHON_TRUE +BUILD_ALISP_FALSE +BUILD_ALISP_TRUE +BUILD_UCM_FALSE +BUILD_UCM_TRUE +BUILD_SEQ_FALSE +BUILD_SEQ_TRUE +BUILD_HWDEP_FALSE +BUILD_HWDEP_TRUE +BUILD_RAWMIDI_FALSE +BUILD_RAWMIDI_TRUE +BUILD_PCM_FALSE +BUILD_PCM_TRUE +BUILD_MIXER_FALSE +BUILD_MIXER_TRUE +PYTHON_INCLUDES +PYTHON_LIBS +KEEP_OLD_SYMBOLS_FALSE +KEEP_OLD_SYMBOLS_TRUE +ALSA_DEPLIBS +BUILD_MODULES_FALSE +BUILD_MODULES_TRUE +SYMBOL_PREFIX +SYMBOLIC_FUNCTIONS_FALSE +SYMBOLIC_FUNCTIONS_TRUE +VERSIONED_SYMBOLS_FALSE +VERSIONED_SYMBOLS_TRUE +ALSA_PLUGIN_DIR +ALSA_CONFIG_DIR +LIBTOOL_VERSION_INFO +SND_LIB_EXTRAVER +SND_LIB_SUBMINOR +SND_LIB_MINOR +SND_LIB_MAJOR +SND_LIB_VERSION +ALSA_HSEARCH_R_FALSE +ALSA_HSEARCH_R_TRUE +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +AR +OBJDUMP +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +LIBTOOL +LN_S +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +INSTALL_M4_FALSE +INSTALL_M4_TRUE +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_dependency_tracking +enable_static +enable_shared +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +with_configdir +with_plugindir +with_versioned +enable_symbolic_functions +with_debug +enable_debug_assert +with_tmpdir +with_softfloat +with_libdl +with_pthread +with_librt +enable_resmgr +enable_aload +with_alsa_devdir +with_aload_devdir +enable_mixer +enable_pcm +enable_rawmidi +enable_hwdep +enable_seq +enable_ucm +enable_alisp +enable_old_symbols +enable_python +with_pythonlibs +with_pythonincludes +with_pcm_plugins +with_ctl_plugins +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0') + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-static[=PKGS] build static libraries [default=no] + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-symbolic-functions + use -Bsymbolic-functions option if available + (optmization for size and speed) + --enable-debug enable assert call at the default error message + handler + --enable-resmgr support resmgr (optional) + --disable-aload disable reading /dev/aload* + --disable-mixer disable the mixer component + --disable-pcm disable the PCM component + --disable-rawmidi disable the raw MIDI component + --disable-hwdep disable the hwdep component + --disable-seq disable the sequencer component + --disable-ucm disable the use-case-manager component + --disable-alisp disable the alisp component + --disable-old-symbols disable old obsoleted symbols + --disable-python disable the python components + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-configdir=dir path where ALSA config files are stored + --with-plugindir=dir path where ALSA plugin files are stored + --with-versioned shared library will be compiled with versioned + symbols (default = yes) + --with-debug library will be compiled with asserts (default = + yes) + --with-tmpdir=directory directory to put tmp socket files (/tmp) + --with-softfloat do you have floating point unit on this machine? + (optional) + --with-libdl Use libdl for plugins (default = yes) + --with-pthread Use pthread (default = yes) + --with-librt Use librt for monotonic clock (default = yes) + --with-alsa-devdir=dir directory with ALSA device files (default /dev/snd) + --with-aload-devdir=dir directory with aload* device files (default /dev) + --with-pythonlibs=ldflags + specify python libraries (-lpthread -lm -ldl + -lpython2.4) + --with-pythonincludes=Cflags + specify python C header files + (-I/usr/include/python) + --with-pcm-plugins= + build PCM plugins (default = all) + --with-ctl-plugins= + build control plugins (default = all) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.67 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.67. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5 ;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5 ;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=alsa-lib + VERSION=1.0.24.1 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +eval LIBTOOL_VERSION_INFO="2:0:0" + if test -n "${ACLOCAL}"; then + INSTALL_M4_TRUE= + INSTALL_M4_FALSE='#' +else + INSTALL_M4_TRUE='#' + INSTALL_M4_FALSE= +fi + + +# Test for new silent rules and enable only if they are available +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=0;; +esac +AM_BACKSLASH='\' + + + + + +if test "x$host" != "x$build" -a -z "`echo $CC | grep -e '-gcc'`"; +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cross-compiler" >&5 +$as_echo_n "checking for cross-compiler... " >&6; } + + which ${program_prefix}gcc >/dev/null 2>&1 && CC=${program_prefix}gcc + which ${host_cpu}-${host_os}-gcc >/dev/null 2>&1 \ + && CC=${host_cpu}-${host-os}-gcc + which ${host_cpu}-${host_vendor}-${host_os}-gcc >/dev/null 2>&1 \ + && CC=${host_cpu}-${host_vendor}-${host_os}-gcc + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +fi + +CFLAGS="$CFLAGS -D_GNU_SOURCE" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5 ; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=no +fi + + + + + + + + + +enable_dlopen=yes + + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.6b' +macro_revision='1.3017' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$ac_tool_prefix"; then + for ac_prog in "dumpbin -symbols" "link -dump -symbols" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in "dumpbin -symbols" "link -dump -symbols" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:4868: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:4871: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:4874: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 6069 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + +# Set options + + + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + + + + + + + + + + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7425: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7429: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7764: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7768: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7869: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:7873: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7924: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:7928: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 +$as_echo "$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10308 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10404 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +CC_NOUNDEFINED + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +ac_config_headers="$ac_config_headers include/config.h" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if test "${ac_cv_header_time+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_time=yes +else + ac_cv_header_time=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h + +fi + + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if test "${ac_cv_prog_gcc_traditional+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then : + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +ac_fn_c_check_func "$LINENO" "hsearch_r" "ac_cv_func_hsearch_r" +if test "x$ac_cv_func_hsearch_r" = x""yes; then : + HAVE_HSEARCH_R=yes +fi + + if test "x$HAVE_HSEARCH_R" != xyes; then + ALSA_HSEARCH_R_TRUE= + ALSA_HSEARCH_R_FALSE='#' +else + ALSA_HSEARCH_R_TRUE='#' + ALSA_HSEARCH_R_FALSE= +fi + +for ac_func in uselocale +do : + ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale" +if test "x$ac_cv_func_uselocale" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_USELOCALE 1 +_ACEOF + +fi +done + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library version" >&5 +$as_echo_n "checking for library version... " >&6; } +SND_LIB_VERSION=$VERSION +echo $VERSION > $srcdir/version + +cat >>confdefs.h <<_ACEOF +#define VERSION "$SND_LIB_VERSION" +_ACEOF + + +SND_LIB_MAJOR=`echo $VERSION | cut -d . -f 1` + +SND_LIB_MINOR=`echo $VERSION | cut -d . -f 2` + +SND_LIB_SUBMINOR=`echo $VERSION | cut -d . -f 3 | sed -e 's/^\([^[:alpha:]]*\)\(.*\)$/\1/g'` + +SND_LIB_EXTRASTR=`echo $VERSION | cut -d . -f 3 | sed -e 's/^\([^[:alpha:]]*\)\([[:alpha:]]*\)\([[:digit:]]*\)\(.*\)$/\2/g'` +SND_LIB_EXTRAVER=`echo $VERSION | cut -d . -f 3 | sed -e 's/^\([^[:alpha:]]*\)\([[:alpha:]]*\)\([[:digit:]]*\)\(.*\)$/\3/g'` +case "$SND_LIB_EXTRASTR" in + pre) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 00000` ;; + alpha) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 10000` ;; + beta) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 20000` ;; + rc) SND_LIB_EXTRAVER=`expr $SND_LIB_EXTRAVER + 100000` ;; + *) SND_LIB_EXTRAVER=1000000 ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: major $SND_LIB_MAJOR minor $SND_LIB_MINOR subminor $SND_LIB_SUBMINOR extrastr $SND_LIB_EXTRASTR extraver $SND_LIB_EXTRAVER" >&5 +$as_echo "major $SND_LIB_MAJOR minor $SND_LIB_MINOR subminor $SND_LIB_SUBMINOR extrastr $SND_LIB_EXTRASTR extraver $SND_LIB_EXTRAVER" >&6; } + + + + +test "x$prefix" = xNONE && prefix=$ac_default_prefix + + +# Check whether --with-configdir was given. +if test "${with_configdir+set}" = set; then : + withval=$with_configdir; confdir="$withval" +else + confdir="" +fi + +if test -z "$confdir"; then + eval dir="$datadir" + case "$dir" in + /*) ;; + *) dir="$prefix/share" + esac + confdir="$dir/alsa" +fi +ALSA_CONFIG_DIR="$confdir" + +cat >>confdefs.h <<_ACEOF +#define ALSA_CONFIG_DIR "$confdir" +_ACEOF + + + +test "x$exec_prefix" = xNONE && exec_prefix=$prefix + + +# Check whether --with-plugindir was given. +if test "${with_plugindir+set}" = set; then : + withval=$with_plugindir; plugindir="$withval" +else + plugindir="" +fi + +if test -z "$plugindir"; then + eval dir="$libdir" + case "$dir" in + /*) ;; + *) dir="$dir" + esac + plugindir="$dir/$PACKAGE" +fi + +cat >>confdefs.h <<_ACEOF +#define ALSA_PLUGIN_DIR "$plugindir" +_ACEOF + +ALSA_PLUGIN_DIR="$plugindir" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for versioned symbols" >&5 +$as_echo_n "checking for versioned symbols... " >&6; } + +# Check whether --with-versioned was given. +if test "${with_versioned+set}" = set; then : + withval=$with_versioned; versioned="$withval" +else + versioned="yes" +fi + +if test "$versioned" = "yes"; then + # it seems that GNU ld versions since 2.10 are not broken + xres=`grep '^VERSION=' ${srcdir}/ltmain.sh | cut -d = -f 2 | cut -d \" -f 2` + major=`echo $xres | cut -d . -f 1` + minor=`echo $xres | cut -d . -f 2` + pass=0 + if test $major -eq 1 && test $minor -gt 3; then + pass=1 + else + if test $major -gt 1; then + pass=1 + fi + fi + if test $pass -eq 1; then + +$as_echo "#define VERSIONED_SYMBOLS /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: broken libtool - use libtool v1.4+; no versions" >&5 +$as_echo "broken libtool - use libtool v1.4+; no versions" >&6; } + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + if test x$versioned = xyes; then + VERSIONED_SYMBOLS_TRUE= + VERSIONED_SYMBOLS_FALSE='#' +else + VERSIONED_SYMBOLS_TRUE='#' + VERSIONED_SYMBOLS_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for symbolic-functions" >&5 +$as_echo_n "checking for symbolic-functions... " >&6; } +# Check whether --enable-symbolic-functions was given. +if test "${enable_symbolic_functions+set}" = set; then : + enableval=$enable_symbolic_functions; symfuncs="$enableval" +else + symfuncs="no" +fi + +if test "$symfuncs" = "yes"; then + if ld --help | grep -q -- '-Bsymbolic-functions'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not supported by ld" >&5 +$as_echo "not supported by ld" >&6; } + symfuncs="no" + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + if test x"$symfuncs" = xyes; then + SYMBOLIC_FUNCTIONS_TRUE= + SYMBOLIC_FUNCTIONS_FALSE='#' +else + SYMBOLIC_FUNCTIONS_TRUE='#' + SYMBOLIC_FUNCTIONS_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for custom symbol prefixes" >&5 +$as_echo_n "checking for custom symbol prefixes... " >&6; } +SYMBOL_PREFIX=` \ + echo "PREFIX=__USER_LABEL_PREFIX__" \ + | ${CPP-${CC-gcc} -E} - 2>&1 \ + | ${EGREP-grep} "^PREFIX=" \ + | ${SED-sed} "s:^PREFIX=::"` + +cat >>confdefs.h <<_ACEOF +#define __SYMBOL_PREFIX "$SYMBOL_PREFIX" +_ACEOF + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYMBOL_PREFIX" >&5 +$as_echo "$SYMBOL_PREFIX" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for debug" >&5 +$as_echo_n "checking for debug... " >&6; } + +# Check whether --with-debug was given. +if test "${with_debug+set}" = set; then : + withval=$with_debug; debug="$withval" +else + debug="yes" +fi + +if test "$debug" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + +$as_echo "#define NDEBUG /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +if test "$debug" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for debug assert" >&5 +$as_echo_n "checking for debug assert... " >&6; } + # Check whether --enable-debug-assert was given. +if test "${enable_debug_assert+set}" = set; then : + enableval=$enable_debug_assert; debug_assert="$enableval" +else + debug_assert="no" +fi + + if test "$debug_assert" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define ALSA_DEBUG_ASSERT /**/" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tmpdir" >&5 +$as_echo_n "checking for tmpdir... " >&6; } + +# Check whether --with-tmpdir was given. +if test "${with_tmpdir+set}" = set; then : + withval=$with_tmpdir; tmpdir="$withval" +else + tmpdir="/tmp" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tmpdir" >&5 +$as_echo "$tmpdir" >&6; } + +cat >>confdefs.h <<_ACEOF +#define TMPDIR "$tmpdir" +_ACEOF + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for softfloat" >&5 +$as_echo_n "checking for softfloat... " >&6; } + +# Check whether --with-softfloat was given. +if test "${with_softfloat+set}" = set; then : + withval=$with_softfloat; case "$withval" in + y|yes) softfloat=yes ;; + *) softfloat=no ;; + esac +fi + +if test "$softfloat" = "yes" ; then + +$as_echo "#define HAVE_SOFT_FLOAT \"1\"" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +ALSA_DEPLIBS="" +if test "$softfloat" != "yes"; then + ALSA_DEPLIBS="-lm" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdl" >&5 +$as_echo_n "checking for libdl... " >&6; } + +# Check whether --with-libdl was given. +if test "${with_libdl+set}" = set; then : + withval=$with_libdl; have_libdl="$withval" +else + have_libdl="yes" +fi + +if test "$have_libdl" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5 +$as_echo_n "checking for dlsym in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlsym+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlsym (); +int +main () +{ +return dlsym (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlsym=yes +else + ac_cv_lib_dl_dlsym=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5 +$as_echo "$ac_cv_lib_dl_dlsym" >&6; } +if test "x$ac_cv_lib_dl_dlsym" = x""yes; then : + HAVE_LIBDL="yes" +fi + + if test "$HAVE_LIBDL" = "yes" ; then + ALSA_DEPLIBS="$ALSA_DEPLIBS -ldl" + +$as_echo "#define HAVE_LIBDL 1" >>confdefs.h + + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + if test "$HAVE_LIBDL"="yes"; then + BUILD_MODULES_TRUE= + BUILD_MODULES_FALSE='#' +else + BUILD_MODULES_TRUE='#' + BUILD_MODULES_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread" >&5 +$as_echo_n "checking for pthread... " >&6; } + +# Check whether --with-pthread was given. +if test "${with_pthread+set}" = set; then : + withval=$with_pthread; have_pthread="$withval" +else + have_pthread="yes" +fi + +if test "$have_pthread" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthread" >&5 +$as_echo_n "checking for pthread_join in -lpthread... " >&6; } +if test "${ac_cv_lib_pthread_pthread_join+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_join (); +int +main () +{ +return pthread_join (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_join=yes +else + ac_cv_lib_pthread_pthread_join=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_join" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_join" >&6; } +if test "x$ac_cv_lib_pthread_pthread_join" = x""yes; then : + HAVE_LIBPTHREAD="yes" +fi + + if test "$HAVE_LIBPTHREAD" = "yes"; then + ALSA_DEPLIBS="$ALSA_DEPLIBS -lpthread" + +$as_echo "#define HAVE_LIBPTHREAD 1" >>confdefs.h + + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for librt" >&5 +$as_echo_n "checking for librt... " >&6; } + +# Check whether --with-librt was given. +if test "${with_librt+set}" = set; then : + withval=$with_librt; have_librt="$withval" +else + have_librt="yes" +fi + +if test "$have_librt" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = x""yes; then : + HAVE_LIBRT="yes" +fi + + if test "$HAVE_LIBRT" = "yes" ; then + ALSA_DEPLIBS="$ALSA_DEPLIBS -lrt" + +$as_echo "#define HAVE_LIBRT 1" >>confdefs.h + + +$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for architecture" >&5 +$as_echo_n "checking for architecture... " >&6; } +case "$host" in +i?86*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: x86" >&5 +$as_echo "x86" >&6; } + ;; +x86_64*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: x86" >&5 +$as_echo "x86" >&6; } + ;; +alpha*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: alpha" >&5 +$as_echo "alpha" >&6; } + ;; +powerpc*|ppc*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ppc" >&5 +$as_echo "ppc" >&6; } + CPPFLAGS="$CPPFLAGS -D__ppc__" + ;; +ia64*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ia64" >&5 +$as_echo "ia64" >&6; } + CPPFLAGS="$CPPFLAGS -D__ia64__" + ;; +mips*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: mips" >&5 +$as_echo "mips" >&6; } + CPPFLAGS="$CPPFLAGS -D__mips__" + ;; +arm*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: arm" >&5 +$as_echo "arm" >&6; } + CPPFLAGS="$CPPFLAGS -D__arm__" + ;; +*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $host_cpu" >&5 +$as_echo "$host_cpu" >&6; } + echo "No atomic operations supported.." + ;; +esac + +for ac_header in wordexp.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "wordexp.h" "ac_cv_header_wordexp_h" "$ac_includes_default" +if test "x$ac_cv_header_wordexp_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WORDEXP_H 1 +_ACEOF + +fi + +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for resmgr support" >&5 +$as_echo_n "checking for resmgr support... " >&6; } +# Check whether --enable-resmgr was given. +if test "${enable_resmgr+set}" = set; then : + enableval=$enable_resmgr; resmgr="$enableval" +else + resmgr="no" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $resmgr" >&5 +$as_echo "$resmgr" >&6; } +if test "$resmgr" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rsm_open_device in -lresmgr" >&5 +$as_echo_n "checking for rsm_open_device in -lresmgr... " >&6; } +if test "${ac_cv_lib_resmgr_rsm_open_device+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresmgr $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char rsm_open_device (); +int +main () +{ +return rsm_open_device (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_resmgr_rsm_open_device=yes +else + ac_cv_lib_resmgr_rsm_open_device=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resmgr_rsm_open_device" >&5 +$as_echo "$ac_cv_lib_resmgr_rsm_open_device" >&6; } +if test "x$ac_cv_lib_resmgr_rsm_open_device" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRESMGR 1 +_ACEOF + + LIBS="-lresmgr $LIBS" + +else + as_fn_error $? "Cannot find libresmgr" "$LINENO" 5 +fi + + +$as_echo "#define SUPPORT_RESMGR \"1\"" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for aload* support" >&5 +$as_echo_n "checking for aload* support... " >&6; } +# Check whether --enable-aload was given. +if test "${enable_aload+set}" = set; then : + enableval=$enable_aload; aload="$enableval" +else + aload="yes" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $aload" >&5 +$as_echo "$aload" >&6; } +if test "$aload" = "yes"; then + +$as_echo "#define SUPPORT_ALOAD \"1\"" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA device file directory" >&5 +$as_echo_n "checking for ALSA device file directory... " >&6; } + +# Check whether --with-alsa-devdir was given. +if test "${with_alsa_devdir+set}" = set; then : + withval=$with_alsa_devdir; alsa_dev_dir="$withval" +else + alsa_dev_dir="/dev/snd" +fi + +if echo "$alsa_dev_dir" | grep -v '/$' > /dev/null; then + alsa_dev_dir="$alsa_dev_dir/" +fi + +cat >>confdefs.h <<_ACEOF +#define ALSA_DEVICE_DIRECTORY "$alsa_dev_dir" +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $alsa_dev_dir" >&5 +$as_echo "$alsa_dev_dir" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for aload* device file directory" >&5 +$as_echo_n "checking for aload* device file directory... " >&6; } + +# Check whether --with-aload-devdir was given. +if test "${with_aload_devdir+set}" = set; then : + withval=$with_aload_devdir; aload_dev_dir="$withval" +else + aload_dev_dir="/dev" +fi + +if echo "$aload_dev_dir" | grep -v '/$' > /dev/null; then + aload_dev_dir="$aload_dev_dir/" +fi + +cat >>confdefs.h <<_ACEOF +#define ALOAD_DEVICE_DIRECTORY "$aload_dev_dir" +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $aload_dev_dir" >&5 +$as_echo "$aload_dev_dir" >&6; } + +# Check whether --enable-mixer was given. +if test "${enable_mixer+set}" = set; then : + enableval=$enable_mixer; build_mixer="$enableval" +else + build_mixer="yes" +fi + +# Check whether --enable-pcm was given. +if test "${enable_pcm+set}" = set; then : + enableval=$enable_pcm; build_pcm="$enableval" +else + build_pcm="yes" +fi + +# Check whether --enable-rawmidi was given. +if test "${enable_rawmidi+set}" = set; then : + enableval=$enable_rawmidi; build_rawmidi="$enableval" +else + build_rawmidi="yes" +fi + +# Check whether --enable-hwdep was given. +if test "${enable_hwdep+set}" = set; then : + enableval=$enable_hwdep; build_hwdep="$enableval" +else + build_hwdep="yes" +fi + +# Check whether --enable-seq was given. +if test "${enable_seq+set}" = set; then : + enableval=$enable_seq; build_seq="$enableval" +else + build_seq="yes" +fi + +# Check whether --enable-ucm was given. +if test "${enable_ucm+set}" = set; then : + enableval=$enable_ucm; build_ucm="$enableval" +else + build_ucm="yes" +fi + +# Check whether --enable-alisp was given. +if test "${enable_alisp+set}" = set; then : + enableval=$enable_alisp; build_alisp="$enableval" +else + build_alisp="yes" +fi + +test "$softfloat" = "yes" && build_alisp="no" +# Check whether --enable-old-symbols was given. +if test "${enable_old_symbols+set}" = set; then : + enableval=$enable_old_symbols; keep_old_symbols="$enableval" +else + keep_old_symbols="yes" +fi + + if test x$keep_old_symbols = xyes; then + KEEP_OLD_SYMBOLS_TRUE= + KEEP_OLD_SYMBOLS_FALSE='#' +else + KEEP_OLD_SYMBOLS_TRUE='#' + KEEP_OLD_SYMBOLS_FALSE= +fi + + +# Check whether --enable-python was given. +if test "${enable_python+set}" = set; then : + enableval=$enable_python; build_python="$enableval" +else + build_python="yes" +fi + +PYTHON_LIBS="" +PYTHON_INCLUDES="" +if test "$build_python" = "yes"; then + +# Check whether --with-pythonlibs was given. +if test "${with_pythonlibs+set}" = set; then : + withval=$with_pythonlibs; pythonlibs="$withval" +else + pythonlibs=`python-config --libs` +fi + + +# Check whether --with-pythonincludes was given. +if test "${with_pythonincludes+set}" = set; then : + withval=$with_pythonincludes; pythonincludes="$withval" +else + pythonincludes=`python-config --includes` +fi + + if test -z "$pythonlibs"; then + echo "Unable to determine python libraries! Probably python-config is not" + echo "available on this system. Please, use --with-pythonlibs and" + echo "--with-pythonincludes options. Python components are disabled in this build." + build_python="no" + else + PYTHON_LIBS="$pythonlibs" + PYTHON_INCLUDES="$pythonincludes" + fi +fi + + + + if test x$build_mixer = xyes; then + BUILD_MIXER_TRUE= + BUILD_MIXER_FALSE='#' +else + BUILD_MIXER_TRUE='#' + BUILD_MIXER_FALSE= +fi + + if test x$build_pcm = xyes; then + BUILD_PCM_TRUE= + BUILD_PCM_FALSE='#' +else + BUILD_PCM_TRUE='#' + BUILD_PCM_FALSE= +fi + + if test x$build_rawmidi = xyes; then + BUILD_RAWMIDI_TRUE= + BUILD_RAWMIDI_FALSE='#' +else + BUILD_RAWMIDI_TRUE='#' + BUILD_RAWMIDI_FALSE= +fi + + if test x$build_hwdep = xyes; then + BUILD_HWDEP_TRUE= + BUILD_HWDEP_FALSE='#' +else + BUILD_HWDEP_TRUE='#' + BUILD_HWDEP_FALSE= +fi + + if test x$build_seq = xyes; then + BUILD_SEQ_TRUE= + BUILD_SEQ_FALSE='#' +else + BUILD_SEQ_TRUE='#' + BUILD_SEQ_FALSE= +fi + + if test x$build_ucm = xyes; then + BUILD_UCM_TRUE= + BUILD_UCM_FALSE='#' +else + BUILD_UCM_TRUE='#' + BUILD_UCM_FALSE= +fi + + if test x$build_alisp = xyes; then + BUILD_ALISP_TRUE= + BUILD_ALISP_FALSE='#' +else + BUILD_ALISP_TRUE='#' + BUILD_ALISP_FALSE= +fi + + if test x$build_python = xyes; then + BUILD_PYTHON_TRUE= + BUILD_PYTHON_FALSE='#' +else + BUILD_PYTHON_TRUE='#' + BUILD_PYTHON_FALSE= +fi + + +if test "$build_mixer" = "yes"; then + +$as_echo "#define BUILD_MIXER \"1\"" >>confdefs.h + +fi +if test "$build_pcm" = "yes"; then + +$as_echo "#define BUILD_PCM \"1\"" >>confdefs.h + +fi +if test "$build_rawmidi" = "yes"; then + +$as_echo "#define BUILD_RAWMIDI \"1\"" >>confdefs.h + +fi +if test "$build_hwdep" = "yes"; then + +$as_echo "#define BUILD_HWDEP \"1\"" >>confdefs.h + +fi +if test "$build_seq" = "yes"; then + +$as_echo "#define BUILD_SEQ \"1\"" >>confdefs.h + +fi +if test "$build_ucm" = "yes"; then + +$as_echo "#define BUILD_UCM \"1\"" >>confdefs.h + +fi + + +if test "$build_pcm" = "yes"; then + +# Check whether --with-pcm-plugins was given. +if test "${with_pcm_plugins+set}" = set; then : + withval=$with_pcm_plugins; pcm_plugins="$withval" +else + pcm_plugins="all" +fi + +else +pcm_plugins="" +fi + +PCM_PLUGIN_LIST="copy linear route mulaw alaw adpcm rate plug multi shm file null empty share meter hooks lfloat ladspa dmix dshare dsnoop asym iec958 softvol extplug ioplug mmap_emul" + +build_pcm_plugin="no" +for t in $PCM_PLUGIN_LIST; do + eval build_pcm_$t="no" +done + +pcm_plugins=`echo $pcm_plugins | sed 's/,/ /g'` +for p in $pcm_plugins; do + for t in $PCM_PLUGIN_LIST; do + if test "$p" = "$t" -o "$p" = "all"; then + eval build_pcm_$t="yes" + build_pcm_plugin="yes" + fi + done +done + +if test "$build_pcm_plug" = "yes"; then + build_pcm_linear="yes" + build_pcm_copy="yes" +fi + +if test "$build_pcm_ioplug" = "yes"; then + build_pcm_extplug="yes" +fi + +if test "$HAVE_LIBDL" != "yes"; then + build_pcm_meter="no" + build_pcm_ladspa="no" + build_pcm_pcm_ioplug="no" + build_pcm_pcm_extplug="no" +fi + +if test "$HAVE_LIBPTHREAD" != "yes"; then + build_pcm_share="no" +fi + +if test "$softfloat" = "yes"; then + build_pcm_lfloat="no" + build_pcm_ladspa="no" +fi + + if test x$build_pcm_plugin = xyes; then + BUILD_PCM_PLUGIN_TRUE= + BUILD_PCM_PLUGIN_FALSE='#' +else + BUILD_PCM_PLUGIN_TRUE='#' + BUILD_PCM_PLUGIN_FALSE= +fi + + if test x$build_pcm_copy = xyes; then + BUILD_PCM_PLUGIN_COPY_TRUE= + BUILD_PCM_PLUGIN_COPY_FALSE='#' +else + BUILD_PCM_PLUGIN_COPY_TRUE='#' + BUILD_PCM_PLUGIN_COPY_FALSE= +fi + + if test x$build_pcm_linear = xyes; then + BUILD_PCM_PLUGIN_LINEAR_TRUE= + BUILD_PCM_PLUGIN_LINEAR_FALSE='#' +else + BUILD_PCM_PLUGIN_LINEAR_TRUE='#' + BUILD_PCM_PLUGIN_LINEAR_FALSE= +fi + + if test x$build_pcm_route = xyes; then + BUILD_PCM_PLUGIN_ROUTE_TRUE= + BUILD_PCM_PLUGIN_ROUTE_FALSE='#' +else + BUILD_PCM_PLUGIN_ROUTE_TRUE='#' + BUILD_PCM_PLUGIN_ROUTE_FALSE= +fi + + if test x$build_pcm_mulaw = xyes; then + BUILD_PCM_PLUGIN_MULAW_TRUE= + BUILD_PCM_PLUGIN_MULAW_FALSE='#' +else + BUILD_PCM_PLUGIN_MULAW_TRUE='#' + BUILD_PCM_PLUGIN_MULAW_FALSE= +fi + + if test x$build_pcm_alaw = xyes; then + BUILD_PCM_PLUGIN_ALAW_TRUE= + BUILD_PCM_PLUGIN_ALAW_FALSE='#' +else + BUILD_PCM_PLUGIN_ALAW_TRUE='#' + BUILD_PCM_PLUGIN_ALAW_FALSE= +fi + + if test x$build_pcm_adpcm = xyes; then + BUILD_PCM_PLUGIN_ADPCM_TRUE= + BUILD_PCM_PLUGIN_ADPCM_FALSE='#' +else + BUILD_PCM_PLUGIN_ADPCM_TRUE='#' + BUILD_PCM_PLUGIN_ADPCM_FALSE= +fi + + if test x$build_pcm_rate = xyes; then + BUILD_PCM_PLUGIN_RATE_TRUE= + BUILD_PCM_PLUGIN_RATE_FALSE='#' +else + BUILD_PCM_PLUGIN_RATE_TRUE='#' + BUILD_PCM_PLUGIN_RATE_FALSE= +fi + + if test x$build_pcm_plug = xyes; then + BUILD_PCM_PLUGIN_PLUG_TRUE= + BUILD_PCM_PLUGIN_PLUG_FALSE='#' +else + BUILD_PCM_PLUGIN_PLUG_TRUE='#' + BUILD_PCM_PLUGIN_PLUG_FALSE= +fi + + if test x$build_pcm_multi = xyes; then + BUILD_PCM_PLUGIN_MULTI_TRUE= + BUILD_PCM_PLUGIN_MULTI_FALSE='#' +else + BUILD_PCM_PLUGIN_MULTI_TRUE='#' + BUILD_PCM_PLUGIN_MULTI_FALSE= +fi + + if test x$build_pcm_shm = xyes; then + BUILD_PCM_PLUGIN_SHM_TRUE= + BUILD_PCM_PLUGIN_SHM_FALSE='#' +else + BUILD_PCM_PLUGIN_SHM_TRUE='#' + BUILD_PCM_PLUGIN_SHM_FALSE= +fi + + if test x$build_pcm_file = xyes; then + BUILD_PCM_PLUGIN_FILE_TRUE= + BUILD_PCM_PLUGIN_FILE_FALSE='#' +else + BUILD_PCM_PLUGIN_FILE_TRUE='#' + BUILD_PCM_PLUGIN_FILE_FALSE= +fi + + if test x$build_pcm_null = xyes; then + BUILD_PCM_PLUGIN_NULL_TRUE= + BUILD_PCM_PLUGIN_NULL_FALSE='#' +else + BUILD_PCM_PLUGIN_NULL_TRUE='#' + BUILD_PCM_PLUGIN_NULL_FALSE= +fi + + if test x$build_pcm_empty = xyes; then + BUILD_PCM_PLUGIN_EMPTY_TRUE= + BUILD_PCM_PLUGIN_EMPTY_FALSE='#' +else + BUILD_PCM_PLUGIN_EMPTY_TRUE='#' + BUILD_PCM_PLUGIN_EMPTY_FALSE= +fi + + if test x$build_pcm_share = xyes; then + BUILD_PCM_PLUGIN_SHARE_TRUE= + BUILD_PCM_PLUGIN_SHARE_FALSE='#' +else + BUILD_PCM_PLUGIN_SHARE_TRUE='#' + BUILD_PCM_PLUGIN_SHARE_FALSE= +fi + + if test x$build_pcm_meter = xyes; then + BUILD_PCM_PLUGIN_METER_TRUE= + BUILD_PCM_PLUGIN_METER_FALSE='#' +else + BUILD_PCM_PLUGIN_METER_TRUE='#' + BUILD_PCM_PLUGIN_METER_FALSE= +fi + + if test x$build_pcm_hooks = xyes; then + BUILD_PCM_PLUGIN_HOOKS_TRUE= + BUILD_PCM_PLUGIN_HOOKS_FALSE='#' +else + BUILD_PCM_PLUGIN_HOOKS_TRUE='#' + BUILD_PCM_PLUGIN_HOOKS_FALSE= +fi + + if test x$build_pcm_lfloat = xyes; then + BUILD_PCM_PLUGIN_LFLOAT_TRUE= + BUILD_PCM_PLUGIN_LFLOAT_FALSE='#' +else + BUILD_PCM_PLUGIN_LFLOAT_TRUE='#' + BUILD_PCM_PLUGIN_LFLOAT_FALSE= +fi + + if test x$build_pcm_ladspa = xyes; then + BUILD_PCM_PLUGIN_LADSPA_TRUE= + BUILD_PCM_PLUGIN_LADSPA_FALSE='#' +else + BUILD_PCM_PLUGIN_LADSPA_TRUE='#' + BUILD_PCM_PLUGIN_LADSPA_FALSE= +fi + + if test x$build_pcm_dmix = xyes; then + BUILD_PCM_PLUGIN_DMIX_TRUE= + BUILD_PCM_PLUGIN_DMIX_FALSE='#' +else + BUILD_PCM_PLUGIN_DMIX_TRUE='#' + BUILD_PCM_PLUGIN_DMIX_FALSE= +fi + + if test x$build_pcm_dshare = xyes; then + BUILD_PCM_PLUGIN_DSHARE_TRUE= + BUILD_PCM_PLUGIN_DSHARE_FALSE='#' +else + BUILD_PCM_PLUGIN_DSHARE_TRUE='#' + BUILD_PCM_PLUGIN_DSHARE_FALSE= +fi + + if test x$build_pcm_dsnoop = xyes; then + BUILD_PCM_PLUGIN_DSNOOP_TRUE= + BUILD_PCM_PLUGIN_DSNOOP_FALSE='#' +else + BUILD_PCM_PLUGIN_DSNOOP_TRUE='#' + BUILD_PCM_PLUGIN_DSNOOP_FALSE= +fi + + if test x$build_pcm_asym = xyes; then + BUILD_PCM_PLUGIN_ASYM_TRUE= + BUILD_PCM_PLUGIN_ASYM_FALSE='#' +else + BUILD_PCM_PLUGIN_ASYM_TRUE='#' + BUILD_PCM_PLUGIN_ASYM_FALSE= +fi + + if test x$build_pcm_iec958 = xyes; then + BUILD_PCM_PLUGIN_IEC958_TRUE= + BUILD_PCM_PLUGIN_IEC958_FALSE='#' +else + BUILD_PCM_PLUGIN_IEC958_TRUE='#' + BUILD_PCM_PLUGIN_IEC958_FALSE= +fi + + if test x$build_pcm_softvol = xyes; then + BUILD_PCM_PLUGIN_SOFTVOL_TRUE= + BUILD_PCM_PLUGIN_SOFTVOL_FALSE='#' +else + BUILD_PCM_PLUGIN_SOFTVOL_TRUE='#' + BUILD_PCM_PLUGIN_SOFTVOL_FALSE= +fi + + if test x$build_pcm_extplug = xyes; then + BUILD_PCM_PLUGIN_EXTPLUG_TRUE= + BUILD_PCM_PLUGIN_EXTPLUG_FALSE='#' +else + BUILD_PCM_PLUGIN_EXTPLUG_TRUE='#' + BUILD_PCM_PLUGIN_EXTPLUG_FALSE= +fi + + if test x$build_pcm_ioplug = xyes; then + BUILD_PCM_PLUGIN_IOPLUG_TRUE= + BUILD_PCM_PLUGIN_IOPLUG_FALSE='#' +else + BUILD_PCM_PLUGIN_IOPLUG_TRUE='#' + BUILD_PCM_PLUGIN_IOPLUG_FALSE= +fi + + if test x$build_pcm_mmap_emul = xyes; then + BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE= + BUILD_PCM_PLUGIN_MMAP_EMUL_FALSE='#' +else + BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE='#' + BUILD_PCM_PLUGIN_MMAP_EMUL_FALSE= +fi + + +if test "$build_pcm_rate" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_RATE \"1\"" >>confdefs.h + +fi +if test "$build_pcm_route" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_ROUTE \"1\"" >>confdefs.h + +fi +if test "$build_pcm_lfloat" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_LFLOAT \"1\"" >>confdefs.h + +fi +if test "$build_pcm_adpcm" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_ADPCM \"1\"" >>confdefs.h + +fi +if test "$build_pcm_mulaw" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_MULAW \"1\"" >>confdefs.h + +fi +if test "$build_pcm_alaw" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_ALAW \"1\"" >>confdefs.h + +fi +if test "$build_pcm_mmap_emul" = "yes"; then + +$as_echo "#define BUILD_PCM_PLUGIN_MMAP_EMUL \"1\"" >>confdefs.h + +fi + + +rm -f "$srcdir"/src/pcm/pcm_symbols_list.c +touch "$srcdir"/src/pcm/pcm_symbols_list.c +for t in $PCM_PLUGIN_LIST; do + if eval test \$build_pcm_$t = yes; then + echo \&_snd_module_pcm_$t, >> "$srcdir"/src/pcm/pcm_symbols_list.c + fi +done + + + +# Check whether --with-ctl-plugins was given. +if test "${with_ctl_plugins+set}" = set; then : + withval=$with_ctl_plugins; ctl_plugins="$withval" +else + ctl_plugins="all" +fi + + +CTL_PLUGIN_LIST="shm ext" + +build_ctl_plugin="no" +for t in $CTL_PLUGIN_LIST; do + eval build_ctl_$t="no" +done + +ctl_plugins=`echo $ctl_plugins | sed 's/,/ /g'` +for p in $ctl_plugins; do + for t in $CTL_PLUGIN_LIST; do + if test "$p" = "$t" -o "$p" = "all"; then + eval build_ctl_$t="yes" + build_ctl_plugin="yes" + fi + done +done + + if test x$build_ctl_plugin = xyes; then + BUILD_CTL_PLUGIN_TRUE= + BUILD_CTL_PLUGIN_FALSE='#' +else + BUILD_CTL_PLUGIN_TRUE='#' + BUILD_CTL_PLUGIN_FALSE= +fi + + if test x$build_ctl_shm = xyes; then + BUILD_CTL_PLUGIN_SHM_TRUE= + BUILD_CTL_PLUGIN_SHM_FALSE='#' +else + BUILD_CTL_PLUGIN_SHM_TRUE='#' + BUILD_CTL_PLUGIN_SHM_FALSE= +fi + + if test x$build_ctl_ext = xyes; then + BUILD_CTL_PLUGIN_EXT_TRUE= + BUILD_CTL_PLUGIN_EXT_FALSE='#' +else + BUILD_CTL_PLUGIN_EXT_TRUE='#' + BUILD_CTL_PLUGIN_EXT_FALSE= +fi + + +rm -f "$srcdir"/src/control/ctl_symbols_list.c +touch "$srcdir"/src/control/ctl_symbols_list.c +for t in $CTL_PLUGIN_LIST; do + if eval test \$build_ctl_$t = yes; then + echo \&_snd_module_control_$t, >> "$srcdir"/src/control/ctl_symbols_list.c + fi +done + +if test ! -L "$srcdir"/include/alsa ; then + echo "Making a symlink include/alsa" + rm -f "$srcdir"/include/alsa + ln -sf . "$srcdir"/include/alsa +fi + +ac_config_files="$ac_config_files Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg include/Makefile include/sound/Makefile src/Versions src/Makefile src/control/Makefile src/mixer/Makefile src/pcm/Makefile src/pcm/scopes/Makefile src/rawmidi/Makefile src/timer/Makefile src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile src/compat/Makefile src/alisp/Makefile src/conf/Makefile src/conf/cards/Makefile src/conf/pcm/Makefile modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile alsalisp/Makefile aserver/Makefile test/Makefile test/lsb/Makefile utils/Makefile utils/alsa-lib.spec utils/alsa.pc" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${INSTALL_M4_TRUE}" && test -z "${INSTALL_M4_FALSE}"; then + as_fn_error $? "conditional \"INSTALL_M4\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ALSA_HSEARCH_R_TRUE}" && test -z "${ALSA_HSEARCH_R_FALSE}"; then + as_fn_error $? "conditional \"ALSA_HSEARCH_R\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${VERSIONED_SYMBOLS_TRUE}" && test -z "${VERSIONED_SYMBOLS_FALSE}"; then + as_fn_error $? "conditional \"VERSIONED_SYMBOLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SYMBOLIC_FUNCTIONS_TRUE}" && test -z "${SYMBOLIC_FUNCTIONS_FALSE}"; then + as_fn_error $? "conditional \"SYMBOLIC_FUNCTIONS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_MODULES_TRUE}" && test -z "${BUILD_MODULES_FALSE}"; then + as_fn_error $? "conditional \"BUILD_MODULES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${KEEP_OLD_SYMBOLS_TRUE}" && test -z "${KEEP_OLD_SYMBOLS_FALSE}"; then + as_fn_error $? "conditional \"KEEP_OLD_SYMBOLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_MIXER_TRUE}" && test -z "${BUILD_MIXER_FALSE}"; then + as_fn_error $? "conditional \"BUILD_MIXER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_TRUE}" && test -z "${BUILD_PCM_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_RAWMIDI_TRUE}" && test -z "${BUILD_RAWMIDI_FALSE}"; then + as_fn_error $? "conditional \"BUILD_RAWMIDI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_HWDEP_TRUE}" && test -z "${BUILD_HWDEP_FALSE}"; then + as_fn_error $? "conditional \"BUILD_HWDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_SEQ_TRUE}" && test -z "${BUILD_SEQ_FALSE}"; then + as_fn_error $? "conditional \"BUILD_SEQ\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_UCM_TRUE}" && test -z "${BUILD_UCM_FALSE}"; then + as_fn_error $? "conditional \"BUILD_UCM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_ALISP_TRUE}" && test -z "${BUILD_ALISP_FALSE}"; then + as_fn_error $? "conditional \"BUILD_ALISP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PYTHON_TRUE}" && test -z "${BUILD_PYTHON_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PYTHON\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_TRUE}" && test -z "${BUILD_PCM_PLUGIN_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_COPY_TRUE}" && test -z "${BUILD_PCM_PLUGIN_COPY_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_COPY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_LINEAR_TRUE}" && test -z "${BUILD_PCM_PLUGIN_LINEAR_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_LINEAR\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_ROUTE_TRUE}" && test -z "${BUILD_PCM_PLUGIN_ROUTE_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_ROUTE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_MULAW_TRUE}" && test -z "${BUILD_PCM_PLUGIN_MULAW_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_MULAW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_ALAW_TRUE}" && test -z "${BUILD_PCM_PLUGIN_ALAW_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_ALAW\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_ADPCM_TRUE}" && test -z "${BUILD_PCM_PLUGIN_ADPCM_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_ADPCM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_RATE_TRUE}" && test -z "${BUILD_PCM_PLUGIN_RATE_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_RATE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_PLUG_TRUE}" && test -z "${BUILD_PCM_PLUGIN_PLUG_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_PLUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_MULTI_TRUE}" && test -z "${BUILD_PCM_PLUGIN_MULTI_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_MULTI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_SHM_TRUE}" && test -z "${BUILD_PCM_PLUGIN_SHM_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_SHM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_FILE_TRUE}" && test -z "${BUILD_PCM_PLUGIN_FILE_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_FILE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_NULL_TRUE}" && test -z "${BUILD_PCM_PLUGIN_NULL_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_NULL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_EMPTY_TRUE}" && test -z "${BUILD_PCM_PLUGIN_EMPTY_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_EMPTY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_SHARE_TRUE}" && test -z "${BUILD_PCM_PLUGIN_SHARE_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_SHARE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_METER_TRUE}" && test -z "${BUILD_PCM_PLUGIN_METER_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_METER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_HOOKS_TRUE}" && test -z "${BUILD_PCM_PLUGIN_HOOKS_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_HOOKS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_LFLOAT_TRUE}" && test -z "${BUILD_PCM_PLUGIN_LFLOAT_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_LFLOAT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_LADSPA_TRUE}" && test -z "${BUILD_PCM_PLUGIN_LADSPA_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_LADSPA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_DMIX_TRUE}" && test -z "${BUILD_PCM_PLUGIN_DMIX_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_DMIX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_DSHARE_TRUE}" && test -z "${BUILD_PCM_PLUGIN_DSHARE_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_DSHARE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_DSNOOP_TRUE}" && test -z "${BUILD_PCM_PLUGIN_DSNOOP_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_DSNOOP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_ASYM_TRUE}" && test -z "${BUILD_PCM_PLUGIN_ASYM_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_ASYM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_IEC958_TRUE}" && test -z "${BUILD_PCM_PLUGIN_IEC958_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_IEC958\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_SOFTVOL_TRUE}" && test -z "${BUILD_PCM_PLUGIN_SOFTVOL_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_SOFTVOL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_EXTPLUG_TRUE}" && test -z "${BUILD_PCM_PLUGIN_EXTPLUG_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_EXTPLUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_IOPLUG_TRUE}" && test -z "${BUILD_PCM_PLUGIN_IOPLUG_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_IOPLUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE}" && test -z "${BUILD_PCM_PLUGIN_MMAP_EMUL_FALSE}"; then + as_fn_error $? "conditional \"BUILD_PCM_PLUGIN_MMAP_EMUL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_CTL_PLUGIN_TRUE}" && test -z "${BUILD_CTL_PLUGIN_FALSE}"; then + as_fn_error $? "conditional \"BUILD_CTL_PLUGIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_CTL_PLUGIN_SHM_TRUE}" && test -z "${BUILD_CTL_PLUGIN_SHM_FALSE}"; then + as_fn_error $? "conditional \"BUILD_CTL_PLUGIN_SHM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_CTL_PLUGIN_EXT_TRUE}" && test -z "${BUILD_CTL_PLUGIN_EXT_FALSE}"; then + as_fn_error $? "conditional \"BUILD_CTL_PLUGIN_EXT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.67. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.67, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' +macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' +macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' +pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' +host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' +host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' +host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' +build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' +build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' +build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' +SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' +Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' +GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' +EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' +FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' +LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' +NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' +LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' +ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' +exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' +lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' +reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' +AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' +STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' +RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' +compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' +GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' +SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' +ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' +need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' +LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' +libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' +version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' +runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' +libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' +soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' +old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' +striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +SHELL \ +ECHO \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` + ;; +esac + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "include/config.h") CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "doc/pictures/Makefile") CONFIG_FILES="$CONFIG_FILES doc/pictures/Makefile" ;; + "doc/doxygen.cfg") CONFIG_FILES="$CONFIG_FILES doc/doxygen.cfg" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "include/sound/Makefile") CONFIG_FILES="$CONFIG_FILES include/sound/Makefile" ;; + "src/Versions") CONFIG_FILES="$CONFIG_FILES src/Versions" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "src/control/Makefile") CONFIG_FILES="$CONFIG_FILES src/control/Makefile" ;; + "src/mixer/Makefile") CONFIG_FILES="$CONFIG_FILES src/mixer/Makefile" ;; + "src/pcm/Makefile") CONFIG_FILES="$CONFIG_FILES src/pcm/Makefile" ;; + "src/pcm/scopes/Makefile") CONFIG_FILES="$CONFIG_FILES src/pcm/scopes/Makefile" ;; + "src/rawmidi/Makefile") CONFIG_FILES="$CONFIG_FILES src/rawmidi/Makefile" ;; + "src/timer/Makefile") CONFIG_FILES="$CONFIG_FILES src/timer/Makefile" ;; + "src/hwdep/Makefile") CONFIG_FILES="$CONFIG_FILES src/hwdep/Makefile" ;; + "src/seq/Makefile") CONFIG_FILES="$CONFIG_FILES src/seq/Makefile" ;; + "src/ucm/Makefile") CONFIG_FILES="$CONFIG_FILES src/ucm/Makefile" ;; + "src/compat/Makefile") CONFIG_FILES="$CONFIG_FILES src/compat/Makefile" ;; + "src/alisp/Makefile") CONFIG_FILES="$CONFIG_FILES src/alisp/Makefile" ;; + "src/conf/Makefile") CONFIG_FILES="$CONFIG_FILES src/conf/Makefile" ;; + "src/conf/cards/Makefile") CONFIG_FILES="$CONFIG_FILES src/conf/cards/Makefile" ;; + "src/conf/pcm/Makefile") CONFIG_FILES="$CONFIG_FILES src/conf/pcm/Makefile" ;; + "modules/Makefile") CONFIG_FILES="$CONFIG_FILES modules/Makefile" ;; + "modules/mixer/Makefile") CONFIG_FILES="$CONFIG_FILES modules/mixer/Makefile" ;; + "modules/mixer/simple/Makefile") CONFIG_FILES="$CONFIG_FILES modules/mixer/simple/Makefile" ;; + "alsalisp/Makefile") CONFIG_FILES="$CONFIG_FILES alsalisp/Makefile" ;; + "aserver/Makefile") CONFIG_FILES="$CONFIG_FILES aserver/Makefile" ;; + "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; + "test/lsb/Makefile") CONFIG_FILES="$CONFIG_FILES test/lsb/Makefile" ;; + "utils/Makefile") CONFIG_FILES="$CONFIG_FILES utils/Makefile" ;; + "utils/alsa-lib.spec") CONFIG_FILES="$CONFIG_FILES utils/alsa-lib.spec" ;; + "utils/alsa.pc") CONFIG_FILES="$CONFIG_FILES utils/alsa.pc" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that does not interpret backslashes. +ECHO=$lt_ECHO + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo "Creating asoundlib.h..." +cp "$srcdir"/include/asoundlib-head.h include/asoundlib.h +test "$build_pcm" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_rawmidi" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_pcm" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_hwdep" = "yes" && echo "#include " >> include/asoundlib.h +echo "#include " >> include/asoundlib.h +test "$build_mixer" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +cat "$srcdir"/include/asoundlib-tail.h >> include/asoundlib.h + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..e33e629 --- /dev/null +++ b/configure.in @@ -0,0 +1,631 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.59) +AC_INIT(src/control/control.c) + +AC_CONFIG_MACRO_DIR([m4]) + +dnl ************************************************* +dnl current:revision:age +dnl change (without API) = c:r+1:a +dnl change API = c+1:0:a +dnl add API = c+1:0:a+1 +dnl remove API = c+1:0:0 +dnl ************************************************* +AC_CANONICAL_HOST +AM_INIT_AUTOMAKE(alsa-lib, 1.0.24.1) +eval LIBTOOL_VERSION_INFO="2:0:0" +dnl ************************************************* +AM_CONDITIONAL(INSTALL_M4, test -n "${ACLOCAL}") + +# Test for new silent rules and enable only if they are available +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREFIX_DEFAULT(/usr) + +dnl Checks for programs. + +dnl try to gues cross-compiler if not set +if test "x$host" != "x$build" -a -z "`echo $CC | grep -e '-gcc'`"; +then + AC_MSG_CHECKING(for cross-compiler) + + which ${program_prefix}gcc >/dev/null 2>&1 && CC=${program_prefix}gcc + which ${host_cpu}-${host_os}-gcc >/dev/null 2>&1 \ + && CC=${host_cpu}-${host-os}-gcc + which ${host_cpu}-${host_vendor}-${host_os}-gcc >/dev/null 2>&1 \ + && CC=${host_cpu}-${host_vendor}-${host_os}-gcc + + AC_MSG_RESULT($CC) +fi + +CFLAGS="$CFLAGS -D_GNU_SOURCE" + + +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_DISABLE_STATIC +AC_LIBTOOL_DLOPEN +AM_PROG_LIBTOOL + +CC_NOUNDEFINED + +dnl Checks for header files. +AC_HEADER_STDC +AM_CONFIG_HEADER(include/config.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_HEADER_TIME + +dnl Checks for library functions. +AC_PROG_GCC_TRADITIONAL +AC_CHECK_FUNC([hsearch_r], [HAVE_HSEARCH_R=yes]) +AM_CONDITIONAL(ALSA_HSEARCH_R, [test "x$HAVE_HSEARCH_R" != xyes]) +AC_CHECK_FUNCS([uselocale]) + +SAVE_LIBRARY_VERSION +AC_SUBST(LIBTOOL_VERSION_INFO) + +test "x$prefix" = xNONE && prefix=$ac_default_prefix + +dnl ALSA configuration directory +AC_ARG_WITH(configdir, + AS_HELP_STRING([--with-configdir=dir], + [path where ALSA config files are stored]), + confdir="$withval", confdir="") +if test -z "$confdir"; then + eval dir="$datadir" + case "$dir" in + /*) ;; + *) dir="$prefix/share" + esac + confdir="$dir/alsa" +fi +ALSA_CONFIG_DIR="$confdir" +AC_DEFINE_UNQUOTED(ALSA_CONFIG_DIR, "$confdir", [directory containing ALSA configuration database]) +AC_SUBST(ALSA_CONFIG_DIR) + +dnl ALSA plugin directory +test "x$exec_prefix" = xNONE && exec_prefix=$prefix + +AC_ARG_WITH(plugindir, + AS_HELP_STRING([--with-plugindir=dir], + [path where ALSA plugin files are stored]), + plugindir="$withval", plugindir="") +if test -z "$plugindir"; then + eval dir="$libdir" + case "$dir" in + /*) ;; + *) dir="$dir" + esac + plugindir="$dir/$PACKAGE" +fi +AC_DEFINE_UNQUOTED(ALSA_PLUGIN_DIR, "$plugindir", [directory containing ALSA add-on modules]) +ALSA_PLUGIN_DIR="$plugindir" +AC_SUBST(ALSA_PLUGIN_DIR) + +dnl Check for versioned symbols +AC_MSG_CHECKING(for versioned symbols) +AC_ARG_WITH(versioned, + AS_HELP_STRING([--with-versioned], + [shared library will be compiled with versioned symbols (default = yes)]), + versioned="$withval", versioned="yes") +if test "$versioned" = "yes"; then + # it seems that GNU ld versions since 2.10 are not broken + xres=`grep '^VERSION=' ${srcdir}/ltmain.sh | cut -d = -f 2 | cut -d \" -f 2` + major=`echo $xres | cut -d . -f 1` + minor=`echo $xres | cut -d . -f 2` + pass=0 + if test $major -eq 1 && test $minor -gt 3; then + pass=1 + else + if test $major -gt 1; then + pass=1 + fi + fi + if test $pass -eq 1; then + AC_DEFINE(VERSIONED_SYMBOLS,,[compiled with versioned symbols]) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(broken libtool - use libtool v1.4+; no versions) + fi +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(VERSIONED_SYMBOLS, test x$versioned = xyes) + +dnl Check for symbolic-functions +AC_MSG_CHECKING(for symbolic-functions) +AC_ARG_ENABLE(symbolic-functions, + AS_HELP_STRING([--enable-symbolic-functions], + [use -Bsymbolic-functions option if available (optmization for size and speed)]), + symfuncs="$enableval", symfuncs="no") +if test "$symfuncs" = "yes"; then + if ld --help | grep -q -- '-Bsymbolic-functions'; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(not supported by ld) + symfuncs="no" + fi +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(SYMBOLIC_FUNCTIONS, test x"$symfuncs" = xyes) + +dnl See if toolchain has a custom prefix for symbols ... +AC_MSG_CHECKING(for custom symbol prefixes) +SYMBOL_PREFIX=` \ + echo "PREFIX=__USER_LABEL_PREFIX__" \ + | ${CPP-${CC-gcc} -E} - 2>&1 \ + | ${EGREP-grep} "^PREFIX=" \ + | ${SED-sed} "s:^PREFIX=::"` +AC_DEFINE_UNQUOTED([__SYMBOL_PREFIX], "$SYMBOL_PREFIX", [Toolchain Symbol Prefix]) +AC_SUBST(SYMBOL_PREFIX) +AC_MSG_RESULT($SYMBOL_PREFIX) + +dnl Check for debug... +AC_MSG_CHECKING(for debug) +AC_ARG_WITH(debug, + AS_HELP_STRING([--with-debug], + [library will be compiled with asserts (default = yes)]), + debug="$withval", debug="yes") +if test "$debug" = "yes"; then + AC_MSG_RESULT(yes) +else + AC_DEFINE(NDEBUG,,[No assert debug]) + AC_MSG_RESULT(no) +fi + +if test "$debug" = "yes"; then + AC_MSG_CHECKING(for debug assert) + AC_ARG_ENABLE(debug-assert, + AS_HELP_STRING([--enable-debug], + [enable assert call at the default error message handler]), + debug_assert="$enableval", debug_assert="no") + if test "$debug_assert" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(ALSA_DEBUG_ASSERT,,[Enable assert at error message handler]) + else + AC_MSG_RESULT(no) + fi +fi + +dnl Temporary directory +AC_MSG_CHECKING(for tmpdir) +AC_ARG_WITH(tmpdir, + AS_HELP_STRING([--with-tmpdir=directory], + [directory to put tmp socket files (/tmp)]), + tmpdir="$withval", tmpdir="/tmp") +AC_MSG_RESULT($tmpdir) +AC_DEFINE_UNQUOTED(TMPDIR, "$tmpdir", [directory to put tmp socket files]) + +dnl Check for softfloat... +AC_MSG_CHECKING(for softfloat) +AC_ARG_WITH(softfloat, + AS_HELP_STRING([--with-softfloat], + [do you have floating point unit on this machine? (optional)]), + [case "$withval" in + y|yes) softfloat=yes ;; + *) softfloat=no ;; + esac],) +if test "$softfloat" = "yes" ; then + AC_DEFINE(HAVE_SOFT_FLOAT, "1", [Avoid calculation in float]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +ALSA_DEPLIBS="" +if test "$softfloat" != "yes"; then + ALSA_DEPLIBS="-lm" +fi + +dnl Check for libdl +AC_MSG_CHECKING(for libdl) +AC_ARG_WITH(libdl, + AS_HELP_STRING([--with-libdl], [Use libdl for plugins (default = yes)]), + [ have_libdl="$withval" ], [ have_libdl="yes" ]) +if test "$have_libdl" = "yes"; then + AC_CHECK_LIB([dl], [dlsym], [HAVE_LIBDL="yes"]) + if test "$HAVE_LIBDL" = "yes" ; then + ALSA_DEPLIBS="$ALSA_DEPLIBS -ldl" + AC_DEFINE([HAVE_LIBDL], 1, [Have libdl]) + fi +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(BUILD_MODULES, test "$HAVE_LIBDL"="yes") + +dnl Check for pthread +AC_MSG_CHECKING(for pthread) +AC_ARG_WITH(pthread, + AS_HELP_STRING([--with-pthread], [Use pthread (default = yes)]), + [ have_pthread="$withval" ], [ have_pthread="yes" ]) +if test "$have_pthread" = "yes"; then + AC_CHECK_LIB([pthread], [pthread_join], [HAVE_LIBPTHREAD="yes"]) + if test "$HAVE_LIBPTHREAD" = "yes"; then + ALSA_DEPLIBS="$ALSA_DEPLIBS -lpthread" + AC_DEFINE([HAVE_LIBPTHREAD], 1, [Have libpthread]) + fi +else + AC_MSG_RESULT(no) +fi + +dnl Check for librt +AC_MSG_CHECKING(for librt) +AC_ARG_WITH(librt, + AS_HELP_STRING([--with-librt], [Use librt for monotonic clock (default = yes)]), + [ have_librt="$withval" ], [ have_librt="yes" ]) +if test "$have_librt" = "yes"; then + AC_CHECK_LIB([rt], [clock_gettime], [HAVE_LIBRT="yes"]) + if test "$HAVE_LIBRT" = "yes" ; then + ALSA_DEPLIBS="$ALSA_DEPLIBS -lrt" + AC_DEFINE([HAVE_LIBRT], 1, [Have librt]) + AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [Have clock gettime]) + fi +else + AC_MSG_RESULT(no) +fi + +AC_SUBST(ALSA_DEPLIBS) + +dnl Check for architecture +AC_MSG_CHECKING(for architecture) +case "$host" in +i?86*) + AC_MSG_RESULT(x86) + ;; +x86_64*) + AC_MSG_RESULT(x86) + ;; +alpha*) + AC_MSG_RESULT(alpha) + ;; +powerpc*|ppc*) + AC_MSG_RESULT(ppc) + CPPFLAGS="$CPPFLAGS -D__ppc__" + ;; +ia64*) + AC_MSG_RESULT(ia64) + CPPFLAGS="$CPPFLAGS -D__ia64__" + ;; +mips*) + AC_MSG_RESULT(mips) + CPPFLAGS="$CPPFLAGS -D__mips__" + ;; +arm*) + AC_MSG_RESULT(arm) + CPPFLAGS="$CPPFLAGS -D__arm__" + ;; +*) + AC_MSG_RESULT($host_cpu) + echo "No atomic operations supported.." + ;; +esac + +dnl Check for wordexp.h +AC_CHECK_HEADERS([wordexp.h]) + +dnl Check for resmgr support... +AC_MSG_CHECKING(for resmgr support) +AC_ARG_ENABLE(resmgr, + AS_HELP_STRING([--enable-resmgr], [support resmgr (optional)]), + resmgr="$enableval", resmgr="no") +AC_MSG_RESULT($resmgr) +if test "$resmgr" = "yes"; then + AC_CHECK_LIB(resmgr, rsm_open_device,, + AC_ERROR([Cannot find libresmgr])) + AC_DEFINE(SUPPORT_RESMGR, "1", [Support resmgr with alsa-lib]) +fi + +dnl Check for aload* support... +AC_MSG_CHECKING(for aload* support) +AC_ARG_ENABLE(aload, + AS_HELP_STRING([--disable-aload], [disable reading /dev/aload*]), + aload="$enableval", aload="yes") +AC_MSG_RESULT($aload) +if test "$aload" = "yes"; then + AC_DEFINE(SUPPORT_ALOAD, "1", [Support /dev/aload* access for auto-loading]) +fi + +dnl Check for non-standard /dev directory +AC_MSG_CHECKING([for ALSA device file directory]) +AC_ARG_WITH(alsa-devdir, + AS_HELP_STRING([--with-alsa-devdir=dir], + [directory with ALSA device files (default /dev/snd)]), + [alsa_dev_dir="$withval"], + [alsa_dev_dir="/dev/snd"]) +dnl make sure it has a trailing slash +if echo "$alsa_dev_dir" | grep -v '/$' > /dev/null; then + alsa_dev_dir="$alsa_dev_dir/" +fi +AC_DEFINE_UNQUOTED(ALSA_DEVICE_DIRECTORY, "$alsa_dev_dir", [Directory with ALSA device files]) +AC_MSG_RESULT([$alsa_dev_dir]) + +AC_MSG_CHECKING([for aload* device file directory]) +AC_ARG_WITH(aload-devdir, + AS_HELP_STRING([--with-aload-devdir=dir], + [directory with aload* device files (default /dev)]), + [aload_dev_dir="$withval"], + [aload_dev_dir="/dev"]) +if echo "$aload_dev_dir" | grep -v '/$' > /dev/null; then + aload_dev_dir="$aload_dev_dir/" +fi +AC_DEFINE_UNQUOTED(ALOAD_DEVICE_DIRECTORY, "$aload_dev_dir", [Directory with aload* device files]) +AC_MSG_RESULT([$aload_dev_dir]) + +dnl Build conditions +AC_ARG_ENABLE(mixer, + AS_HELP_STRING([--disable-mixer], [disable the mixer component]), + [build_mixer="$enableval"], [build_mixer="yes"]) +AC_ARG_ENABLE(pcm, + AS_HELP_STRING([--disable-pcm], [disable the PCM component]), + [build_pcm="$enableval"], [build_pcm="yes"]) +AC_ARG_ENABLE(rawmidi, + AS_HELP_STRING([--disable-rawmidi], [disable the raw MIDI component]), + [build_rawmidi="$enableval"], [build_rawmidi="yes"]) +AC_ARG_ENABLE(hwdep, + AS_HELP_STRING([--disable-hwdep], [disable the hwdep component]), + [build_hwdep="$enableval"], [build_hwdep="yes"]) +AC_ARG_ENABLE(seq, + AS_HELP_STRING([--disable-seq], [disable the sequencer component]), + [build_seq="$enableval"], [build_seq="yes"]) +AC_ARG_ENABLE(ucm, + AS_HELP_STRING([--disable-ucm], [disable the use-case-manager component]), + [build_ucm="$enableval"], [build_ucm="yes"]) +AC_ARG_ENABLE(alisp, + AS_HELP_STRING([--disable-alisp], [disable the alisp component]), + [build_alisp="$enableval"], [build_alisp="yes"]) +test "$softfloat" = "yes" && build_alisp="no" +AC_ARG_ENABLE(old-symbols, + AS_HELP_STRING([--disable-old-symbols], [disable old obsoleted symbols]), + [keep_old_symbols="$enableval"], [keep_old_symbols="yes"]) +AM_CONDITIONAL(KEEP_OLD_SYMBOLS, test x$keep_old_symbols = xyes) + +AC_ARG_ENABLE(python, + AS_HELP_STRING([--disable-python], [disable the python components]), + [build_python="$enableval"], [build_python="yes"]) +PYTHON_LIBS="" +PYTHON_INCLUDES="" +if test "$build_python" = "yes"; then + AC_ARG_WITH(pythonlibs, + AS_HELP_STRING([--with-pythonlibs=ldflags], + [specify python libraries (-lpthread -lm -ldl -lpython2.4)]), + pythonlibs="$withval", pythonlibs=`python-config --libs`) + AC_ARG_WITH(pythonincludes, + AS_HELP_STRING([--with-pythonincludes=Cflags], + [specify python C header files (-I/usr/include/python)]), + pythonincludes="$withval", pythonincludes=`python-config --includes`) + if test -z "$pythonlibs"; then + echo "Unable to determine python libraries! Probably python-config is not" + echo "available on this system. Please, use --with-pythonlibs and" + echo "--with-pythonincludes options. Python components are disabled in this build." + build_python="no" + else + PYTHON_LIBS="$pythonlibs" + PYTHON_INCLUDES="$pythonincludes" + fi +fi +AC_SUBST(PYTHON_LIBS) +AC_SUBST(PYTHON_INCLUDES) + +AM_CONDITIONAL(BUILD_MIXER, test x$build_mixer = xyes) +AM_CONDITIONAL(BUILD_PCM, test x$build_pcm = xyes) +AM_CONDITIONAL(BUILD_RAWMIDI, test x$build_rawmidi = xyes) +AM_CONDITIONAL(BUILD_HWDEP, test x$build_hwdep = xyes) +AM_CONDITIONAL(BUILD_SEQ, test x$build_seq = xyes) +AM_CONDITIONAL(BUILD_UCM, test x$build_ucm = xyes) +AM_CONDITIONAL(BUILD_ALISP, test x$build_alisp = xyes) +AM_CONDITIONAL(BUILD_PYTHON, test x$build_python = xyes) + +if test "$build_mixer" = "yes"; then + AC_DEFINE([BUILD_MIXER], "1", [Build mixer component]) +fi +if test "$build_pcm" = "yes"; then + AC_DEFINE([BUILD_PCM], "1", [Build PCM component]) +fi +if test "$build_rawmidi" = "yes"; then + AC_DEFINE([BUILD_RAWMIDI], "1", [Build raw MIDI component]) +fi +if test "$build_hwdep" = "yes"; then + AC_DEFINE([BUILD_HWDEP], "1", [Build hwdep component]) +fi +if test "$build_seq" = "yes"; then + AC_DEFINE([BUILD_SEQ], "1", [Build sequencer component]) +fi +if test "$build_ucm" = "yes"; then + AC_DEFINE([BUILD_UCM], "1", [Build UCM component]) +fi + +dnl PCM Plugins + +if test "$build_pcm" = "yes"; then +AC_ARG_WITH(pcm-plugins, + AS_HELP_STRING([--with-pcm-plugins=], + [build PCM plugins (default = all)]), + [pcm_plugins="$withval"], [pcm_plugins="all"]) +else +pcm_plugins="" +fi + +PCM_PLUGIN_LIST="copy linear route mulaw alaw adpcm rate plug multi shm file null empty share meter hooks lfloat ladspa dmix dshare dsnoop asym iec958 softvol extplug ioplug mmap_emul" + +build_pcm_plugin="no" +for t in $PCM_PLUGIN_LIST; do + eval build_pcm_$t="no" +done + +pcm_plugins=`echo $pcm_plugins | sed 's/,/ /g'` +for p in $pcm_plugins; do + for t in $PCM_PLUGIN_LIST; do + if test "$p" = "$t" -o "$p" = "all"; then + eval build_pcm_$t="yes" + build_pcm_plugin="yes" + fi + done +done + +dnl special dependencies +if test "$build_pcm_plug" = "yes"; then + build_pcm_linear="yes" + build_pcm_copy="yes" +fi + +if test "$build_pcm_ioplug" = "yes"; then + build_pcm_extplug="yes" +fi + +if test "$HAVE_LIBDL" != "yes"; then + build_pcm_meter="no" + build_pcm_ladspa="no" + build_pcm_pcm_ioplug="no" + build_pcm_pcm_extplug="no" +fi + +if test "$HAVE_LIBPTHREAD" != "yes"; then + build_pcm_share="no" +fi + +if test "$softfloat" = "yes"; then + build_pcm_lfloat="no" + build_pcm_ladspa="no" +fi + +AM_CONDITIONAL(BUILD_PCM_PLUGIN, test x$build_pcm_plugin = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_COPY, test x$build_pcm_copy = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_LINEAR, test x$build_pcm_linear = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_ROUTE, test x$build_pcm_route = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_MULAW, test x$build_pcm_mulaw = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_ALAW, test x$build_pcm_alaw = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_ADPCM, test x$build_pcm_adpcm = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_RATE, test x$build_pcm_rate = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_PLUG, test x$build_pcm_plug = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_MULTI, test x$build_pcm_multi = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_SHM, test x$build_pcm_shm = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_FILE, test x$build_pcm_file = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_NULL, test x$build_pcm_null = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_EMPTY, test x$build_pcm_empty = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_SHARE, test x$build_pcm_share = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_METER, test x$build_pcm_meter = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_HOOKS, test x$build_pcm_hooks = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_LFLOAT, test x$build_pcm_lfloat = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_LADSPA, test x$build_pcm_ladspa = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_DMIX, test x$build_pcm_dmix = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_DSHARE, test x$build_pcm_dshare = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_DSNOOP, test x$build_pcm_dsnoop = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_ASYM, test x$build_pcm_asym = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_IEC958, test x$build_pcm_iec958 = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_SOFTVOL, test x$build_pcm_softvol = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_EXTPLUG, test x$build_pcm_extplug = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_IOPLUG, test x$build_pcm_ioplug = xyes) +AM_CONDITIONAL(BUILD_PCM_PLUGIN_MMAP_EMUL, test x$build_pcm_mmap_emul = xyes) + +dnl Defines for plug plugin +if test "$build_pcm_rate" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_RATE], "1", [Build PCM rate plugin]) +fi +if test "$build_pcm_route" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_ROUTE], "1", [Build PCM route plugin]) +fi +if test "$build_pcm_lfloat" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_LFLOAT], "1", [Build PCM lfloat plugin]) +fi +if test "$build_pcm_adpcm" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_ADPCM], "1", [Build PCM adpcm plugin]) +fi +if test "$build_pcm_mulaw" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_MULAW], "1", [Build PCM mulaw plugin]) +fi +if test "$build_pcm_alaw" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_ALAW], "1", [Build PCM alaw plugin]) +fi +if test "$build_pcm_mmap_emul" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_MMAP_EMUL], "1", [Build PCM mmap-emul plugin]) +fi + + +dnl Create PCM plugin symbol list for static library +rm -f "$srcdir"/src/pcm/pcm_symbols_list.c +touch "$srcdir"/src/pcm/pcm_symbols_list.c +for t in $PCM_PLUGIN_LIST; do + if eval test \$build_pcm_$t = yes; then + echo \&_snd_module_pcm_$t, >> "$srcdir"/src/pcm/pcm_symbols_list.c + fi +done + +dnl Control Plugins + +AC_ARG_WITH(ctl-plugins, + AS_HELP_STRING([--with-ctl-plugins=], + [build control plugins (default = all)]), + [ctl_plugins="$withval"], [ctl_plugins="all"]) + +CTL_PLUGIN_LIST="shm ext" + +build_ctl_plugin="no" +for t in $CTL_PLUGIN_LIST; do + eval build_ctl_$t="no" +done + +ctl_plugins=`echo $ctl_plugins | sed 's/,/ /g'` +for p in $ctl_plugins; do + for t in $CTL_PLUGIN_LIST; do + if test "$p" = "$t" -o "$p" = "all"; then + eval build_ctl_$t="yes" + build_ctl_plugin="yes" + fi + done +done + +AM_CONDITIONAL(BUILD_CTL_PLUGIN, test x$build_ctl_plugin = xyes) +AM_CONDITIONAL(BUILD_CTL_PLUGIN_SHM, test x$build_ctl_shm = xyes) +AM_CONDITIONAL(BUILD_CTL_PLUGIN_EXT, test x$build_ctl_ext = xyes) + +dnl Create ctl plugin symbol list for static library +rm -f "$srcdir"/src/control/ctl_symbols_list.c +touch "$srcdir"/src/control/ctl_symbols_list.c +for t in $CTL_PLUGIN_LIST; do + if eval test \$build_ctl_$t = yes; then + echo \&_snd_module_control_$t, >> "$srcdir"/src/control/ctl_symbols_list.c + fi +done + +dnl Make a symlink for inclusion of alsa/xxx.h +if test ! -L "$srcdir"/include/alsa ; then + echo "Making a symlink include/alsa" + rm -f "$srcdir"/include/alsa + ln -sf . "$srcdir"/include/alsa +fi + +AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \ + include/Makefile include/sound/Makefile src/Versions src/Makefile \ + src/control/Makefile src/mixer/Makefile \ + src/pcm/Makefile src/pcm/scopes/Makefile \ + src/rawmidi/Makefile src/timer/Makefile \ + src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \ + src/compat/Makefile src/alisp/Makefile src/conf/Makefile \ + src/conf/cards/Makefile \ + src/conf/pcm/Makefile \ + modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \ + alsalisp/Makefile aserver/Makefile \ + test/Makefile test/lsb/Makefile \ + utils/Makefile utils/alsa-lib.spec utils/alsa.pc) + +dnl Create asoundlib.h dynamically according to configure options +echo "Creating asoundlib.h..." +cp "$srcdir"/include/asoundlib-head.h include/asoundlib.h +test "$build_pcm" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_rawmidi" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_pcm" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_hwdep" = "yes" && echo "#include " >> include/asoundlib.h +echo "#include " >> include/asoundlib.h +test "$build_mixer" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +test "$build_seq" = "yes" && echo "#include " >> include/asoundlib.h +cat "$srcdir"/include/asoundlib-tail.h >> include/asoundlib.h + diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..0a1c7f0 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,111 @@ +alsa-lib (1.0.24.1-0) unstable; urgency=low + + * Version upgrade from 1.0.21a to 1.0.24.1 + * Git: pkgs/a/alsa-lib + * Tag: alsa-lib_1.0.24.1-0 + + -- Seungbae Shin Tue, 03 Jan 2012 14:17:44 +0900 + +alsa-lib (1.0.21a-11slp3) unstable; urgency=low + + * update debian/copyright + * Git: 165.213.180.234:slp/pkgs/a/alsa-lib + * Tag: alsa-lib_1.0.21a-11slp3 + + -- Seungbae Shin Thu, 06 Jan 2011 18:04:43 +0900 + +alsa-lib (1.0.21a-11slp2) unstable; urgency=low + + * complie/link optimize option applied. + * Git: 165.213.180.234:/git/slp/pkgs/alsa-lib + * Tag: alsa-lib_1.0.21a-11slp2 + + -- KwangHui Cho Thu, 18 Nov 2010 10:01:25 +0900 + +alsa-lib (1.0.21a-10slp4) unstable; urgency=low + + * Add sdk-dev + * Git: 165.213.180.234:/git/slp/pkgs/alsa-lib + * Tag: alsa-lib_1.0.21a-10slp4 + + -- Seungbae Shin Thu, 15 Jul 2010 19:46:07 +0900 + +alsa-lib (1.0.21a-10slp3) unstable; urgency=low + + * Change maintainer + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/alsa-lib-1.0.21a + * Tag: alsa-lib_1.0.21a-10slp3 + + -- Seungbae Shin Thu, 08 Jul 2010 14:53:10 +0900 + +alsa-lib (1.0.21a-10slp2) unstable; urgency=low + + * remove --with-soft-flaot option which causes sqrt() error + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/alsa-lib-1.0.21a + * Tag: alsa-lib_1.0.21a-10slp2 + + -- KwangHui Cho Thu, 08 Apr 2010 19:26:47 +0900 + +alsa-lib (1.0.21a-9slp2) unstable; urgency=low + + * fix control file + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/alsa-lib-1.0.21a + * Tag: alsa-lib_1.0.21a-9slp2 + + -- KwangHui Cho Thu, 08 Apr 2010 15:29:46 +0900 + +alsa-lib (1.0.21a-8slp2) unstable; urgency=low + + * change configure option & add debug package + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/alsa-lib-1.0.21a + * Tag: alsa-lib_1.0.21a-8slp2 + + -- KwangHui Cho Thu, 08 Apr 2010 13:46:08 +0900 + +alsa-lib (1.0.21a-7slp2) unstable; urgency=low + + * Change package naming rule + + -- Seungbae Shin Thu, 25 Mar 2010 14:51:33 +0900 + +alsa-lib (1.0.21a-7) unstable; urgency=low + + * changed sound device path in rules file + + -- Yunchan Cho Thu, 26 Nov 2009 18:41:50 +0900 + +alsa-lib (1.0.21a-6) unstable; urgency=low + + * remove .git directory + + -- Yunchan Cho Fri, 20 Nov 2009 16:15:51 +0900 + +alsa-lib (1.0.21a-5) unstable; urgency=low + + * update debianize + + -- Yunchan Cho Thu, 19 Nov 2009 17:06:53 +0900 + +alsa-lib (1.0.21a-4) unstable; urgency=low + + * enable dh_mkshlibs in rule file + + -- Yunchan Cho Mon, 16 Nov 2009 19:21:50 +0900 + +alsa-lib (1.0.21a-3) unstable; urgency=low + + * change rules and control file. + + -- Yunchan Cho Fri, 13 Nov 2009 13:56:18 +0900 + +alsa-lib (1.0.21a-2) unstable; urgency=low + + * change toolchain + + -- Sangho Park Wed, 11 Nov 2009 15:10:04 +0900 + +alsa-lib (1.0.21a-1) unstable; urgency=low + + * Initial release. + + -- Jongwoo Chae Tue, 30 Jun 2009 13:09:04 +0900 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..12f9a9b --- /dev/null +++ b/debian/control @@ -0,0 +1,37 @@ +Source: alsa-lib +Priority: extra +Maintainer: Seungbae Shin , JongHyuk Choi +Uploaders: Seungbae Shin +Build-Depends: debhelper (>= 5), autotools-dev +Standards-Version: 3.7.2 +Section: libs + +Package: libasound2-dev +XB-Public-Package: no +Section: libdevel +Architecture: any +Depends: libasound2 (= ${Source-Version}), libasound2-sdk-dev +Description: ALSA Library package for multimedia framework middleware package + ALSA Library package for multimedia framework middleware package + +Package: libasound2-sdk-dev +Section: libdevel +Architecture: any +Depends: libasound2 (= ${Source-Version}) +Description: ALSA Library package for multimedia framework middleware package + ALSA Library package for multimedia framework middleware package + + +Package: libasound2 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: ALSA Library package for multimedia framework middleware package + ALSA Library package for multimedia framework middleware package + +Package: libasound2-dbg +Section: debug +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libasound2(= ${Source-Version}) +Description: ALSA Library package for multimedia framework middleware package + ALSA Library package for multimedia framework middleware package (unstripped) diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..baf369a --- /dev/null +++ b/debian/copyright @@ -0,0 +1,30 @@ +Bugs in the source code (as opposed to bugs in the packaging) are best +reported to the upstream bug tracking system: + + https://bugtrack.alsa-project.org/alsa-bug + +The source code was downloaded from the ALSA homepage: + + http://alsa.sourceforge.net + +alsa-lib +-------- +Copyright (c) 1998 Jarsolav Kysela and others. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301, USA. + +On Debian systems, the complete text of the GNU Lesser General Public License +can be found in /usr/share/common-licenses/LGPL. diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..ca882bb --- /dev/null +++ b/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..1333ed7 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +TODO diff --git a/debian/libasound2-dev.dirs b/debian/libasound2-dev.dirs new file mode 100644 index 0000000..995e528 --- /dev/null +++ b/debian/libasound2-dev.dirs @@ -0,0 +1,3 @@ +usr/lib +usr/include +usr/share diff --git a/debian/libasound2-dev.install.in b/debian/libasound2-dev.install.in new file mode 100644 index 0000000..f7721bc --- /dev/null +++ b/debian/libasound2-dev.install.in @@ -0,0 +1 @@ +@PREFIX@/include/* diff --git a/debian/libasound2-sdk-dev.install.in b/debian/libasound2-sdk-dev.install.in new file mode 100644 index 0000000..bfb512d --- /dev/null +++ b/debian/libasound2-sdk-dev.install.in @@ -0,0 +1,4 @@ +@PREFIX@/lib/pkgconfig/* +@PREFIX@/lib/*.la +@PREFIX@/share/aclocal +@PREFIX@/lib/alsa-lib/smixer/*.la diff --git a/debian/libasound2.dirs b/debian/libasound2.dirs new file mode 100644 index 0000000..5e8ff3e --- /dev/null +++ b/debian/libasound2.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/share/alsa diff --git a/debian/libasound2.install.in b/debian/libasound2.install.in new file mode 100644 index 0000000..d945d26 --- /dev/null +++ b/debian/libasound2.install.in @@ -0,0 +1,4 @@ +@PREFIX@/lib/lib*.so +@PREFIX@/lib/lib*.so.* +@PREFIX@/lib/alsa-lib/smixer/*.so +@PREFIX@/share/alsa/* diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..4d61ecf --- /dev/null +++ b/debian/rules @@ -0,0 +1,140 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +CU= "$(shell sb-conf cu)" + +CFLAGS ?= -Wall -g +LDFLAGS ?= +PREFIX ?= /usr +DATADIR ?= /opt + +CFLAGS += -fPIC + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +LDFLAGS+= -Wl,--warn-unresolved-symbols -Wl,--hash-style=both -Wl,--as-needed + +ifneq (,$(findstring arm, $(CU))) + OPTIONS= --with-alsa-devdir=/dev/snd --disable-alisp --disable-seq --disable-rawmidi --disable-python --with-gnu-ld --with-pcm-plugins=rate,linear,plug,dmix,dsnoop,asym,mmap +else + OPTIONS= +endif + + + +# shared library versions, option 1 +version=2.0.5 +major=2 +# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so +#version=`ls src/.libs/lib*.so.* | \ +# awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` +#major=`ls src/.libs/lib*.so.* | \ +# awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` + +config.status: configure + dh_testdir + # Add here commands to configure the package. + ./autogen.sh + CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --prefix=$(PREFIX) $(OPTIONS) + +build: build-stamp +build-stamp: config.status + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + + for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ + cat $$f > $${f%.in}; \ + sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \ + sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \ + done + + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) distclean + +ifneq "$(wildcard /usr/share/misc/config.sub)" "" + cp -f /usr/share/misc/config.sub config.sub +endif +ifneq "$(wildcard /usr/share/misc/config.guess)" "" + cp -f /usr/share/misc/config.guess config.guess +endif + + for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ + rm -f $${f%.in}; \ + done + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/tmp + $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs ChangeLog + dh_installdocs + dh_installexamples + dh_install --sourcedir=debian/tmp +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo +# dh_installman + dh_link + dh_strip --dbg-package=libasound2-dbg + dh_compress + dh_fixperms +# dh_perl +# dh_python + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/depcomp b/depcomp new file mode 100755 index 0000000..df8eea7 --- /dev/null +++ b/depcomp @@ -0,0 +1,630 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free +# Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u="sed s,\\\\\\\\,/,g" + depmode=msvisualcpp +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..2cc250b --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS=pictures + +EXTRA_DIST=README.1st asoundrc.txt doxygen.cfg index.doxygen + +INCLUDES=-I$(top_srcdir)/include + +doc: + test -e doxygen.cfg || sed s:[@]top_srcdir[@]:..:g doxygen.cfg.in > doxygen.cfg + doxygen doxygen.cfg + +doc-pack: doc + -chmod a+r $(top_srcdir)/doc/doxygen/html/* + -chmod a-w $(top_srcdir)/doc/doxygen/html/* + if ! test -z "$(AMTAR)"; then \ + $(AMTAR) --create --directory=$(top_srcdir)/doc/doxygen/html --verbose --file=- . | bzip2 -c -9 > $(top_srcdir)/../alsa-lib-doc.tar.bz2 ; \ + else \ + $(TAR) --create --directory=$(top_srcdir)/doc/doxygen/html --verbose --file=- . | bzip2 -c -9 > $(top_srcdir)/../alsa-lib-doc.tar.bz2 ; \ + fi + rm -f $(top_srcdir)/doc/doxygen/html/* + +doc-clean: + rm -f $(top_srcdir)/doc/doxygen/html/* diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..0197dd5 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,592 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = doc +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/doxygen.cfg.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = doxygen.cfg +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = pictures +EXTRA_DIST = README.1st asoundrc.txt doxygen.cfg index.doxygen +INCLUDES = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +doxygen.cfg: $(top_builddir)/config.status $(srcdir)/doxygen.cfg.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +doc: + test -e doxygen.cfg || sed s:[@]top_srcdir[@]:..:g doxygen.cfg.in > doxygen.cfg + doxygen doxygen.cfg + +doc-pack: doc + -chmod a+r $(top_srcdir)/doc/doxygen/html/* + -chmod a-w $(top_srcdir)/doc/doxygen/html/* + if ! test -z "$(AMTAR)"; then \ + $(AMTAR) --create --directory=$(top_srcdir)/doc/doxygen/html --verbose --file=- . | bzip2 -c -9 > $(top_srcdir)/../alsa-lib-doc.tar.bz2 ; \ + else \ + $(TAR) --create --directory=$(top_srcdir)/doc/doxygen/html --verbose --file=- . | bzip2 -c -9 > $(top_srcdir)/../alsa-lib-doc.tar.bz2 ; \ + fi + rm -f $(top_srcdir)/doc/doxygen/html/* + +doc-clean: + rm -f $(top_srcdir)/doc/doxygen/html/* + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/README.1st b/doc/README.1st new file mode 100644 index 0000000..f96b21c --- /dev/null +++ b/doc/README.1st @@ -0,0 +1,2 @@ +The doxygen documentation is created with command 'make doc' in toplevel +directory. diff --git a/doc/asoundrc.txt b/doc/asoundrc.txt new file mode 100644 index 0000000..f79d528 --- /dev/null +++ b/doc/asoundrc.txt @@ -0,0 +1,480 @@ +# Configuration file syntax + +# Include a new configuration file + + +# Simple assign +name [=] value [,|;] + +# Compound assign (first style) +name [=] { + name1 [=] value [,|;] + ... +} + +# Compound assign (second style) +name.name1 [=] value [,|;] + +# Array assign (first style) +name [ + value0 [,|;] + value1 [,|;] + ... +] + +# Array assign (second style) +name.0 [=] value0 [,|;] +name.1 [=] value1 [,|;] + +# ****************************************************************************** + +# Server definition +server.NAME { + host STR # host where the server is located (if map to local address + # server is local, and then it may be started automatically) + [socket STR] # PF_LOCAL socket name to listen/connect + [port INT] # PF_INET port number to listen/connect +} + +# PCM type definition +pcm_type.NAME { + [lib STR] # Library file (default libasound.so) + [open STR] # Open function (default _snd_pcm_NAME_open) + [redirect { # Redirect this PCM to an another + [filename STR] # Configuration file specification + name STR # PCM name specification + }] +} + +# PCM scope type definition +pcm_scope_type.NAME { + [lib STR] # Library file (default libasound.so) + [open STR] # Open function (default _snd_pcm_scope_NAME_open) +} + +# PCM scope definition +pcm_scope.NAME { + type STR # Scope type + ... +} + +# Slave PCM definition +pcm_slave.NAME { + pcm STR # PCM name + # or + pcm { } # PCM definition + format STR # Format + channels INT # Channels + rate INT # Rate + period_time INT # Period time + buffer_time INT # Buffer time + etc. +} + +# Hook arguments definition +hook_args.NAME { + ... # Arbitrary arguments +} + +# PCM hook type +pcm_hook_type.NAME { + [lib STR] # Library file (default libasound.so) + [install STR] # Install function (default _snd_pcm_hook_NAME_install) +} + +# PCM hook definition +pcm_hook.NAME { + type STR # PCM Hook type (see pcm_hook_type) + [args STR] # Arguments for install function (see hook_args) + # or + [args { }] # Arguments for install function +} + +# PCM definition +pcm.NAME { + type STR # Type + [comment ANY] # Saved comments + + +# PCM types: + type hw # Kernel PCM + card INT/STR # Card name or number + [device] INT # Device number (default 0) + [subdevice] INT # Subdevice number, -1 first available (default -1) + mmap_emulation BOOL # enable mmap emulation for ro/wo devices + + + type hooks # PCM with hooks + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + hooks { + ID STR # Hook name (see pcm_hook) + # or + ID { } # Hook definition (see pcm_hook) + } + + type plug # Format adjusted PCM + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format (default nearest) or "unchanged" + [channels INT] # Slave channels (default nearest) or "unchanged" + [rate INT] # Slave rate (default nearest) or "unchanged" + } + route_policy STR # route policy for automatic ttable generation + # STR can be 'default', 'average', 'copy', 'duplicate' + # average: result is average of input channels + # copy: only first channels are copied to destination + # duplicate: duplicate first set of channels + # default: copy policy, except for mono capture - sum + ttable { # Transfer table (bidimensional compound of + # cchannels * schannels numbers) + CCHANNEL { + SCHANNEL REAL # route value (0.0 ... 1.0) + } + } + + + type copy # Copy conversion PCM + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + + + type linear # Linear format conversion PCM + type adpcm # IMA-ADPCM format conversion PCM + type alaw # A-Law format conversion PCM + type mulaw # Mu-Law format conversion PCM + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + format STR # Slave format + } + + + type rate # Rate conversion PCM + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format (default client format) + rate INT # Slave rate + } + + + type route # Attenuated static route PCM + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format (default client format) + [channels INT] # Slave channels (default client channels) + } + ttable { # Transfer table (bidimensional compound of + # cchannels * schannels numbers) + CCHANNEL { + SCHANNEL REAL # route value (0.0 ... 1.0) + } + } + + + type multi # Linked PCMs (exclusive access to selected channels) + slaves { # Slaves definitions + ID STR # Slave name for slave N (see pcm_slave) + # or + ID { # Slave definition for slave N + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + channels INT # Slave channels + } + } + bindings { # Bindings table + N { # Binding for client channel N + slave STR # Slave key + channel INT # Slave channel + } + } + [master INT] # Define the master slave + + + type file # File plugin + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + file STR # File name + # or + file INT # File descriptor + [format STR] # File format (NYI) + [perm INT] # File permission (default 0600) + + type meter # Meter PCM + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition or name + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + [frequency INT] # Updates per second + scopes { # Scopes + ID STR # Scope name (see pcm_scope) + # or + ID { } # Scope definition (see pcm_scope) + } + + + type droute # Attenuated dynamic route PCM (NYI) + slave STR # Slave name (see pcm_slave) + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format (default client format) + [channels INT] # Slave channels (default client channels) + } + ctl STR # Ctl name + bindings { # Bindings table + ID { # Binding entry + cchannels { # Client channels + C INT # Client channel + } + schannel { # Slave channels + S INT # Slave channel + } + control STR # Control name of C * S (or C values: only if C == S) + } + } + + + type null # Null endpoint plugin + [time INT] # Time related or not (NYI) + + + type shm # Shared memory client PCM + server STR # Server name + pcm STR # PCM name on server + + + type share # Share PCM + slave STR # Slave name (see pcm_slave) + bindings { # Bindings table + N INT # Slave channel for client channel N + } + + + type mix # Mix PCM + slave STR # Slave name (see pcm_slave) + bindings { # Bindings table + N INT # Slave channel for client channel N + } + + + type ladspa # LADSPA plugin PCM + slave STR # Slave name (see pcm_slave) + path STR # Path or paths (delimited with ':') + plugins | playback_plugins | capture_plugins { + N { # Configuration for LADSPA plugin N + id # # LADSPA plugin ID (for example 1043) + label STR # LADSPA plugin label (for example 'delay_5s') + filename STR # Full filename of .so library with LADPA plugin code + policy STR # Policy can be 'none' or 'duplicate' + input | output { + bindings { + C INT or STR # C - channel, INT - audio port index, STR - audio port name + } + controls { + I INT or REAL # I - control port index, INT or REAL - control value + } + } + } + } + + type dmix # Direct mixing plugin + slave STR # Slave name (see pcm_slave) + ipc_key INT # Unique ipc key + ipc_perm INT # ipc permissions (default 0600) + ipc_gid INT # ipc gid (default -1 = disable) + ipc_key_add_uid BOOL # Add current uid to ipc_key + bindings { # Bindings table + N INT # Slave channel for client channel N + } + + type dsnoop # Direct snoop (split one capture stream to more) + slave STR # Slave name (see pcm_slave) + ipc_key INT # Unique ipc key + ipc_perm INT # ipc permissions (default 0600) + ipc_gid INT # ipc gid (default -1 = disable) + ipc_key_add_uid BOOL # Add current uid to ipc_key + bindings { # Bindings table + N INT # Slave channel for client channel N + } + + type dshare # Share channels from one stream + slave STR # Slave name (see pcm_slave) + ipc_key INT # Unique ipc key + ipc_perm INT # ipc permissions (default 0600) + ipc_gid INT # ipc gid (default -1 = disable) + ipc_key_add_uid BOOL # Add current uid to ipc_key + bindings { # Bindings table + N INT # Slave channel for client channel N + } +} + +# CTL type definition +ctl_type.NAME { + [lib STR] # Library file (default libasound.so) + [open STR] # Open function (default _snd_ctl_NAME_open) +} + +# CTL definition +ctl.NAME { + type STR # Type + [comment ANY] # Saved comments + +# CTL types + type hw + card STR/INT # Card name or number + + + type shm # Shared memory client CTL + server STR # Server name + ctl STR # CTL name on server + + +} + + +# RAWMIDI type definition +rawmidi_type.NAME { + [lib STR] # Library file (default libasound.so) + [open STR] # Open function (default _snd_rawmidi_NAME_open) +} + +# RAWMIDI definition +rawmidi.NAME { + type STR # Type + [comment ANY] # Saved comments + +# RAWMIDI types: + type hw # Kernel RAWMIDI + card INT/STR # Card name or number + [device] INT # Device number (default 0) + [subdevice] INT # Subdevice number, -1 first available (default -1) + + +} + +# SEQ type definition +seq_type.NAME { + [lib STR] # Library file (default libasound.so) + [open STR] # Open function (default _snd_seq_NAME_open) +} + +# SEQ definition +seq.NAME { + type STR # Type + [comment ANY] # Saved comments + +# SEQ types: + type hw # Kernel SEQ + + +} + +# Aliases +DEF.NAME1 NAME2 # DEF.NAME1 is an alias for DEF.NAME2 + +Some examples: + +pcm.trident { + type hw + card 0 + device 0 +} + +pcm.ice1712 { + type hw + card 1 + device 0 +} + +pcm.ice1712_spdif { + type plug + ttable.0.8 1 + ttable.1.9 1 + slave.pcm ice1712 +} + +pcm_slave.rs { + pcm trident + rate 44100 +} + +pcm.r { + type rate + slave rs +} + +pcm.m { + type meter + slave.pcm plug:trident + frequency 50 + scopes [ + { + type level + } + ] +} + +pcm_scope_type.level { + lib /home/abramo/scopes/scope-level.so +} + +# an example command is 'aplay -D plug:ladspa ' +# otherwise, the ladspa plugin expects FLOAT type which +# is very rare +pcm.ladspa { + type ladspa + slave.pcm "plughw:0,0"; + path "/home/perex/src/ladspa_sdk/plugins"; + plugins [ + { + label delay_5s + input { + controls [ 0.8 0.2 ] + } + } + ] +} + +# an example command for dmix plugin to force 44100Hz mixing rate: +# aplay -D"plug:'dmix:RATE=44100'" +# an example command for dmix plugin to force 44100Hz and hw:1,0 output device +# aplay -Dplug:\'dmix:SLAVE=\"hw:1,0\",RATE=44100\' +# an example command for dmix plugin to force 32-bit signed little endian format +# aplay -D"plug:'dmix:FORMAT=S32_LE'" diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in new file mode 100644 index 0000000..f4499d6 --- /dev/null +++ b/doc/doxygen.cfg.in @@ -0,0 +1,123 @@ +PROJECT_NAME = "ALSA project - the C library reference" +OUTPUT_DIRECTORY = doxygen +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO + +CASE_SENSE_NAMES = NO +INPUT = @top_srcdir@/doc/index.doxygen \ + @top_srcdir@/include/asoundlib.h \ + @top_srcdir@/include/version.h \ + @top_srcdir@/include/global.h \ + @top_srcdir@/include/asoundef.h \ + @top_srcdir@/include/input.h \ + @top_srcdir@/include/output.h \ + @top_srcdir@/include/error.h \ + @top_srcdir@/include/conf.h \ + @top_srcdir@/include/control.h \ + @top_srcdir@/include/pcm.h \ + @top_srcdir@/include/rawmidi.h \ + @top_srcdir@/include/timer.h \ + @top_srcdir@/include/hwdep.h \ + @top_srcdir@/include/seq.h \ + @top_srcdir@/include/seq_event.h \ + @top_srcdir@/include/seqmid.h \ + @top_srcdir@/include/seq_midi_event.h \ + @top_srcdir@/include/pcm_external.h \ + @top_srcdir@/include/pcm_extplug.h \ + @top_srcdir@/include/pcm_ioplug.h \ + @top_srcdir@/include/control_external.h \ + @top_srcdir@/include/mixer.h \ + @top_srcdir@/include/use-case.h \ + @top_srcdir@/src/error.c \ + @top_srcdir@/src/dlmisc.c \ + @top_srcdir@/src/async.c \ + @top_srcdir@/src/input.c \ + @top_srcdir@/src/output.c \ + @top_srcdir@/src/conf.c \ + @top_srcdir@/src/confmisc.c \ + @top_srcdir@/src/names.c \ + @top_srcdir@/src/shmarea.c \ + @top_srcdir@/src/userfile.c \ + @top_srcdir@/src/control \ + @top_srcdir@/src/mixer \ + @top_srcdir@/src/pcm/pcm.c \ + @top_srcdir@/src/pcm/pcm_mmap.c \ + @top_srcdir@/src/pcm/pcm_plugin.c \ + @top_srcdir@/src/pcm/pcm_hw.c \ + @top_srcdir@/src/pcm/pcm_mmap_emul.c \ + @top_srcdir@/src/pcm/pcm_shm.c \ + @top_srcdir@/src/pcm/pcm_null.c \ + @top_srcdir@/src/pcm/pcm_copy.c \ + @top_srcdir@/src/pcm/pcm_linear.c \ + @top_srcdir@/src/pcm/pcm_lfloat.c \ + @top_srcdir@/src/pcm/pcm_mulaw.c \ + @top_srcdir@/src/pcm/pcm_alaw.c \ + @top_srcdir@/src/pcm/pcm_adpcm.c \ + @top_srcdir@/src/pcm/pcm_route.c \ + @top_srcdir@/src/pcm/pcm_rate.c \ + @top_srcdir@/src/pcm/pcm_plug.c \ + @top_srcdir@/src/pcm/pcm_file.c \ + @top_srcdir@/src/pcm/pcm_multi.c \ + @top_srcdir@/src/pcm/pcm_share.c \ + @top_srcdir@/src/pcm/pcm_hooks.c \ + @top_srcdir@/src/pcm/pcm_dmix.c \ + @top_srcdir@/src/pcm/pcm_dshare.c \ + @top_srcdir@/src/pcm/pcm_dsnoop.c \ + @top_srcdir@/src/pcm/pcm_meter.c \ + @top_srcdir@/src/pcm/pcm_ladspa.c \ + @top_srcdir@/src/pcm/pcm_asym.c \ + @top_srcdir@/src/pcm/pcm_iec958.c \ + @top_srcdir@/src/pcm/pcm_softvol.c \ + @top_srcdir@/src/pcm/pcm_extplug.c \ + @top_srcdir@/src/pcm/pcm_ioplug.c \ + @top_srcdir@/src/pcm/pcm_empty.c \ + @top_srcdir@/src/pcm/pcm_misc.c \ + @top_srcdir@/src/pcm/pcm_simple.c \ + @top_srcdir@/src/rawmidi \ + @top_srcdir@/src/timer \ + @top_srcdir@/src/hwdep \ + @top_srcdir@/src/seq \ + @top_srcdir@/src/ucm +EXCLUDE = @top_srcdir@/src/control/control_local.h \ + @top_srcdir@/src/pcm/atomic.h \ + @top_srcdir@/src/pcm/interval.h \ + @top_srcdir@/src/pcm/interval_inline.h \ + @top_srcdir@/src/pcm/mask.h \ + @top_srcdir@/src/pcm/mask_inline.h \ + @top_srcdir@/src/pcm/pcm_local.h \ + @top_srcdir@/src/pcm/pcm_meter.h \ + @top_srcdir@/src/pcm/pcm_plugin.h \ + @top_srcdir@/src/pcm/plugin_ops.h \ + @top_srcdir@/src/pcm/ladspa.h \ + @top_srcdir@/src/hwdep/hwdep_local.h \ + @top_srcdir@/src/mixer/mixer_local.h \ + @top_srcdir@/src/rawmidi/rawmidi_local.h \ + @top_srcdir@/src/seq/seq_local.h \ + @top_srcdir@/src/seq/ucm_local.h +RECURSIVE = YES +FILE_PATTERNS = *.c *.h +EXAMPLE_PATH = @top_srcdir@/test +IMAGE_PATH = pictures +QUIET = YES + +EXTRACT_ALL = NO +EXTRACT_STATIC = NO +SHOW_INCLUDE_FILES = NO +JAVADOC_AUTOBRIEF = NO +INHERIT_DOCS = YES +ENABLED_SECTIONS = "" +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +PREDEFINED = DOXYGEN PIC "DOC_HIDDEN" \ + "ATTRIBUTE_UNUSED=" \ + ALSA_PCM_NEW_HW_PARAMS_API \ + _POSIX_C_SOURCE \ + "use_default_symbol_version(x,y,z)=" \ + "link_warning(x,y)=" + +OPTIMIZE_OUTPUT_FOR_C = YES # doxygen 1.2.6 option +TYPEDEF_HIDES_STRUCT = YES # needed in doxygen >= 1.5.4 + +#INPUT_FILTER = inputfilter +#FILTER_SOURCE_FILES = YES diff --git a/doc/index.doxygen b/doc/index.doxygen new file mode 100644 index 0000000..f76cc10 --- /dev/null +++ b/doc/index.doxygen @@ -0,0 +1,54 @@ +/*! \page Index Preamble and License + +\author Jaroslav Kysela +\author Abramo Bagnara +\author Takashi Iwai +\author Frank van de Pol + +

Preface

+

The Advanced Linux Sound Architecture (\e ALSA) comes with a kernel +API and a library API. This document describes the library API and how +it interfaces with the kernel API.

+ +

Documentation License

+ +

This documentation is free; you can redistribute it without +any restrictions. Modifications or derived work must retain +the copyright and list all authors.

+ +

This documentation is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ +

API usage

+

Application programmers should use the library API rather than the +kernel API. The library offers 100% of the functionality of the kernel API, +but adds major improvements in usability, making the application code simpler +and better looking. In addition, future fixes or compatibility code +may be placed in the library code instead of the kernel driver.

+ +

API links

+ +
    +
  • Page \ref control explains the primitive controls API. +
  • Page \ref hcontrol explains the high-level primitive controls API. +
  • Page \ref mixer explains the mixer controls API. +
  • Page \ref pcm explains the design of the PCM (digital audio) API. +
  • Page \ref pcm_plugins explains the design of PCM (digital audio) plugins. +
  • Page \ref pcm_external_plugins explains the external PCM plugin SDK. +
  • Page \ref ctl_external_plugins explains the external control plugin SDK. +
  • Page \ref rawmidi explains the design of the RawMidi API. +
  • Page \ref timer explains the design of the Timer API. +
  • Page \ref seq explains the design of the Sequencer API. +
+ +

Configuration

+ +
    +
  • Page \ref conf explains the syntax of library configuration files. +
  • Page \ref confarg explains the run-time argument syntax. +
  • Page \ref conffunc explains run-time function definitions and their usage. +
  • Page \ref confhooks explains run-time hook definitions and their usage. +
+ +*/ diff --git a/doc/pictures/Makefile.am b/doc/pictures/Makefile.am new file mode 100644 index 0000000..17b6e12 --- /dev/null +++ b/doc/pictures/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST=wave1.gif wave2.gif diff --git a/doc/pictures/Makefile.in b/doc/pictures/Makefile.in new file mode 100644 index 0000000..5f0c4a0 --- /dev/null +++ b/doc/pictures/Makefile.in @@ -0,0 +1,368 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = doc/pictures +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = wave1.gif wave2.gif +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/pictures/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign doc/pictures/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/pictures/wave1.gif b/doc/pictures/wave1.gif new file mode 100644 index 0000000000000000000000000000000000000000..e465df8ab84f0f4b1fc825bfd6d1f4369fcc5e50 GIT binary patch literal 1715 zcmV;k22A-!Nk%w1VIl#o0OJ4v0001h0001h0Dyo1004l10Du61fPjF21Ox>91Oxy8 z&;M)j$~<` zXsWJkYhLi>&U9_xc&^iNKkdMva7Zk=d_JRc$!t1R$lh~Gty+Q6*mcY8dOum%cT6rb z!!oma&E}yi?YMj%dc*1XeA`aZ`~P2jKY)aVPl6JLii<>u7>tmSHja{&mQaY7nwxc* zoS&eSpre|iq^FUlsH=t&1qD&BgRHcGuCNrZxD&F8wZD3|6}rQ_z{hmLxxKu`$j@xb z&AZaj)@IVT)DO(p-htfP#LKha=2h9@;?C#ohvCKREq4w_4`5Ey8i&X@f+Ar zUBH9v2r9hc42RCcwP#t*d>fH!KrwXdg3KFsFJFFdwEm?R>mks=^$P#{ieQ1` z$5kFfo+8`Mwg3WlW7n-a*d79V zw-DRDgY?FY<*ZoG9DEZuvOBnr=F5vje?9$o_1gt!WBnY$Iga4hcYqK7oILp)mXMF2*)iXAw4b0);71_+oxH?%3Ud zKGp_gkQ;DzSA;kc>A{6K_IM%?Nh+CKjyWiX&uckK8JdP#N_b+IHd0w$mN*2)PLpAx zw_%rPviTvJJZ@MfNG8Jh;|grzsbz|L)~RGyT40B#ntFc6C!uS8*TSFdAyL|*O4^ww ze2~t^Vx*Tc)MyftPCCPjo&LAzd<7B-Dv^MSv16zterm(2L56Cot2Lx5gO9P=hbyj> z()uZ^wer_iHwhGL?6JrutL(DO{x<9Ev(QE>?X=WZYwfkzW*coo!zSb_hVY#l?zae* zI&Oj74$Ih=<@O4$yM>hrlki?G)NU7vwYMPa#@u;rzs;R=c;lR0-yN8_alUunjW*wfOP9EU z=6N9a$uR$YT5Y*4>9^(npIwgm<{Uh3l+C(n&bg?nO_w*)t&TRj+-1|9w4kGr##-s5 zSDt$8%lYOx-y6mlaX)Z@;Nm)7M{%y=Lpr3jeP2A1wfAJ^^lm zfcZ1vDG>NM1rE@C^mE`Z(nrAtN)Qzel1l+EmHMT&5(wn@SqfM_=y>K9P9OIab719w8 zbG&05@~FpX*s+g${39U!2(&@UQILkj1|kzl20k(p9EE&jAR{SBLUN>%le{D*Eop~M z?qQLhw1Oi>Ny<{1@|37dr7Bm+%2vAam9UJZEN4l}TH5lKxXh(4cgaf+&ITXglZ`L6 z*vn!X^O&ea-ZYjuL}n-xnb3@;GzAe%nfOB~!2IGgx5>?J3iF!=!KO2{>CJMQ6Pne; z$u*7iAab7bo$$nEI)B3zj+2b~45&a=$D&qVszwJ)MHke<~ECAiZcotvQa8{xhT~O(`=o%1o2uVxuaJDMm*M z(UQc(nljDlLTO6Tn?h8lK+PvlJxUFj2KA`$9BO}7`b?xc^_WV91Ox>9 z1Ox;G1qB5L1_lQQ2M7oV2?+@b3JMDg3k(bl4Gj$r4h|0w4-gO#z`(%&000300RR60 z009600RI60|NsC0A^8LW000;OEC2ui01N?_06+!*AR>-rX`X1Ru59bRa4gSsZQppV z?|kq7z@TtQEE5f($n3;DZoGDB*+@R%qdc7-p!USleZn5_aE# zH;ag7bl5~$blqiFAIudd*L1wO2wih8(m11x(!mHEi?QGsqmMgIlA?+?9>-cKL89`b zC`ryGTw_h@IMQuT8fhAmOJYeJlT}(t8<$;ziHJ+@>_g@|{cxw)nEf0ojHVdWO8+UmZzP8&Ne8ah2q(#po!{vXkb$^dIOzgs5z;nabl_urSpWs z>6@Nv3W}&u__-&flg8F4qLC`PsHCYHx+<%&x>~EFkD{t7pRL-utFEv@c_py2@_H+- zulgFSm&pnnrjk+GIINVtifJ5qv$I0GrIyb+iJY_Ddiy7}$67nCw5N(YCQJ5QCu+NR zkOXf#D$N^*NcQH4Zjc^o3*@%_iW{)H1KU_Ijt4VFq;vmnD ver.tmp + @echo " * version.h" >> ver.tmp + @echo " */" >> ver.tmp + @echo "" >> ver.tmp + @echo "#define SND_LIB_MAJOR $(SND_LIB_MAJOR) /**< major number of library version */" >> ver.tmp + @echo "#define SND_LIB_MINOR $(SND_LIB_MINOR) /**< minor number of library version */" >> ver.tmp + @echo "#define SND_LIB_SUBMINOR $(SND_LIB_SUBMINOR) /**< subminor number of library version */" >> ver.tmp + @echo "#define SND_LIB_EXTRAVER $(SND_LIB_EXTRAVER) /**< extra version number, used mainly for betas */" >> ver.tmp + @echo "/** library version */" >> ver.tmp + @echo "#define SND_LIB_VERSION ((SND_LIB_MAJOR<<16)|\\" >> ver.tmp + @echo " (SND_LIB_MINOR<<8)|\\" >> ver.tmp + @echo " SND_LIB_SUBMINOR)" >> ver.tmp + @echo "/** library version (string) */" >> ver.tmp + @echo "#define SND_LIB_VERSION_STR \"$(SND_LIB_VERSION)\"" >> ver.tmp + @echo >> ver.tmp + @cmp -s version.h ver.tmp \ + || (echo "Updating version.h"; \ + cp ver.tmp version.h; \ + echo timestamp > stamp-vh) + -@rm -f ver.tmp + +INCLUDES=-I$(top_srcdir)/include + +install-data-hook: + test -d $(DESTDIR)$(sysincludedir) || mkdir -p $(DESTDIR)$(sysincludedir) + $(INSTALL_DATA) $(srcdir)/sys.h $(DESTDIR)$(sysincludedir)/asoundlib.h diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 0000000..153da47 --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,705 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_CTL_PLUGIN_EXT_TRUE@am__append_1 = control_external.h +@BUILD_PCM_TRUE@am__append_2 = pcm.h pcm_old.h timer.h +@BUILD_PCM_PLUGIN_TRUE@@BUILD_PCM_TRUE@am__append_3 = pcm_plugin.h +@BUILD_PCM_PLUGIN_RATE_TRUE@@BUILD_PCM_TRUE@am__append_4 = pcm_rate.h +@BUILD_PCM_PLUGIN_EXTPLUG_TRUE@@BUILD_PCM_TRUE@am__append_5 = pcm_external.h pcm_extplug.h +@BUILD_PCM_PLUGIN_EXTPLUG_FALSE@@BUILD_PCM_PLUGIN_IOPLUG_TRUE@@BUILD_PCM_TRUE@am__append_6 = pcm_external.h +@BUILD_PCM_PLUGIN_IOPLUG_TRUE@@BUILD_PCM_TRUE@am__append_7 = pcm_ioplug.h +@BUILD_RAWMIDI_TRUE@am__append_8 = rawmidi.h +@BUILD_HWDEP_TRUE@am__append_9 = hwdep.h +@BUILD_MIXER_TRUE@am__append_10 = mixer.h mixer_abst.h +@BUILD_SEQ_TRUE@am__append_11 = seq_event.h seq.h seqmid.h seq_midi_event.h +@BUILD_ALISP_TRUE@am__append_12 = alisp.h +subdir = include +DIST_COMMON = $(am__alsainclude_HEADERS_DIST) $(noinst_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__alsainclude_HEADERS_DIST = asoundlib.h asoundef.h version.h \ + global.h input.h output.h error.h conf.h control.h iatomic.h \ + use-case.h control_external.h pcm.h pcm_old.h timer.h \ + pcm_plugin.h pcm_rate.h pcm_external.h pcm_extplug.h \ + pcm_ioplug.h rawmidi.h hwdep.h mixer.h mixer_abst.h \ + seq_event.h seq.h seqmid.h seq_midi_event.h alisp.h +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(alsaincludedir)" +HEADERS = $(alsainclude_HEADERS) $(noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = sound +sysincludedir = ${includedir}/sys +alsaincludedir = ${includedir}/alsa +alsainclude_HEADERS = asoundlib.h asoundef.h version.h global.h \ + input.h output.h error.h conf.h control.h iatomic.h use-case.h \ + $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) $(am__append_6) \ + $(am__append_7) $(am__append_8) $(am__append_9) \ + $(am__append_10) $(am__append_11) $(am__append_12) +noinst_HEADERS = alsa sys.h search.h list.h aserver.h local.h alsa-symbols.h \ + asoundlib-head.h asoundlib-tail.h + +DISTCLEANFILES = stamp-vh version.h alsa asoundlib.h +INCLUDES = -I$(top_srcdir)/include +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status include/config.h +$(srcdir)/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-alsaincludeHEADERS: $(alsainclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(alsaincludedir)" || $(MKDIR_P) "$(DESTDIR)$(alsaincludedir)" + @list='$(alsainclude_HEADERS)'; test -n "$(alsaincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(alsaincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(alsaincludedir)" || exit $$?; \ + done + +uninstall-alsaincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(alsainclude_HEADERS)'; test -n "$(alsaincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(alsaincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(alsaincludedir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(alsaincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-alsaincludeHEADERS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-alsaincludeHEADERS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ + ctags-recursive install-am install-data-am install-strip \ + tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install \ + install-alsaincludeHEADERS install-am install-data \ + install-data-am install-data-hook install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-alsaincludeHEADERS \ + uninstall-am + + +alsa: + ln -s $(top_srcdir)/include alsa + +version.h: stamp-vh alsa + @: + +stamp-vh: $(top_builddir)/configure.in + @echo "/*" > ver.tmp + @echo " * version.h" >> ver.tmp + @echo " */" >> ver.tmp + @echo "" >> ver.tmp + @echo "#define SND_LIB_MAJOR $(SND_LIB_MAJOR) /**< major number of library version */" >> ver.tmp + @echo "#define SND_LIB_MINOR $(SND_LIB_MINOR) /**< minor number of library version */" >> ver.tmp + @echo "#define SND_LIB_SUBMINOR $(SND_LIB_SUBMINOR) /**< subminor number of library version */" >> ver.tmp + @echo "#define SND_LIB_EXTRAVER $(SND_LIB_EXTRAVER) /**< extra version number, used mainly for betas */" >> ver.tmp + @echo "/** library version */" >> ver.tmp + @echo "#define SND_LIB_VERSION ((SND_LIB_MAJOR<<16)|\\" >> ver.tmp + @echo " (SND_LIB_MINOR<<8)|\\" >> ver.tmp + @echo " SND_LIB_SUBMINOR)" >> ver.tmp + @echo "/** library version (string) */" >> ver.tmp + @echo "#define SND_LIB_VERSION_STR \"$(SND_LIB_VERSION)\"" >> ver.tmp + @echo >> ver.tmp + @cmp -s version.h ver.tmp \ + || (echo "Updating version.h"; \ + cp ver.tmp version.h; \ + echo timestamp > stamp-vh) + -@rm -f ver.tmp + +install-data-hook: + test -d $(DESTDIR)$(sysincludedir) || mkdir -p $(DESTDIR)$(sysincludedir) + $(INSTALL_DATA) $(srcdir)/sys.h $(DESTDIR)$(sysincludedir)/asoundlib.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/include/alisp.h b/include/alisp.h new file mode 100644 index 0000000..407ed64 --- /dev/null +++ b/include/alisp.h @@ -0,0 +1,55 @@ +/* + * ALSA lisp implementation + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +struct alisp_cfg { + int verbose: 1, + warning: 1, + debug: 1; + snd_input_t *in; /* program code */ + snd_output_t *out; /* program output */ + snd_output_t *eout; /* error output */ + snd_output_t *vout; /* verbose output */ + snd_output_t *wout; /* warning output */ + snd_output_t *dout; /* debug output */ +}; + +struct alisp_instance; +struct alisp_object; +struct alisp_seq_iterator; + +struct alisp_cfg *alsa_lisp_default_cfg(snd_input_t *input); +void alsa_lisp_default_cfg_free(struct alisp_cfg *cfg); +int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **instance); +void alsa_lisp_free(struct alisp_instance *instance); +int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterator **result, + const char *id, const char *args, ...) +#ifndef DOC_HIDDEN + __attribute__ ((format (printf, 4, 5))) +#endif + ; +void alsa_lisp_result_free(struct alisp_instance *instance, + struct alisp_seq_iterator *result); +int alsa_lisp_seq_first(struct alisp_instance *instance, const char *id, + struct alisp_seq_iterator **seq); +int alsa_lisp_seq_next(struct alisp_seq_iterator **seq); +int alsa_lisp_seq_count(struct alisp_seq_iterator *seq); +int alsa_lisp_seq_integer(struct alisp_seq_iterator *seq, long *val); +int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, void **ptr); diff --git a/include/alsa-symbols.h b/include/alsa-symbols.h new file mode 100644 index 0000000..51cb982 --- /dev/null +++ b/include/alsa-symbols.h @@ -0,0 +1,72 @@ +/* + * ALSA lib - dynamic symbol versions + * Copyright (c) 2002 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_SYMBOLS_H +#define __ALSA_SYMBOLS_H + +#if defined(PIC) && defined(VERSIONED_SYMBOLS) /* might be also configurable */ +#define USE_VERSIONED_SYMBOLS +#endif + +#define INTERNAL_CONCAT2_2(Pre, Post) Pre##Post +#define INTERNAL(Name) INTERNAL_CONCAT2_2(__, Name) + +#ifdef __powerpc64__ +# define symbol_version(real, name, version) \ + __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@" #version); \ + __asm__ (".symver ." ASM_NAME(#real) ",." ASM_NAME(#name) "@" #version) +# define default_symbol_version(real, name, version) \ + __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@@" #version); \ + __asm__ (".symver ." ASM_NAME(#real) ",." ASM_NAME(#name) "@@" #version) +#else +# define symbol_version(real, name, version) \ + __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@" #version) +# define default_symbol_version(real, name, version) \ + __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@@" #version) +#endif + +#ifdef USE_VERSIONED_SYMBOLS +#define use_symbol_version(real, name, version) \ + symbol_version(real, name, version) +#define use_default_symbol_version(real, name, version) \ + default_symbol_version(real, name, version) +#else +#define use_symbol_version(real, name, version) /* nothing */ +#ifdef __powerpc64__ +#define use_default_symbol_version(real, name, version) \ + __asm__ (".weak " ASM_NAME(#name)); \ + __asm__ (".weak ." ASM_NAME(#name)); \ + __asm__ (".set " ASM_NAME(#name) "," ASM_NAME(#real)); \ + __asm__ (".set ." ASM_NAME(#name) ",." ASM_NAME(#real)) +#else +#if defined(__alpha__) || defined(__mips__) +#define use_default_symbol_version(real, name, version) \ + __asm__ (".weak " ASM_NAME(#name)); \ + __asm__ (ASM_NAME(#name) " = " ASM_NAME(#real)) +#else +#define use_default_symbol_version(real, name, version) \ + __asm__ (".weak " ASM_NAME(#name)); \ + __asm__ (".set " ASM_NAME(#name) "," ASM_NAME(#real)) +#endif +#endif +#endif + +#endif /* __ALSA_SYMBOLS_H */ diff --git a/include/aserver.h b/include/aserver.h new file mode 100644 index 0000000..2586832 --- /dev/null +++ b/include/aserver.h @@ -0,0 +1,160 @@ +/* + * ALSA client/server header file + * Copyright (c) 2000 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "../src/pcm/pcm_local.h" +#include "../src/control/control_local.h" + +int snd_receive_fd(int sock, void *data, size_t len, int *fd); +int snd_is_local(struct hostent *hent); + +typedef enum _snd_dev_type { + SND_DEV_TYPE_PCM, + SND_DEV_TYPE_CONTROL, + SND_DEV_TYPE_RAWMIDI, + SND_DEV_TYPE_TIMER, + SND_DEV_TYPE_HWDEP, + SND_DEV_TYPE_SEQ, +} snd_dev_type_t; + +typedef enum _snd_transport_type { + SND_TRANSPORT_TYPE_SHM, + SND_TRANSPORT_TYPE_TCP, +} snd_transport_type_t; + +#define SND_PCM_IOCTL_HWSYNC _IO ('A', 0x22) +#define SND_PCM_IOCTL_STATE _IO ('A', 0xf1) +#define SND_PCM_IOCTL_MMAP _IO ('A', 0xf2) +#define SND_PCM_IOCTL_MUNMAP _IO ('A', 0xf3) +#define SND_PCM_IOCTL_MMAP_COMMIT _IO ('A', 0xf4) +#define SND_PCM_IOCTL_AVAIL_UPDATE _IO ('A', 0xf5) +#define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf6) +#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xf7) +#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xf8) +#define SND_PCM_IOCTL_HW_PTR_FD _IO ('A', 0xf9) +#define SND_PCM_IOCTL_APPL_PTR_FD _IO ('A', 0xfa) +#define SND_PCM_IOCTL_FORWARD _IO ('A', 0xfb) + +typedef struct { + snd_pcm_uframes_t ptr; + int use_mmap; + off_t offset; /* for mmap */ + int changed; +} snd_pcm_shm_rbptr_t; + +typedef struct { + long result; + int cmd; + snd_pcm_shm_rbptr_t hw; + snd_pcm_shm_rbptr_t appl; + union { + struct { + int sig; + pid_t pid; + } async; + snd_pcm_info_t info; + snd_pcm_hw_params_t hw_refine; + snd_pcm_hw_params_t hw_params; + snd_pcm_sw_params_t sw_params; + snd_pcm_status_t status; + struct { + snd_pcm_uframes_t frames; + } avail; + struct { + snd_pcm_sframes_t frames; + } delay; + struct { + int enable; + } pause; + snd_pcm_channel_info_t channel_info; + struct { + snd_pcm_uframes_t frames; + } rewind; + struct { + snd_pcm_uframes_t frames; + } forward; + struct { + int fd; + } link; + struct { + snd_pcm_uframes_t offset; + snd_pcm_uframes_t frames; + } mmap_commit; + struct { + char use_mmap; + int shmid; + off_t offset; + } rbptr; + } u; + char data[0]; +} snd_pcm_shm_ctrl_t; + +#define PCM_SHM_SIZE sizeof(snd_pcm_shm_ctrl_t) + +#define SND_CTL_IOCTL_READ _IOR('U', 0xf1, snd_ctl_event_t) +#define SND_CTL_IOCTL_CLOSE _IO ('U', 0xf2) +#define SND_CTL_IOCTL_POLL_DESCRIPTOR _IO ('U', 0xf3) +#define SND_CTL_IOCTL_ASYNC _IO ('U', 0xf4) + +typedef struct { + int result; + int cmd; + union { + struct { + int sig; + pid_t pid; + } async; + int device; + int subscribe_events; + snd_ctl_card_info_t card_info; + snd_ctl_elem_list_t element_list; + snd_ctl_elem_info_t element_info; + snd_ctl_elem_value_t element_read; + snd_ctl_elem_value_t element_write; + snd_ctl_elem_id_t element_lock; + snd_ctl_elem_id_t element_unlock; + snd_hwdep_info_t hwdep_info; + snd_pcm_info_t pcm_info; + int pcm_prefer_subdevice; + snd_rawmidi_info_t rawmidi_info; + int rawmidi_prefer_subdevice; + unsigned int power_state; + snd_ctl_event_t read; + } u; + char data[0]; +} snd_ctl_shm_ctrl_t; + +#define CTL_SHM_SIZE 65536 +#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_shm_ctrl_t, data)) + +typedef struct { + unsigned char dev_type; + unsigned char transport_type; + unsigned char stream; + unsigned char mode; + unsigned char namelen; + char name[0]; +} snd_client_open_request_t; + +typedef struct { + long result; + int cookie; +} snd_client_open_answer_t; + diff --git a/include/asoundef.h b/include/asoundef.h new file mode 100644 index 0000000..c6c4eec --- /dev/null +++ b/include/asoundef.h @@ -0,0 +1,310 @@ +/** + * \file include/asoundef.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Definitions of constants for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_ASOUNDEF_H +#define __ALSA_ASOUNDEF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Digital_Audio_Interface Constants for Digital Audio Interfaces + * AES/IEC958 channel status bits. + * \{ + */ + +#define IEC958_AES0_PROFESSIONAL (1<<0) /**< 0 = consumer, 1 = professional */ +#define IEC958_AES0_NONAUDIO (1<<1) /**< 0 = audio, 1 = non-audio */ +#define IEC958_AES0_PRO_EMPHASIS (7<<2) /**< mask - emphasis */ +#define IEC958_AES0_PRO_EMPHASIS_NOTID (0<<2) /**< emphasis not indicated */ +#define IEC958_AES0_PRO_EMPHASIS_NONE (1<<2) /**< no emphasis */ +#define IEC958_AES0_PRO_EMPHASIS_5015 (3<<2) /**< 50/15us emphasis */ +#define IEC958_AES0_PRO_EMPHASIS_CCITT (7<<2) /**< CCITT J.17 emphasis */ +#define IEC958_AES0_PRO_FREQ_UNLOCKED (1<<5) /**< source sample frequency: 0 = locked, 1 = unlocked */ +#define IEC958_AES0_PRO_FS (3<<6) /**< mask - sample frequency */ +#define IEC958_AES0_PRO_FS_NOTID (0<<6) /**< fs not indicated */ +#define IEC958_AES0_PRO_FS_44100 (1<<6) /**< 44.1kHz */ +#define IEC958_AES0_PRO_FS_48000 (2<<6) /**< 48kHz */ +#define IEC958_AES0_PRO_FS_32000 (3<<6) /**< 32kHz */ +#define IEC958_AES0_CON_NOT_COPYRIGHT (1<<2) /**< 0 = copyright, 1 = not copyright */ +#define IEC958_AES0_CON_EMPHASIS (7<<3) /**< mask - emphasis */ +#define IEC958_AES0_CON_EMPHASIS_NONE (0<<3) /**< no emphasis */ +#define IEC958_AES0_CON_EMPHASIS_5015 (1<<3) /**< 50/15us emphasis */ +#define IEC958_AES0_CON_MODE (3<<6) /**< mask - mode */ +#define IEC958_AES1_PRO_MODE (15<<0) /**< mask - channel mode */ +#define IEC958_AES1_PRO_MODE_NOTID (0<<0) /**< mode not indicated */ +#define IEC958_AES1_PRO_MODE_STEREOPHONIC (2<<0) /**< stereophonic - ch A is left */ +#define IEC958_AES1_PRO_MODE_SINGLE (4<<0) /**< single channel */ +#define IEC958_AES1_PRO_MODE_TWO (8<<0) /**< two channels */ +#define IEC958_AES1_PRO_MODE_PRIMARY (12<<0) /**< primary/secondary */ +#define IEC958_AES1_PRO_MODE_BYTE3 (15<<0) /**< vector to byte 3 */ +#define IEC958_AES1_PRO_USERBITS (15<<4) /**< mask - user bits */ +#define IEC958_AES1_PRO_USERBITS_NOTID (0<<4) /**< user bits not indicated */ +#define IEC958_AES1_PRO_USERBITS_192 (8<<4) /**< 192-bit structure */ +#define IEC958_AES1_PRO_USERBITS_UDEF (12<<4) /**< user defined application */ +#define IEC958_AES1_CON_CATEGORY 0x7f /**< consumer category */ +#define IEC958_AES1_CON_GENERAL 0x00 /**< general category */ +#define IEC958_AES1_CON_LASEROPT_MASK 0x07 /**< Laser-optical mask */ +#define IEC958_AES1_CON_LASEROPT_ID 0x01 /**< Laser-optical ID */ +#define IEC958_AES1_CON_IEC908_CD (IEC958_AES1_CON_LASEROPT_ID|0x00) /**< IEC958 CD compatible device */ +#define IEC958_AES1_CON_NON_IEC908_CD (IEC958_AES1_CON_LASEROPT_ID|0x08) /**< non-IEC958 CD compatible device */ +#define IEC958_AES1_CON_MINI_DISC (IEC958_AES1_CON_LASEROPT_ID|0x48) /**< Mini-Disc device */ +#define IEC958_AES1_CON_DVD (IEC958_AES1_CON_LASEROPT_ID|0x18) /**< DVD device */ +#define IEC958_AES1_CON_LASTEROPT_OTHER (IEC958_AES1_CON_LASEROPT_ID|0x78) /**< Other laser-optical product */ +#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07 /**< digital<->digital converter mask */ +#define IEC958_AES1_CON_DIGDIGCONV_ID 0x02 /**< digital<->digital converter id */ +#define IEC958_AES1_CON_PCM_CODER (IEC958_AES1_CON_DIGDIGCONV_ID|0x00) /**< PCM coder */ +#define IEC958_AES1_CON_MIXER (IEC958_AES1_CON_DIGDIGCONV_ID|0x10) /**< Digital signal mixer */ +#define IEC958_AES1_CON_RATE_CONVERTER (IEC958_AES1_CON_DIGDIGCONV_ID|0x18) /**< Rate converter */ +#define IEC958_AES1_CON_SAMPLER (IEC958_AES1_CON_DIGDIGCONV_ID|0x20) /**< PCM sampler */ +#define IEC958_AES1_CON_DSP (IEC958_AES1_CON_DIGDIGCONV_ID|0x28) /**< Digital sound processor */ +#define IEC958_AES1_CON_DIGDIGCONV_OTHER (IEC958_AES1_CON_DIGDIGCONV_ID|0x78) /**< Other digital<->digital product */ +#define IEC958_AES1_CON_MAGNETIC_MASK 0x07 /**< Magnetic device mask */ +#define IEC958_AES1_CON_MAGNETIC_ID 0x03 /**< Magnetic device ID */ +#define IEC958_AES1_CON_DAT (IEC958_AES1_CON_MAGNETIC_ID|0x00) /**< Digital Audio Tape */ +#define IEC958_AES1_CON_VCR (IEC958_AES1_CON_MAGNETIC_ID|0x08) /**< Video recorder */ +#define IEC958_AES1_CON_DCC (IEC958_AES1_CON_MAGNETIC_ID|0x40) /**< Digital compact cassette */ +#define IEC958_AES1_CON_MAGNETIC_DISC (IEC958_AES1_CON_MAGNETIC_ID|0x18) /**< Magnetic disc digital audio device */ +#define IEC958_AES1_CON_MAGNETIC_OTHER (IEC958_AES1_CON_MAGNETIC_ID|0x78) /**< Other magnetic device */ +#define IEC958_AES1_CON_BROADCAST1_MASK 0x07 /**< Broadcast mask */ +#define IEC958_AES1_CON_BROADCAST1_ID 0x04 /**< Broadcast ID */ +#define IEC958_AES1_CON_DAB_JAPAN (IEC958_AES1_CON_BROADCAST1_ID|0x00) /**< Digital audio broadcast (Japan) */ +#define IEC958_AES1_CON_DAB_EUROPE (IEC958_AES1_CON_BROADCAST1_ID|0x08) /**< Digital audio broadcast (Europe) */ +#define IEC958_AES1_CON_DAB_USA (IEC958_AES1_CON_BROADCAST1_ID|0x60) /**< Digital audio broadcast (USA) */ +#define IEC958_AES1_CON_SOFTWARE (IEC958_AES1_CON_BROADCAST1_ID|0x40) /**< Electronic software delivery */ +#define IEC958_AES1_CON_IEC62105 (IEC958_AES1_CON_BROADCAST1_ID|0x20) /**< Used by another standard (IEC 62105) */ +#define IEC958_AES1_CON_BROADCAST1_OTHER (IEC958_AES1_CON_BROADCAST1_ID|0x78) /**< Other broadcast product */ +#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f /**< Broadcast alternative mask */ +#define IEC958_AES1_CON_BROADCAST2_ID 0x0e /**< Broadcast alternative ID */ +#define IEC958_AES1_CON_MUSICAL_MASK 0x07 /**< Musical device mask */ +#define IEC958_AES1_CON_MUSICAL_ID 0x05 /**< Musical device ID */ +#define IEC958_AES1_CON_SYNTHESIZER (IEC958_AES1_CON_MUSICAL_ID|0x00) /**< Synthesizer */ +#define IEC958_AES1_CON_MICROPHONE (IEC958_AES1_CON_MUSICAL_ID|0x08) /**< Microphone */ +#define IEC958_AES1_CON_MUSICAL_OTHER (IEC958_AES1_CON_MUSICAL_ID|0x78) /**< Other musical device */ +#define IEC958_AES1_CON_ADC_MASK 0x1f /**< ADC Mask */ +#define IEC958_AES1_CON_ADC_ID 0x06 /**< ADC ID */ +#define IEC958_AES1_CON_ADC (IEC958_AES1_CON_ADC_ID|0x00) /**< ADC without copyright information */ +#define IEC958_AES1_CON_ADC_OTHER (IEC958_AES1_CON_ADC_ID|0x60) /**< Other ADC product (with no copyright information) */ +#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f /**< ADC Copyright mask */ +#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x16 /**< ADC Copyright ID */ +#define IEC958_AES1_CON_ADC_COPYRIGHT (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x00) /**< ADC with copyright information */ +#define IEC958_AES1_CON_ADC_COPYRIGHT_OTHER (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x60) /**< Other ADC with copyright information product */ +#define IEC958_AES1_CON_SOLIDMEM_MASK 0x0f /**< Solid memory based products mask */ +#define IEC958_AES1_CON_SOLIDMEM_ID 0x08 /**< Solid memory based products ID */ +#define IEC958_AES1_CON_SOLIDMEM_DIGITAL_RECORDER_PLAYER (IEC958_AES1_CON_SOLIDMEM_ID|0x00) /**< Digital audio recorder and player using solid state memory */ +#define IEC958_AES1_CON_SOLIDMEM_OTHER (IEC958_AES1_CON_SOLIDMEM_ID|0x70) /**< Other solid state memory based product */ +#define IEC958_AES1_CON_EXPERIMENTAL 0x40 /**< experimental category */ +#define IEC958_AES1_CON_ORIGINAL (1<<7) /**< this bits depends on the category code */ +#define IEC958_AES2_PRO_SBITS (7<<0) /**< mask - sample bits */ +#define IEC958_AES2_PRO_SBITS_20 (2<<0) /**< 20-bit - coordination */ +#define IEC958_AES2_PRO_SBITS_24 (4<<0) /**< 24-bit - main audio */ +#define IEC958_AES2_PRO_SBITS_UDEF (6<<0) /**< user defined application */ +#define IEC958_AES2_PRO_WORDLEN (7<<3) /**< mask - source word length */ +#define IEC958_AES2_PRO_WORDLEN_NOTID (0<<3) /**< source word length not indicated */ +#define IEC958_AES2_PRO_WORDLEN_22_18 (2<<3) /**< 22-bit or 18-bit */ +#define IEC958_AES2_PRO_WORDLEN_23_19 (4<<3) /**< 23-bit or 19-bit */ +#define IEC958_AES2_PRO_WORDLEN_24_20 (5<<3) /**< 24-bit or 20-bit */ +#define IEC958_AES2_PRO_WORDLEN_20_16 (6<<3) /**< 20-bit or 16-bit */ +#define IEC958_AES2_CON_SOURCE (15<<0) /**< mask - source number */ +#define IEC958_AES2_CON_SOURCE_UNSPEC (0<<0) /**< source number unspecified */ +#define IEC958_AES2_CON_CHANNEL (15<<4) /**< mask - channel number */ +#define IEC958_AES2_CON_CHANNEL_UNSPEC (0<<4) /**< channel number unspecified */ +#define IEC958_AES3_CON_FS (15<<0) /**< mask - sample frequency */ +#define IEC958_AES3_CON_FS_44100 (0<<0) /**< 44.1kHz */ +#define IEC958_AES3_CON_FS_NOTID (1<<0) /**< sample frequency non indicated */ +#define IEC958_AES3_CON_FS_48000 (2<<0) /**< 48kHz */ +#define IEC958_AES3_CON_FS_32000 (3<<0) /**< 32kHz */ +#define IEC958_AES3_CON_FS_22050 (4<<0) /**< 22.05kHz */ +#define IEC958_AES3_CON_FS_24000 (6<<0) /**< 24kHz */ +#define IEC958_AES3_CON_FS_88200 (8<<0) /**< 88.2kHz */ +#define IEC958_AES3_CON_FS_768000 (9<<0) /**< 768kHz */ +#define IEC958_AES3_CON_FS_96000 (10<<0) /**< 96kHz */ +#define IEC958_AES3_CON_FS_176400 (12<<0) /**< 176.4kHz */ +#define IEC958_AES3_CON_FS_192000 (14<<0) /**< 192kHz */ +#define IEC958_AES3_CON_CLOCK (3<<4) /**< mask - clock accuracy */ +#define IEC958_AES3_CON_CLOCK_1000PPM (0<<4) /**< 1000 ppm */ +#define IEC958_AES3_CON_CLOCK_50PPM (1<<4) /**< 50 ppm */ +#define IEC958_AES3_CON_CLOCK_VARIABLE (2<<4) /**< variable pitch */ +#define IEC958_AES4_CON_MAX_WORDLEN_24 (1<<0) /**< 0 = 20-bit, 1 = 24-bit */ +#define IEC958_AES4_CON_WORDLEN (7<<1) /**< mask - sample word length */ +#define IEC958_AES4_CON_WORDLEN_NOTID (0<<1) /**< not indicated */ +#define IEC958_AES4_CON_WORDLEN_20_16 (1<<1) /**< 20-bit or 16-bit */ +#define IEC958_AES4_CON_WORDLEN_22_18 (2<<1) /**< 22-bit or 18-bit */ +#define IEC958_AES4_CON_WORDLEN_23_19 (4<<1) /**< 23-bit or 19-bit */ +#define IEC958_AES4_CON_WORDLEN_24_20 (5<<1) /**< 24-bit or 20-bit */ +#define IEC958_AES4_CON_WORDLEN_21_17 (6<<1) /**< 21-bit or 17-bit */ +#define IEC958_AES4_CON_ORIGFS (15<<4) /**< mask - original sample frequency */ +#define IEC958_AES4_CON_ORIGFS_NOTID (0<<4) /**< original sample frequency not indicated */ +#define IEC958_AES4_CON_ORIGFS_192000 (1<<4) /**< 192kHz */ +#define IEC958_AES4_CON_ORIGFS_12000 (2<<4) /**< 12kHz */ +#define IEC958_AES4_CON_ORIGFS_176400 (3<<4) /**< 176.4kHz */ +#define IEC958_AES4_CON_ORIGFS_96000 (5<<4) /**< 96kHz */ +#define IEC958_AES4_CON_ORIGFS_8000 (6<<4) /**< 8kHz */ +#define IEC958_AES4_CON_ORIGFS_88200 (7<<4) /**< 88.2kHz */ +#define IEC958_AES4_CON_ORIGFS_16000 (8<<4) /**< 16kHz */ +#define IEC958_AES4_CON_ORIGFS_24000 (9<<4) /**< 24kHz */ +#define IEC958_AES4_CON_ORIGFS_11025 (10<<4) /**< 11.025kHz */ +#define IEC958_AES4_CON_ORIGFS_22050 (11<<4) /**< 22.05kHz */ +#define IEC958_AES4_CON_ORIGFS_32000 (12<<4) /**< 32kHz */ +#define IEC958_AES4_CON_ORIGFS_48000 (13<<4) /**< 48kHz */ +#define IEC958_AES4_CON_ORIGFS_44100 (15<<4) /**< 44.1kHz */ +#define IEC958_AES5_CON_CGMSA (3<<0) /**< mask - CGMS-A */ +#define IEC958_AES5_CON_CGMSA_COPYFREELY (0<<0) /**< copying is permitted without restriction */ +#define IEC958_AES5_CON_CGMSA_COPYONCE (1<<0) /**< one generation of copies may be made */ +#define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0) /**< condition not be used */ +#define IEC958_AES5_CON_CGMSA_COPYNEVER (3<<0) /**< no copying is permitted */ + +/** \} */ + +/** + * \defgroup MIDI_Interface Constants for MIDI v1.0 + * Constants for MIDI v1.0. + * \{ + */ + +#define MIDI_CHANNELS 16 /**< Number of channels per port/cable. */ +#define MIDI_GM_DRUM_CHANNEL (10-1) /**< Channel number for GM drums. */ + +/** + * \defgroup MIDI_Commands MIDI Commands + * MIDI command codes. + * \{ + */ + +#define MIDI_CMD_NOTE_OFF 0x80 /**< note off */ +#define MIDI_CMD_NOTE_ON 0x90 /**< note on */ +#define MIDI_CMD_NOTE_PRESSURE 0xa0 /**< key pressure */ +#define MIDI_CMD_CONTROL 0xb0 /**< control change */ +#define MIDI_CMD_PGM_CHANGE 0xc0 /**< program change */ +#define MIDI_CMD_CHANNEL_PRESSURE 0xd0 /**< channel pressure */ +#define MIDI_CMD_BENDER 0xe0 /**< pitch bender */ + +#define MIDI_CMD_COMMON_SYSEX 0xf0 /**< sysex (system exclusive) begin */ +#define MIDI_CMD_COMMON_MTC_QUARTER 0xf1 /**< MTC quarter frame */ +#define MIDI_CMD_COMMON_SONG_POS 0xf2 /**< song position */ +#define MIDI_CMD_COMMON_SONG_SELECT 0xf3 /**< song select */ +#define MIDI_CMD_COMMON_TUNE_REQUEST 0xf6 /**< tune request */ +#define MIDI_CMD_COMMON_SYSEX_END 0xf7 /**< end of sysex */ +#define MIDI_CMD_COMMON_CLOCK 0xf8 /**< clock */ +#define MIDI_CMD_COMMON_START 0xfa /**< start */ +#define MIDI_CMD_COMMON_CONTINUE 0xfb /**< continue */ +#define MIDI_CMD_COMMON_STOP 0xfc /**< stop */ +#define MIDI_CMD_COMMON_SENSING 0xfe /**< active sensing */ +#define MIDI_CMD_COMMON_RESET 0xff /**< reset */ + +/** \} */ + +/** + * \defgroup MIDI_Controllers MIDI Controllers + * MIDI controller numbers. + * \{ + */ + +#define MIDI_CTL_MSB_BANK 0x00 /**< Bank selection */ +#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ +#define MIDI_CTL_MSB_BREATH 0x02 /**< Breath */ +#define MIDI_CTL_MSB_FOOT 0x04 /**< Foot */ +#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ +#define MIDI_CTL_MSB_DATA_ENTRY 0x06 /**< Data entry */ +#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ +#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ +#define MIDI_CTL_MSB_PAN 0x0a /**< Panpot */ +#define MIDI_CTL_MSB_EXPRESSION 0x0b /**< Expression */ +#define MIDI_CTL_MSB_EFFECT1 0x0c /**< Effect1 */ +#define MIDI_CTL_MSB_EFFECT2 0x0d /**< Effect2 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 /**< General purpose 1 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 /**< General purpose 2 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 /**< General purpose 3 */ +#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 /**< General purpose 4 */ +#define MIDI_CTL_LSB_BANK 0x20 /**< Bank selection */ +#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ +#define MIDI_CTL_LSB_BREATH 0x22 /**< Breath */ +#define MIDI_CTL_LSB_FOOT 0x24 /**< Foot */ +#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ +#define MIDI_CTL_LSB_DATA_ENTRY 0x26 /**< Data entry */ +#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ +#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ +#define MIDI_CTL_LSB_PAN 0x2a /**< Panpot */ +#define MIDI_CTL_LSB_EXPRESSION 0x2b /**< Expression */ +#define MIDI_CTL_LSB_EFFECT1 0x2c /**< Effect1 */ +#define MIDI_CTL_LSB_EFFECT2 0x2d /**< Effect2 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 /**< General purpose 1 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 /**< General purpose 2 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 /**< General purpose 3 */ +#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 /**< General purpose 4 */ +#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ +#define MIDI_CTL_PORTAMENTO 0x41 /**< Portamento */ +#define MIDI_CTL_SOSTENUTO 0x42 /**< Sostenuto */ +#define MIDI_CTL_SUSTENUTO 0x42 /**< Sostenuto (a typo in the older version) */ +#define MIDI_CTL_SOFT_PEDAL 0x43 /**< Soft pedal */ +#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 /**< Legato foot switch */ +#define MIDI_CTL_HOLD2 0x45 /**< Hold2 */ +#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 /**< SC1 Sound Variation */ +#define MIDI_CTL_SC2_TIMBRE 0x47 /**< SC2 Timbre */ +#define MIDI_CTL_SC3_RELEASE_TIME 0x48 /**< SC3 Release Time */ +#define MIDI_CTL_SC4_ATTACK_TIME 0x49 /**< SC4 Attack Time */ +#define MIDI_CTL_SC5_BRIGHTNESS 0x4a /**< SC5 Brightness */ +#define MIDI_CTL_SC6 0x4b /**< SC6 */ +#define MIDI_CTL_SC7 0x4c /**< SC7 */ +#define MIDI_CTL_SC8 0x4d /**< SC8 */ +#define MIDI_CTL_SC9 0x4e /**< SC9 */ +#define MIDI_CTL_SC10 0x4f /**< SC10 */ +#define MIDI_CTL_GENERAL_PURPOSE5 0x50 /**< General purpose 5 */ +#define MIDI_CTL_GENERAL_PURPOSE6 0x51 /**< General purpose 6 */ +#define MIDI_CTL_GENERAL_PURPOSE7 0x52 /**< General purpose 7 */ +#define MIDI_CTL_GENERAL_PURPOSE8 0x53 /**< General purpose 8 */ +#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 /**< Portamento control */ +#define MIDI_CTL_E1_REVERB_DEPTH 0x5b /**< E1 Reverb Depth */ +#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5c /**< E2 Tremolo Depth */ +#define MIDI_CTL_E3_CHORUS_DEPTH 0x5d /**< E3 Chorus Depth */ +#define MIDI_CTL_E4_DETUNE_DEPTH 0x5e /**< E4 Detune Depth */ +#define MIDI_CTL_E5_PHASER_DEPTH 0x5f /**< E5 Phaser Depth */ +#define MIDI_CTL_DATA_INCREMENT 0x60 /**< Data Increment */ +#define MIDI_CTL_DATA_DECREMENT 0x61 /**< Data Decrement */ +#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 /**< Non-registered parameter number */ +#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 /**< Non-registered parameter number */ +#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 /**< Registered parameter number */ +#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 /**< Registered parameter number */ +#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ +#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ +#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7a /**< Local control switch */ +#define MIDI_CTL_ALL_NOTES_OFF 0x7b /**< All notes off */ +#define MIDI_CTL_OMNI_OFF 0x7c /**< Omni off */ +#define MIDI_CTL_OMNI_ON 0x7d /**< Omni on */ +#define MIDI_CTL_MONO1 0x7e /**< Mono1 */ +#define MIDI_CTL_MONO2 0x7f /**< Mono2 */ + +/** \} */ + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_ASOUNDEF_H */ diff --git a/include/asoundlib-head.h b/include/asoundlib-head.h new file mode 100644 index 0000000..20c8a68 --- /dev/null +++ b/include/asoundlib-head.h @@ -0,0 +1,48 @@ +/** + * \file include/asoundlib.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASOUNDLIB_H +#define __ASOUNDLIB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include diff --git a/include/asoundlib-tail.h b/include/asoundlib-tail.h new file mode 100644 index 0000000..e20f5ad --- /dev/null +++ b/include/asoundlib-tail.h @@ -0,0 +1,2 @@ + +#endif /* __ASOUNDLIB_H */ diff --git a/include/conf.h b/include/conf.h new file mode 100644 index 0000000..ff270f6 --- /dev/null +++ b/include/conf.h @@ -0,0 +1,207 @@ +/** + * \file include/conf.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_CONF_H +#define __ALSA_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Config Configuration Interface + * The configuration functions and types allow you to read, enumerate, + * modify and write the contents of ALSA configuration files. + * \{ + */ + +/** \brief \c dlsym version for the config evaluate callback. */ +#define SND_CONFIG_DLSYM_VERSION_EVALUATE _dlsym_config_evaluate_001 +/** \brief \c dlsym version for the config hook callback. */ +#define SND_CONFIG_DLSYM_VERSION_HOOK _dlsym_config_hook_001 + +/** \brief Configuration node type. */ +typedef enum _snd_config_type { + /** Integer number. */ + SND_CONFIG_TYPE_INTEGER, + /** 64-bit integer number. */ + SND_CONFIG_TYPE_INTEGER64, + /** Real number. */ + SND_CONFIG_TYPE_REAL, + /** Character string. */ + SND_CONFIG_TYPE_STRING, + /** Pointer (runtime only, cannot be saved). */ + SND_CONFIG_TYPE_POINTER, + /** Compound node. */ + SND_CONFIG_TYPE_COMPOUND = 1024 +} snd_config_type_t; + +/** + * \brief Internal structure for a configuration node object. + * + * The ALSA library uses a pointer to this structure as a handle to a + * configuration node. Applications don't access its contents directly. + */ +typedef struct _snd_config snd_config_t; +/** + * \brief Type for a configuration compound iterator. + * + * The ALSA library uses this pointer type as a handle to a configuration + * compound iterator. Applications don't directly access the contents of + * the structure pointed to by this type. + */ +typedef struct _snd_config_iterator *snd_config_iterator_t; +/** + * \brief Internal structure for a configuration private update object. + * + * The ALSA library uses this structure to save private update information. + */ +typedef struct _snd_config_update snd_config_update_t; + +extern snd_config_t *snd_config; + +int snd_config_top(snd_config_t **config); + +int snd_config_load(snd_config_t *config, snd_input_t *in); +int snd_config_load_override(snd_config_t *config, snd_input_t *in); +int snd_config_save(snd_config_t *config, snd_output_t *out); +int snd_config_update(void); +int snd_config_update_r(snd_config_t **top, snd_config_update_t **update, const char *path); +int snd_config_update_free(snd_config_update_t *update); +int snd_config_update_free_global(void); + +int snd_config_search(snd_config_t *config, const char *key, + snd_config_t **result); +int snd_config_searchv(snd_config_t *config, + snd_config_t **result, ...); +int snd_config_search_definition(snd_config_t *config, + const char *base, const char *key, + snd_config_t **result); + +int snd_config_expand(snd_config_t *config, snd_config_t *root, + const char *args, snd_config_t *private_data, + snd_config_t **result); +int snd_config_evaluate(snd_config_t *config, snd_config_t *root, + snd_config_t *private_data, snd_config_t **result); + +int snd_config_add(snd_config_t *config, snd_config_t *leaf); +int snd_config_delete(snd_config_t *config); +int snd_config_delete_compound_members(const snd_config_t *config); +int snd_config_copy(snd_config_t **dst, snd_config_t *src); + +int snd_config_make(snd_config_t **config, const char *key, + snd_config_type_t type); +int snd_config_make_integer(snd_config_t **config, const char *key); +int snd_config_make_integer64(snd_config_t **config, const char *key); +int snd_config_make_real(snd_config_t **config, const char *key); +int snd_config_make_string(snd_config_t **config, const char *key); +int snd_config_make_pointer(snd_config_t **config, const char *key); +int snd_config_make_compound(snd_config_t **config, const char *key, int join); + +int snd_config_imake_integer(snd_config_t **config, const char *key, const long value); +int snd_config_imake_integer64(snd_config_t **config, const char *key, const long long value); +int snd_config_imake_real(snd_config_t **config, const char *key, const double value); +int snd_config_imake_string(snd_config_t **config, const char *key, const char *ascii); +int snd_config_imake_pointer(snd_config_t **config, const char *key, const void *ptr); + +snd_config_type_t snd_config_get_type(const snd_config_t *config); + +int snd_config_set_id(snd_config_t *config, const char *id); +int snd_config_set_integer(snd_config_t *config, long value); +int snd_config_set_integer64(snd_config_t *config, long long value); +int snd_config_set_real(snd_config_t *config, double value); +int snd_config_set_string(snd_config_t *config, const char *value); +int snd_config_set_ascii(snd_config_t *config, const char *ascii); +int snd_config_set_pointer(snd_config_t *config, const void *ptr); +int snd_config_get_id(const snd_config_t *config, const char **value); +int snd_config_get_integer(const snd_config_t *config, long *value); +int snd_config_get_integer64(const snd_config_t *config, long long *value); +int snd_config_get_real(const snd_config_t *config, double *value); +int snd_config_get_ireal(const snd_config_t *config, double *value); +int snd_config_get_string(const snd_config_t *config, const char **value); +int snd_config_get_ascii(const snd_config_t *config, char **value); +int snd_config_get_pointer(const snd_config_t *config, const void **value); +int snd_config_test_id(const snd_config_t *config, const char *id); + +snd_config_iterator_t snd_config_iterator_first(const snd_config_t *node); +snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator); +snd_config_iterator_t snd_config_iterator_end(const snd_config_t *node); +snd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator); + +/** + * \brief Helper macro to iterate over the children of a compound node. + * \param[in,out] pos Iterator variable for the current node. + * \param[in,out] next Temporary iterator variable for the next node. + * \param[in] node Handle to the compound configuration node to iterate over. + * + * Use this macro like a \c for statement, e.g.: + * \code + * snd_config_iterator_t pos, next; + * snd_config_for_each(pos, next, node) { + * snd_config_t *entry = snd_config_iterator_entry(pos); + * ... + * } + * \endcode + * + * This macro allows deleting or removing the current node. + */ +#define snd_config_for_each(pos, next, node) \ + for (pos = snd_config_iterator_first(node), next = snd_config_iterator_next(pos); pos != snd_config_iterator_end(node); pos = next, next = snd_config_iterator_next(pos)) + +/* Misc functions */ + +int snd_config_get_bool_ascii(const char *ascii); +int snd_config_get_bool(const snd_config_t *conf); +int snd_config_get_ctl_iface_ascii(const char *ascii); +int snd_config_get_ctl_iface(const snd_config_t *conf); + +/* Names functions */ + +/** + * Device-name list element + */ +typedef struct snd_devname snd_devname_t; + +/** + * Device-name list element (definition) + */ +struct snd_devname { + char *name; /**< Device name string */ + char *comment; /**< Comments */ + snd_devname_t *next; /**< Next pointer */ +}; + +int snd_names_list(const char *iface, snd_devname_t **list); +void snd_names_list_free(snd_devname_t *list); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_CONF_H */ diff --git a/include/config.h.in b/include/config.h.in new file mode 100644 index 0000000..c01a78b --- /dev/null +++ b/include/config.h.in @@ -0,0 +1,170 @@ +/* include/config.h.in. Generated from configure.in by autoheader. */ + +/* Directory with aload* device files */ +#undef ALOAD_DEVICE_DIRECTORY + +/* directory containing ALSA configuration database */ +#undef ALSA_CONFIG_DIR + +/* Enable assert at error message handler */ +#undef ALSA_DEBUG_ASSERT + +/* Directory with ALSA device files */ +#undef ALSA_DEVICE_DIRECTORY + +/* directory containing ALSA add-on modules */ +#undef ALSA_PLUGIN_DIR + +/* Build hwdep component */ +#undef BUILD_HWDEP + +/* Build mixer component */ +#undef BUILD_MIXER + +/* Build PCM component */ +#undef BUILD_PCM + +/* Build PCM adpcm plugin */ +#undef BUILD_PCM_PLUGIN_ADPCM + +/* Build PCM alaw plugin */ +#undef BUILD_PCM_PLUGIN_ALAW + +/* Build PCM lfloat plugin */ +#undef BUILD_PCM_PLUGIN_LFLOAT + +/* Build PCM mmap-emul plugin */ +#undef BUILD_PCM_PLUGIN_MMAP_EMUL + +/* Build PCM mulaw plugin */ +#undef BUILD_PCM_PLUGIN_MULAW + +/* Build PCM rate plugin */ +#undef BUILD_PCM_PLUGIN_RATE + +/* Build PCM route plugin */ +#undef BUILD_PCM_PLUGIN_ROUTE + +/* Build raw MIDI component */ +#undef BUILD_RAWMIDI + +/* Build sequencer component */ +#undef BUILD_SEQ + +/* Build UCM component */ +#undef BUILD_UCM + +/* Have clock gettime */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Have libdl */ +#undef HAVE_LIBDL + +/* Have libpthread */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the `resmgr' library (-lresmgr). */ +#undef HAVE_LIBRESMGR + +/* Have librt */ +#undef HAVE_LIBRT + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Avoid calculation in float */ +#undef HAVE_SOFT_FLOAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `uselocale' function. */ +#undef HAVE_USELOCALE + +/* Define to 1 if you have the header file. */ +#undef HAVE_WORDEXP_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* No assert debug */ +#undef NDEBUG + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Support /dev/aload* access for auto-loading */ +#undef SUPPORT_ALOAD + +/* Support resmgr with alsa-lib */ +#undef SUPPORT_RESMGR + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* directory to put tmp socket files */ +#undef TMPDIR + +/* sound library version string */ +#undef VERSION + +/* compiled with versioned symbols */ +#undef VERSIONED_SYMBOLS + +/* Toolchain Symbol Prefix */ +#undef __SYMBOL_PREFIX + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif diff --git a/include/control.h b/include/control.h new file mode 100644 index 0000000..e8f38bb --- /dev/null +++ b/include/control.h @@ -0,0 +1,588 @@ +/** + * \file include/control.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_CONTROL_H +#define __ALSA_CONTROL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Control Control Interface + * The control interface. + * See \ref control page for more details. + * \{ + */ + +/** dlsym version for interface entry callback */ +#define SND_CONTROL_DLSYM_VERSION _dlsym_control_001 + +/** IEC958 structure */ +typedef struct snd_aes_iec958 { + unsigned char status[24]; /**< AES/IEC958 channel status bits */ + unsigned char subcode[147]; /**< AES/IEC958 subcode bits */ + unsigned char pad; /**< nothing */ + unsigned char dig_subframe[4]; /**< AES/IEC958 subframe bits */ +} snd_aes_iec958_t; + +/** CTL card info container */ +typedef struct _snd_ctl_card_info snd_ctl_card_info_t; + +/** CTL element identifier container */ +typedef struct _snd_ctl_elem_id snd_ctl_elem_id_t; + +/** CTL element identifier list container */ +typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; + +/** CTL element info container */ +typedef struct _snd_ctl_elem_info snd_ctl_elem_info_t; + +/** CTL element value container */ +typedef struct _snd_ctl_elem_value snd_ctl_elem_value_t; + +/** CTL event container */ +typedef struct _snd_ctl_event snd_ctl_event_t; + +/** CTL element type */ +typedef enum _snd_ctl_elem_type { + /** Invalid type */ + SND_CTL_ELEM_TYPE_NONE = 0, + /** Boolean contents */ + SND_CTL_ELEM_TYPE_BOOLEAN, + /** Integer contents */ + SND_CTL_ELEM_TYPE_INTEGER, + /** Enumerated contents */ + SND_CTL_ELEM_TYPE_ENUMERATED, + /** Bytes contents */ + SND_CTL_ELEM_TYPE_BYTES, + /** IEC958 (S/PDIF) setting content */ + SND_CTL_ELEM_TYPE_IEC958, + /** 64-bit integer contents */ + SND_CTL_ELEM_TYPE_INTEGER64, + SND_CTL_ELEM_TYPE_LAST = SND_CTL_ELEM_TYPE_INTEGER64 +} snd_ctl_elem_type_t; + +/** CTL related interface */ +typedef enum _snd_ctl_elem_iface { + /** Card level */ + SND_CTL_ELEM_IFACE_CARD = 0, + /** Hardware dependent device */ + SND_CTL_ELEM_IFACE_HWDEP, + /** Mixer */ + SND_CTL_ELEM_IFACE_MIXER, + /** PCM */ + SND_CTL_ELEM_IFACE_PCM, + /** RawMidi */ + SND_CTL_ELEM_IFACE_RAWMIDI, + /** Timer */ + SND_CTL_ELEM_IFACE_TIMER, + /** Sequencer */ + SND_CTL_ELEM_IFACE_SEQUENCER, + SND_CTL_ELEM_IFACE_LAST = SND_CTL_ELEM_IFACE_SEQUENCER +} snd_ctl_elem_iface_t; + +/** Event class */ +typedef enum _snd_ctl_event_type { + /** Elements related event */ + SND_CTL_EVENT_ELEM = 0, + SND_CTL_EVENT_LAST = SND_CTL_EVENT_ELEM +}snd_ctl_event_type_t; + +/** Element has been removed (Warning: test this first and if set don't + * test the other masks) \hideinitializer */ +#define SND_CTL_EVENT_MASK_REMOVE (~0U) +/** Element value has been changed \hideinitializer */ +#define SND_CTL_EVENT_MASK_VALUE (1<<0) +/** Element info has been changed \hideinitializer */ +#define SND_CTL_EVENT_MASK_INFO (1<<1) +/** Element has been added \hideinitializer */ +#define SND_CTL_EVENT_MASK_ADD (1<<2) +/** Element's TLV value has been changed \hideinitializer */ +#define SND_CTL_EVENT_MASK_TLV (1<<3) + +/** CTL name helper */ +#define SND_CTL_NAME_NONE "" +/** CTL name helper */ +#define SND_CTL_NAME_PLAYBACK "Playback " +/** CTL name helper */ +#define SND_CTL_NAME_CAPTURE "Capture " + +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_NONE "" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_SWITCH "Switch" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_VOLUME "Volume" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_DEFAULT "Default" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_MASK "Mask" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_CON_MASK "Con Mask" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_PRO_MASK "Pro Mask" +/** CTL name helper */ +#define SND_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" +/** Element name for IEC958 (S/PDIF) */ +#define SND_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SND_CTL_NAME_##direction SND_CTL_NAME_IEC958_##what + +/** Mask for the major Power State identifier */ +#define SND_CTL_POWER_MASK 0xff00 +/** ACPI/PCI Power State D0 */ +#define SND_CTL_POWER_D0 0x0000 +/** ACPI/PCI Power State D1 */ +#define SND_CTL_POWER_D1 0x0100 +/** ACPI/PCI Power State D2 */ +#define SND_CTL_POWER_D2 0x0200 +/** ACPI/PCI Power State D3 */ +#define SND_CTL_POWER_D3 0x0300 +/** ACPI/PCI Power State D3hot */ +#define SND_CTL_POWER_D3hot (SND_CTL_POWER_D3|0x0000) +/** ACPI/PCI Power State D3cold */ +#define SND_CTL_POWER_D3cold (SND_CTL_POWER_D3|0x0001) + +/** TLV type - Container */ +#define SND_CTL_TLVT_CONTAINER 0x0000 +/** TLV type - basic dB scale */ +#define SND_CTL_TLVT_DB_SCALE 0x0001 +/** TLV type - linear volume */ +#define SND_CTL_TLVT_DB_LINEAR 0x0002 +/** TLV type - dB range container */ +#define SND_CTL_TLVT_DB_RANGE 0x0003 +/** TLV type - dB scale specified by min/max values */ +#define SND_CTL_TLVT_DB_MINMAX 0x0004 +/** TLV type - dB scale specified by min/max values (with mute) */ +#define SND_CTL_TLVT_DB_MINMAX_MUTE 0x0005 + +/** Mute state */ +#define SND_CTL_TLV_DB_GAIN_MUTE -9999999 + +/** CTL type */ +typedef enum _snd_ctl_type { + /** Kernel level CTL */ + SND_CTL_TYPE_HW, + /** Shared memory client CTL */ + SND_CTL_TYPE_SHM, + /** INET client CTL (not yet implemented) */ + SND_CTL_TYPE_INET, + /** External control plugin */ + SND_CTL_TYPE_EXT +} snd_ctl_type_t; + +/** Non blocking mode (flag for open mode) \hideinitializer */ +#define SND_CTL_NONBLOCK 0x0001 + +/** Async notification (flag for open mode) \hideinitializer */ +#define SND_CTL_ASYNC 0x0002 + +/** Read only (flag for open mode) \hideinitializer */ +#define SND_CTL_READONLY 0x0004 + +/** CTL handle */ +typedef struct _snd_ctl snd_ctl_t; + +/** Don't destroy the ctl handle when close */ +#define SND_SCTL_NOFREE 0x0001 + +/** SCTL type */ +typedef struct _snd_sctl snd_sctl_t; + +int snd_card_load(int card); +int snd_card_next(int *card); +int snd_card_get_index(const char *name); +int snd_card_get_name(int card, char **name); +int snd_card_get_longname(int card, char **name); + +int snd_device_name_hint(int card, const char *iface, void ***hints); +int snd_device_name_free_hint(void **hints); +char *snd_device_name_get_hint(const void *hint, const char *id); + +int snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode); +int snd_ctl_open_lconf(snd_ctl_t **ctl, const char *name, int mode, snd_config_t *lconf); +int snd_ctl_close(snd_ctl_t *ctl); +int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock); +int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl, + snd_async_callback_t callback, void *private_data); +snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler); +int snd_ctl_poll_descriptors_count(snd_ctl_t *ctl); +int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int space); +int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe); +int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info); +int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list); +int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info); +int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *value); +int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *value); +int snd_ctl_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); +int snd_ctl_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); +int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int *tlv, unsigned int tlv_size); +int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + const unsigned int *tlv); +int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + const unsigned int *tlv); +#ifdef __ALSA_HWDEP_H +int snd_ctl_hwdep_next_device(snd_ctl_t *ctl, int * device); +int snd_ctl_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info); +#endif +#ifdef __ALSA_PCM_H +int snd_ctl_pcm_next_device(snd_ctl_t *ctl, int *device); +int snd_ctl_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info); +int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev); +#endif +#ifdef __ALSA_RAWMIDI_H +int snd_ctl_rawmidi_next_device(snd_ctl_t *ctl, int * device); +int snd_ctl_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info); +int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev); +#endif +int snd_ctl_set_power_state(snd_ctl_t *ctl, unsigned int state); +int snd_ctl_get_power_state(snd_ctl_t *ctl, unsigned int *state); + +int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_event_t *event); +int snd_ctl_wait(snd_ctl_t *ctl, int timeout); +const char *snd_ctl_name(snd_ctl_t *ctl); +snd_ctl_type_t snd_ctl_type(snd_ctl_t *ctl); + +const char *snd_ctl_elem_type_name(snd_ctl_elem_type_t type); +const char *snd_ctl_elem_iface_name(snd_ctl_elem_iface_t iface); +const char *snd_ctl_event_type_name(snd_ctl_event_type_t type); + +unsigned int snd_ctl_event_elem_get_mask(const snd_ctl_event_t *obj); +unsigned int snd_ctl_event_elem_get_numid(const snd_ctl_event_t *obj); +void snd_ctl_event_elem_get_id(const snd_ctl_event_t *obj, snd_ctl_elem_id_t *ptr); +snd_ctl_elem_iface_t snd_ctl_event_elem_get_interface(const snd_ctl_event_t *obj); +unsigned int snd_ctl_event_elem_get_device(const snd_ctl_event_t *obj); +unsigned int snd_ctl_event_elem_get_subdevice(const snd_ctl_event_t *obj); +const char *snd_ctl_event_elem_get_name(const snd_ctl_event_t *obj); +unsigned int snd_ctl_event_elem_get_index(const snd_ctl_event_t *obj); + +int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries); +void snd_ctl_elem_list_free_space(snd_ctl_elem_list_t *obj); + +char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id); +int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str); +int snd_ctl_ascii_value_parse(snd_ctl_t *handle, + snd_ctl_elem_value_t *dst, + snd_ctl_elem_info_t *info, + const char *value); + +size_t snd_ctl_elem_id_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_ctl_elem_id_t using standard alloca + * \param ptr returned pointer + */ +#define snd_ctl_elem_id_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_id) +int snd_ctl_elem_id_malloc(snd_ctl_elem_id_t **ptr); +void snd_ctl_elem_id_free(snd_ctl_elem_id_t *obj); +void snd_ctl_elem_id_clear(snd_ctl_elem_id_t *obj); +void snd_ctl_elem_id_copy(snd_ctl_elem_id_t *dst, const snd_ctl_elem_id_t *src); +unsigned int snd_ctl_elem_id_get_numid(const snd_ctl_elem_id_t *obj); +snd_ctl_elem_iface_t snd_ctl_elem_id_get_interface(const snd_ctl_elem_id_t *obj); +unsigned int snd_ctl_elem_id_get_device(const snd_ctl_elem_id_t *obj); +unsigned int snd_ctl_elem_id_get_subdevice(const snd_ctl_elem_id_t *obj); +const char *snd_ctl_elem_id_get_name(const snd_ctl_elem_id_t *obj); +unsigned int snd_ctl_elem_id_get_index(const snd_ctl_elem_id_t *obj); +void snd_ctl_elem_id_set_numid(snd_ctl_elem_id_t *obj, unsigned int val); +void snd_ctl_elem_id_set_interface(snd_ctl_elem_id_t *obj, snd_ctl_elem_iface_t val); +void snd_ctl_elem_id_set_device(snd_ctl_elem_id_t *obj, unsigned int val); +void snd_ctl_elem_id_set_subdevice(snd_ctl_elem_id_t *obj, unsigned int val); +void snd_ctl_elem_id_set_name(snd_ctl_elem_id_t *obj, const char *val); +void snd_ctl_elem_id_set_index(snd_ctl_elem_id_t *obj, unsigned int val); + +size_t snd_ctl_card_info_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_ctl_card_info_t using standard alloca + * \param ptr returned pointer + */ +#define snd_ctl_card_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_card_info) +int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr); +void snd_ctl_card_info_free(snd_ctl_card_info_t *obj); +void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj); +void snd_ctl_card_info_copy(snd_ctl_card_info_t *dst, const snd_ctl_card_info_t *src); +int snd_ctl_card_info_get_card(const snd_ctl_card_info_t *obj); +const char *snd_ctl_card_info_get_id(const snd_ctl_card_info_t *obj); +const char *snd_ctl_card_info_get_driver(const snd_ctl_card_info_t *obj); +const char *snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj); +const char *snd_ctl_card_info_get_longname(const snd_ctl_card_info_t *obj); +const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj); +const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj); + +size_t snd_ctl_event_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_ctl_event_t using standard alloca + * \param ptr returned pointer + */ +#define snd_ctl_event_alloca(ptr) __snd_alloca(ptr, snd_ctl_event) +int snd_ctl_event_malloc(snd_ctl_event_t **ptr); +void snd_ctl_event_free(snd_ctl_event_t *obj); +void snd_ctl_event_clear(snd_ctl_event_t *obj); +void snd_ctl_event_copy(snd_ctl_event_t *dst, const snd_ctl_event_t *src); +snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj); + +size_t snd_ctl_elem_list_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_ctl_elem_list_t using standard alloca + * \param ptr returned pointer + */ +#define snd_ctl_elem_list_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_list) +int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr); +void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj); +void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj); +void snd_ctl_elem_list_copy(snd_ctl_elem_list_t *dst, const snd_ctl_elem_list_t *src); +void snd_ctl_elem_list_set_offset(snd_ctl_elem_list_t *obj, unsigned int val); +unsigned int snd_ctl_elem_list_get_used(const snd_ctl_elem_list_t *obj); +unsigned int snd_ctl_elem_list_get_count(const snd_ctl_elem_list_t *obj); +void snd_ctl_elem_list_get_id(const snd_ctl_elem_list_t *obj, unsigned int idx, snd_ctl_elem_id_t *ptr); +unsigned int snd_ctl_elem_list_get_numid(const snd_ctl_elem_list_t *obj, unsigned int idx); +snd_ctl_elem_iface_t snd_ctl_elem_list_get_interface(const snd_ctl_elem_list_t *obj, unsigned int idx); +unsigned int snd_ctl_elem_list_get_device(const snd_ctl_elem_list_t *obj, unsigned int idx); +unsigned int snd_ctl_elem_list_get_subdevice(const snd_ctl_elem_list_t *obj, unsigned int idx); +const char *snd_ctl_elem_list_get_name(const snd_ctl_elem_list_t *obj, unsigned int idx); +unsigned int snd_ctl_elem_list_get_index(const snd_ctl_elem_list_t *obj, unsigned int idx); + +size_t snd_ctl_elem_info_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_ctl_elem_info_t using standard alloca + * \param ptr returned pointer + */ +#define snd_ctl_elem_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_info) +int snd_ctl_elem_info_malloc(snd_ctl_elem_info_t **ptr); +void snd_ctl_elem_info_free(snd_ctl_elem_info_t *obj); +void snd_ctl_elem_info_clear(snd_ctl_elem_info_t *obj); +void snd_ctl_elem_info_copy(snd_ctl_elem_info_t *dst, const snd_ctl_elem_info_t *src); +snd_ctl_elem_type_t snd_ctl_elem_info_get_type(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_readable(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_writable(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_volatile(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_inactive(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_locked(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_tlv_readable(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_tlv_writable(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_tlv_commandable(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_owner(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_is_user(const snd_ctl_elem_info_t *obj); +pid_t snd_ctl_elem_info_get_owner(const snd_ctl_elem_info_t *obj); +unsigned int snd_ctl_elem_info_get_count(const snd_ctl_elem_info_t *obj); +long snd_ctl_elem_info_get_min(const snd_ctl_elem_info_t *obj); +long snd_ctl_elem_info_get_max(const snd_ctl_elem_info_t *obj); +long snd_ctl_elem_info_get_step(const snd_ctl_elem_info_t *obj); +long long snd_ctl_elem_info_get_min64(const snd_ctl_elem_info_t *obj); +long long snd_ctl_elem_info_get_max64(const snd_ctl_elem_info_t *obj); +long long snd_ctl_elem_info_get_step64(const snd_ctl_elem_info_t *obj); +unsigned int snd_ctl_elem_info_get_items(const snd_ctl_elem_info_t *obj); +void snd_ctl_elem_info_set_item(snd_ctl_elem_info_t *obj, unsigned int val); +const char *snd_ctl_elem_info_get_item_name(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_get_dimensions(const snd_ctl_elem_info_t *obj); +int snd_ctl_elem_info_get_dimension(const snd_ctl_elem_info_t *obj, unsigned int idx); +void snd_ctl_elem_info_get_id(const snd_ctl_elem_info_t *obj, snd_ctl_elem_id_t *ptr); +unsigned int snd_ctl_elem_info_get_numid(const snd_ctl_elem_info_t *obj); +snd_ctl_elem_iface_t snd_ctl_elem_info_get_interface(const snd_ctl_elem_info_t *obj); +unsigned int snd_ctl_elem_info_get_device(const snd_ctl_elem_info_t *obj); +unsigned int snd_ctl_elem_info_get_subdevice(const snd_ctl_elem_info_t *obj); +const char *snd_ctl_elem_info_get_name(const snd_ctl_elem_info_t *obj); +unsigned int snd_ctl_elem_info_get_index(const snd_ctl_elem_info_t *obj); +void snd_ctl_elem_info_set_id(snd_ctl_elem_info_t *obj, const snd_ctl_elem_id_t *ptr); +void snd_ctl_elem_info_set_numid(snd_ctl_elem_info_t *obj, unsigned int val); +void snd_ctl_elem_info_set_interface(snd_ctl_elem_info_t *obj, snd_ctl_elem_iface_t val); +void snd_ctl_elem_info_set_device(snd_ctl_elem_info_t *obj, unsigned int val); +void snd_ctl_elem_info_set_subdevice(snd_ctl_elem_info_t *obj, unsigned int val); +void snd_ctl_elem_info_set_name(snd_ctl_elem_info_t *obj, const char *val); +void snd_ctl_elem_info_set_index(snd_ctl_elem_info_t *obj, unsigned int val); + +int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, long imin, long imax, long istep); +int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, long long imin, long long imax, long long istep); +int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count); +int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); +int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); + +size_t snd_ctl_elem_value_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_ctl_elem_value_t using standard alloca + * \param ptr returned pointer + */ +#define snd_ctl_elem_value_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_value) +int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr); +void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj); +void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj); +void snd_ctl_elem_value_copy(snd_ctl_elem_value_t *dst, const snd_ctl_elem_value_t *src); +int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, const snd_ctl_elem_value_t *right); +void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_t *ptr); +unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj); +snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t *obj); +unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj); +unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj); +const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj); +unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj); +void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr); +void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val); +void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_iface_t val); +void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val); +void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int val); +void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val); +void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val); +int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx); +long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx); +long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx); +unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx); +unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx); +void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val); +void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val); +void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val); +void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val); +void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val); +void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size); +const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj); +void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr); +void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr); + +int snd_tlv_parse_dB_info(unsigned int *tlv, unsigned int tlv_size, + unsigned int **db_tlvp); +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max); +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain); +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir); +int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long *min, long *max); +int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long volume, long *db_gain); +int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long db_gain, long *value, int xdir); + +/** + * \defgroup HControl High level Control Interface + * \ingroup Control + * The high level control interface. + * See \ref hcontrol page for more details. + * \{ + */ + +/** HCTL element handle */ +typedef struct _snd_hctl_elem snd_hctl_elem_t; + +/** HCTL handle */ +typedef struct _snd_hctl snd_hctl_t; + +/** + * \brief Compare function for sorting HCTL elements + * \param e1 First element + * \param e2 Second element + * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 + */ +typedef int (*snd_hctl_compare_t)(const snd_hctl_elem_t *e1, + const snd_hctl_elem_t *e2); +int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, + const snd_hctl_elem_t *c2); +/** + * \brief HCTL callback function + * \param hctl HCTL handle + * \param mask event mask + * \param elem related HCTL element (if any) + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_hctl_callback_t)(snd_hctl_t *hctl, + unsigned int mask, + snd_hctl_elem_t *elem); +/** + * \brief HCTL element callback function + * \param elem HCTL element + * \param mask event mask + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_hctl_elem_callback_t)(snd_hctl_elem_t *elem, + unsigned int mask); + +int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode); +int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl); +int snd_hctl_close(snd_hctl_t *hctl); +int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock); +int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl); +int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space); +int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +unsigned int snd_hctl_get_count(snd_hctl_t *hctl); +int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort); +snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl); +snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl); +snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id); +void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback); +void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data); +void *snd_hctl_get_callback_private(snd_hctl_t *hctl); +int snd_hctl_load(snd_hctl_t *hctl); +int snd_hctl_free(snd_hctl_t *hctl); +int snd_hctl_handle_events(snd_hctl_t *hctl); +const char *snd_hctl_name(snd_hctl_t *hctl); +int snd_hctl_wait(snd_hctl_t *hctl, int timeout); +snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl); + +snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem); +snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem); +int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info); +int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); +int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); +int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size); +int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv); +int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv); + +snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem); + +void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr); +unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj); +snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj); +unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj); +unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj); +const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj); +unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj); +void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val); +void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj); +void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val); + +/** \} */ + +/** \} */ + +/** + * \defgroup SControl Setup Control Interface + * \ingroup Control + * The setup control interface - set or modify control elements from a configuration file. + * \{ + */ + +int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config, + snd_config_t *private_data, int mode); +int snd_sctl_free(snd_sctl_t *handle); +int snd_sctl_install(snd_sctl_t *handle); +int snd_sctl_remove(snd_sctl_t *handle); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_CONTROL_H */ diff --git a/include/control_external.h b/include/control_external.h new file mode 100644 index 0000000..7c066cf --- /dev/null +++ b/include/control_external.h @@ -0,0 +1,265 @@ +/** + * \file include/control_external.h + * \brief External control plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * External control plugin SDK. + */ + +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __ALSA_CONTROL_EXTERNAL_H +#define __ALSA_CONTROL_EXTERNAL_H + +#include "control.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup CtlPlugin_SDK External Control Plugin SDK + * \{ + */ + +/** + * Define the object entry for external control plugins + */ +#define SND_CTL_PLUGIN_ENTRY(name) _snd_ctl_##name##_open + +/** + * Define the symbols of the given control plugin with versions + */ +#define SND_CTL_PLUGIN_SYMBOL(name) SND_DLSYM_BUILD_VERSION(SND_CTL_PLUGIN_ENTRY(name), SND_CONTROL_DLSYM_VERSION); + +/** + * Define the control plugin + */ +#define SND_CTL_PLUGIN_DEFINE_FUNC(plugin) \ +int SND_CTL_PLUGIN_ENTRY(plugin) (snd_ctl_t **handlep, const char *name,\ + snd_config_t *root, snd_config_t *conf, int mode) + +/** External control plugin handle */ +typedef struct snd_ctl_ext snd_ctl_ext_t; +/** Callback table of control ext */ +typedef struct snd_ctl_ext_callback snd_ctl_ext_callback_t; +/** Key to access a control pointer */ +typedef unsigned long snd_ctl_ext_key_t; + +/* + * Protocol version + */ +#define SND_CTL_EXT_VERSION_MAJOR 1 /**< Protocol major version */ +#define SND_CTL_EXT_VERSION_MINOR 0 /**< Protocol minor version */ +#define SND_CTL_EXT_VERSION_TINY 0 /**< Protocol tiny version */ +/** + * external plugin protocol version + */ +#define SND_CTL_EXT_VERSION ((SND_CTL_EXT_VERSION_MAJOR<<16) |\ + (SND_CTL_EXT_VERSION_MINOR<<8) |\ + (SND_CTL_EXT_VERSION_TINY)) + +/** Handle of control ext */ +struct snd_ctl_ext { + /** + * protocol version; #SND_CTL_EXT_VERSION must be filled here + * before calling #snd_ctl_ext_create() + */ + unsigned int version; + /** + * Index of this card; must be filled before calling #snd_ctl_ext_create() + */ + int card_idx; + /** + * ID string of this card; must be filled before calling #snd_ctl_ext_create() + */ + char id[16]; + /** + * Driver name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char driver[16]; + /** + * short name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char name[32]; + /** + * Long name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char longname[80]; + /** + * Mixer name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char mixername[80]; + /** + * poll descriptor + */ + int poll_fd; + + /** + * callbacks of this plugin; must be filled before calling #snd_pcm_ioplug_create() + */ + const snd_ctl_ext_callback_t *callback; + /** + * private data, which can be used freely in the driver callbacks + */ + void *private_data; + /** + * control handle filled by #snd_ctl_ext_create() + */ + snd_ctl_t *handle; + + int nonblock; /**< non-block mode; read-only */ + int subscribed; /**< events subscribed; read-only */ +}; + +/** Callback table of ext */ +struct snd_ctl_ext_callback { + /** + * close the control handle; optional + */ + void (*close)(snd_ctl_ext_t *ext); + /** + * return the total number of elements; required + */ + int (*elem_count)(snd_ctl_ext_t *ext); + /** + * return the element id of the given offset (array index); required + */ + int (*elem_list)(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id); + /** + * convert the element id to a search key; required + */ + snd_ctl_ext_key_t (*find_elem)(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id); + /** + * the destructor of the key; optional + */ + void (*free_key)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key); + /** + * get the attribute of the element; required + */ + int (*get_attribute)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + int *type, unsigned int *acc, unsigned int *count); + /** + * get the element information of integer type + */ + int (*get_integer_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + long *imin, long *imax, long *istep); + /** + * get the element information of integer64 type + */ + int (*get_integer64_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + int64_t *imin, int64_t *imax, int64_t *istep); + /** + * get the element information of enumerated type + */ + int (*get_enumerated_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); + /** + * get the name of the enumerated item + */ + int (*get_enumerated_name)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int item, + char *name, size_t name_max_len); + /** + * read the current values of integer type + */ + int (*read_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value); + /** + * read the current values of integer64 type + */ + int (*read_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value); + /** + * read the current values of enumerated type + */ + int (*read_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); + /** + * read the current values of bytes type + */ + int (*read_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, + size_t max_bytes); + /** + * read the current values of iec958 type + */ + int (*read_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958); + /** + * update the current values of integer type with the given values + */ + int (*write_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value); + /** + * update the current values of integer64 type with the given values + */ + int (*write_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value); + /** + * update the current values of enumerated type with the given values + */ + int (*write_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); + /** + * update the current values of bytes type with the given values + */ + int (*write_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, + size_t max_bytes); + /** + * update the current values of iec958 type with the given values + */ + int (*write_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958); + /** + * subscribe/unsubscribe the event notification; optional + */ + void (*subscribe_events)(snd_ctl_ext_t *ext, int subscribe); + /** + * read a pending notification event; optional + */ + int (*read_event)(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, unsigned int *event_mask); + /** + * return the number of poll descriptors; optional + */ + int (*poll_descriptors_count)(snd_ctl_ext_t *ext); + /** + * fill the poll descriptors; optional + */ + int (*poll_descriptors)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int space); + /** + * mangle the revents of poll descriptors + */ + int (*poll_revents)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +}; + +/** + * The access type bits stored in get_attribute callback + */ +typedef enum snd_ctl_ext_access { + SND_CTL_EXT_ACCESS_READ = (1<<0), + SND_CTL_EXT_ACCESS_WRITE = (1<<1), + SND_CTL_EXT_ACCESS_READWRITE = (3<<0), + SND_CTL_EXT_ACCESS_VOLATILE = (1<<2), + SND_CTL_EXT_ACCESS_INACTIVE = (1<<8), +} snd_ctl_ext_access_t; + +/** + * find_elem callback returns this if no matching control element is found + */ +#define SND_CTL_EXT_KEY_NOT_FOUND (snd_ctl_ext_key_t)(-1) + +int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode); +int snd_ctl_ext_delete(snd_ctl_ext_t *ext); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_CONTROL_EXTERNAL_H */ diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..6d27083 --- /dev/null +++ b/include/error.h @@ -0,0 +1,78 @@ +/** + * \file include/error.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_ERROR_H +#define __ALSA_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Error Error handling + * Error handling macros and functions. + * \{ + */ + +#define SND_ERROR_BEGIN 500000 /**< Lower boundary of sound error codes. */ +#define SND_ERROR_INCOMPATIBLE_VERSION (SND_ERROR_BEGIN+0) /**< Kernel/library protocols are not compatible. */ +#define SND_ERROR_ALISP_NIL (SND_ERROR_BEGIN+1) /**< Lisp encountered an error during acall. */ + +const char *snd_strerror(int errnum); + +/** + * \brief Error handler callback. + * \param file Source file name. + * \param line Line number. + * \param function Function name. + * \param err Value of \c errno, or 0 if not relevant. + * \param fmt \c printf(3) format. + * \param ... \c printf(3) arguments. + * + * A function of this type is called by the ALSA library when an error occurs. + * This function usually shows the message on the screen, and/or logs it. + */ +typedef void (*snd_lib_error_handler_t)(const char *file, int line, const char *function, int err, const char *fmt, ...) /* __attribute__ ((format (printf, 5, 6))) */; +extern snd_lib_error_handler_t snd_lib_error; +extern int snd_lib_error_set_handler(snd_lib_error_handler_t handler); + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) +#define SNDERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__) /**< Shows a sound error message. */ +#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__) /**< Shows a system error message (related to \c errno). */ +#else +#define SNDERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args) /**< Shows a sound error message. */ +#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args) /**< Shows a system error message (related to \c errno). */ +#endif + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_ERROR_H */ + diff --git a/include/global.h b/include/global.h new file mode 100644 index 0000000..3e3680f --- /dev/null +++ b/include/global.h @@ -0,0 +1,159 @@ +/** + * \file include/global.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_GLOBAL_H_ +#define __ALSA_GLOBAL_H_ + +/* for timeval and timespec */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Global Global defines and functions + * Global defines and functions. + * \par + * The ALSA library implementation uses these macros and functions. + * Most applications probably do not need them. + * \{ + */ + +const char *snd_asoundlib_version(void); + +#ifndef ATTRIBUTE_UNUSED +/** do not print warning (gcc) when function parameter is not used */ +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +#ifdef PIC /* dynamic build */ + +/** \hideinitializer \brief Helper macro for #SND_DLSYM_BUILD_VERSION. */ +#define __SND_DLSYM_VERSION(name, version) _ ## name ## version +/** + * \hideinitializer + * \brief Appends the build version to the name of a versioned dynamic symbol. + */ +#define SND_DLSYM_BUILD_VERSION(name, version) char __SND_DLSYM_VERSION(name, version); + +#else /* static build */ + +struct snd_dlsym_link { + struct snd_dlsym_link *next; + const char *dlsym_name; + const void *dlsym_ptr; +}; + +extern struct snd_dlsym_link *snd_dlsym_start; + +/** \hideinitializer \brief Helper macro for #SND_DLSYM_BUILD_VERSION. */ +#define __SND_DLSYM_VERSION(prefix, name, version) _ ## prefix ## name ## version +/** + * \hideinitializer + * \brief Appends the build version to the name of a versioned dynamic symbol. + */ +#define SND_DLSYM_BUILD_VERSION(name, version) \ + static struct snd_dlsym_link __SND_DLSYM_VERSION(snd_dlsym_, name, version); \ + void __SND_DLSYM_VERSION(snd_dlsym_constructor_, name, version) (void) __attribute__ ((constructor)); \ + void __SND_DLSYM_VERSION(snd_dlsym_constructor_, name, version) (void) { \ + __SND_DLSYM_VERSION(snd_dlsym_, name, version).next = snd_dlsym_start; \ + __SND_DLSYM_VERSION(snd_dlsym_, name, version).dlsym_name = # name; \ + __SND_DLSYM_VERSION(snd_dlsym_, name, version).dlsym_ptr = (void *)&name; \ + snd_dlsym_start = &__SND_DLSYM_VERSION(snd_dlsym_, name, version); \ + } + +#endif + +#ifndef __STRING +/** \brief Return 'x' argument as string */ +#define __STRING(x) #x +#endif + +/** \brief Returns the version of a dynamic symbol as a string. */ +#define SND_DLSYM_VERSION(version) __STRING(version) + +void *snd_dlopen(const char *file, int mode); +void *snd_dlsym(void *handle, const char *name, const char *version); +int snd_dlclose(void *handle); + + +/** \brief alloca helper macro. */ +#define __snd_alloca(ptr,type) do { *ptr = (type##_t *) alloca(type##_sizeof()); memset(*ptr, 0, type##_sizeof()); } while (0) + +/** + * \brief Internal structure for an async notification client handler. + * + * The ALSA library uses a pointer to this structure as a handle to an async + * notification object. Applications don't access its contents directly. + */ +typedef struct _snd_async_handler snd_async_handler_t; + +/** + * \brief Async notification callback. + * + * See the #snd_async_add_handler function for details. + */ +typedef void (*snd_async_callback_t)(snd_async_handler_t *handler); + +int snd_async_add_handler(snd_async_handler_t **handler, int fd, + snd_async_callback_t callback, void *private_data); +int snd_async_del_handler(snd_async_handler_t *handler); +int snd_async_handler_get_fd(snd_async_handler_t *handler); +int snd_async_handler_get_signo(snd_async_handler_t *handler); +void *snd_async_handler_get_callback_private(snd_async_handler_t *handler); + +struct snd_shm_area *snd_shm_area_create(int shmid, void *ptr); +struct snd_shm_area *snd_shm_area_share(struct snd_shm_area *area); +int snd_shm_area_destroy(struct snd_shm_area *area); + +int snd_user_file(const char *file, char **result); + +#if !defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE) +struct timeval { + time_t tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif + +/** Timestamp */ +typedef struct timeval snd_timestamp_t; +/** Hi-res timestamp */ +typedef struct timespec snd_htimestamp_t; + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_GLOBAL_H */ diff --git a/include/hwdep.h b/include/hwdep.h new file mode 100644 index 0000000..ab12822 --- /dev/null +++ b/include/hwdep.h @@ -0,0 +1,160 @@ +/** + * \file include/hwdep.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_HWDEP_H +#define __ALSA_HWDEP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup HwDep Hardware Dependant Interface + * The Hardware Dependant Interface. + * \{ + */ + +/** dlsym version for interface entry callback */ +#define SND_HWDEP_DLSYM_VERSION _dlsym_hwdep_001 + +/** HwDep information container */ +typedef struct _snd_hwdep_info snd_hwdep_info_t; + +/** HwDep DSP status container */ +typedef struct _snd_hwdep_dsp_status snd_hwdep_dsp_status_t; + +/** HwDep DSP image container */ +typedef struct _snd_hwdep_dsp_image snd_hwdep_dsp_image_t; + +/** HwDep interface */ +typedef enum _snd_hwdep_iface { + SND_HWDEP_IFACE_OPL2 = 0, /**< OPL2 raw driver */ + SND_HWDEP_IFACE_OPL3, /**< OPL3 raw driver */ + SND_HWDEP_IFACE_OPL4, /**< OPL4 raw driver */ + SND_HWDEP_IFACE_SB16CSP, /**< SB16CSP driver */ + SND_HWDEP_IFACE_EMU10K1, /**< EMU10K1 driver */ + SND_HWDEP_IFACE_YSS225, /**< YSS225 driver */ + SND_HWDEP_IFACE_ICS2115, /**< ICS2115 driver */ + SND_HWDEP_IFACE_SSCAPE, /**< Ensoniq SoundScape ISA card (MC68EC000) */ + SND_HWDEP_IFACE_VX, /**< Digigram VX cards */ + SND_HWDEP_IFACE_MIXART, /**< Digigram miXart cards */ + SND_HWDEP_IFACE_USX2Y, /**< Tascam US122, US224 & US428 usb */ + SND_HWDEP_IFACE_EMUX_WAVETABLE, /**< EmuX wavetable */ + SND_HWDEP_IFACE_BLUETOOTH, /**< Bluetooth audio */ + SND_HWDEP_IFACE_USX2Y_PCM, /**< Tascam US122, US224 & US428 raw USB PCM */ + SND_HWDEP_IFACE_PCXHR, /**< Digigram PCXHR */ + SND_HWDEP_IFACE_SB_RC, /**< SB Extigy/Audigy2NX remote control */ + + SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_SB_RC /**< last known hwdep interface */ +} snd_hwdep_iface_t; + +/** open for reading */ +#define SND_HWDEP_OPEN_READ (O_RDONLY) +/** open for writing */ +#define SND_HWDEP_OPEN_WRITE (O_WRONLY) +/** open for reading and writing */ +#define SND_HWDEP_OPEN_DUPLEX (O_RDWR) +/** open mode flag: open in nonblock mode */ +#define SND_HWDEP_OPEN_NONBLOCK (O_NONBLOCK) + +/** HwDep handle type */ +typedef enum _snd_hwdep_type { + /** Kernel level HwDep */ + SND_HWDEP_TYPE_HW, + /** Shared memory client HwDep (not yet implemented) */ + SND_HWDEP_TYPE_SHM, + /** INET client HwDep (not yet implemented) */ + SND_HWDEP_TYPE_INET +} snd_hwdep_type_t; + +/** HwDep handle */ +typedef struct _snd_hwdep snd_hwdep_t; + +int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode); +int snd_hwdep_close(snd_hwdep_t *hwdep); +int snd_hwdep_poll_descriptors(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int space); +int snd_hwdep_poll_descriptors_revents(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_hwdep_nonblock(snd_hwdep_t *hwdep, int nonblock); +int snd_hwdep_info(snd_hwdep_t *hwdep, snd_hwdep_info_t * info); +int snd_hwdep_dsp_status(snd_hwdep_t *hwdep, snd_hwdep_dsp_status_t *status); +int snd_hwdep_dsp_load(snd_hwdep_t *hwdep, snd_hwdep_dsp_image_t *block); +int snd_hwdep_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg); +ssize_t snd_hwdep_write(snd_hwdep_t *hwdep, const void *buffer, size_t size); +ssize_t snd_hwdep_read(snd_hwdep_t *hwdep, void *buffer, size_t size); + +size_t snd_hwdep_info_sizeof(void); +/** allocate #snd_hwdep_info_t container on stack */ +#define snd_hwdep_info_alloca(ptr) __snd_alloca(ptr, snd_hwdep_info) +int snd_hwdep_info_malloc(snd_hwdep_info_t **ptr); +void snd_hwdep_info_free(snd_hwdep_info_t *obj); +void snd_hwdep_info_copy(snd_hwdep_info_t *dst, const snd_hwdep_info_t *src); + +unsigned int snd_hwdep_info_get_device(const snd_hwdep_info_t *obj); +int snd_hwdep_info_get_card(const snd_hwdep_info_t *obj); +const char *snd_hwdep_info_get_id(const snd_hwdep_info_t *obj); +const char *snd_hwdep_info_get_name(const snd_hwdep_info_t *obj); +snd_hwdep_iface_t snd_hwdep_info_get_iface(const snd_hwdep_info_t *obj); +void snd_hwdep_info_set_device(snd_hwdep_info_t *obj, unsigned int val); + +size_t snd_hwdep_dsp_status_sizeof(void); +/** allocate #snd_hwdep_dsp_status_t container on stack */ +#define snd_hwdep_dsp_status_alloca(ptr) __snd_alloca(ptr, snd_hwdep_dsp_status) +int snd_hwdep_dsp_status_malloc(snd_hwdep_dsp_status_t **ptr); +void snd_hwdep_dsp_status_free(snd_hwdep_dsp_status_t *obj); +void snd_hwdep_dsp_status_copy(snd_hwdep_dsp_status_t *dst, const snd_hwdep_dsp_status_t *src); + +unsigned int snd_hwdep_dsp_status_get_version(const snd_hwdep_dsp_status_t *obj); +const char *snd_hwdep_dsp_status_get_id(const snd_hwdep_dsp_status_t *obj); +unsigned int snd_hwdep_dsp_status_get_num_dsps(const snd_hwdep_dsp_status_t *obj); +unsigned int snd_hwdep_dsp_status_get_dsp_loaded(const snd_hwdep_dsp_status_t *obj); +unsigned int snd_hwdep_dsp_status_get_chip_ready(const snd_hwdep_dsp_status_t *obj); + +size_t snd_hwdep_dsp_image_sizeof(void); +/** allocate #snd_hwdep_dsp_image_t container on stack */ +#define snd_hwdep_dsp_image_alloca(ptr) __snd_alloca(ptr, snd_hwdep_dsp_image) +int snd_hwdep_dsp_image_malloc(snd_hwdep_dsp_image_t **ptr); +void snd_hwdep_dsp_image_free(snd_hwdep_dsp_image_t *obj); +void snd_hwdep_dsp_image_copy(snd_hwdep_dsp_image_t *dst, const snd_hwdep_dsp_image_t *src); + +unsigned int snd_hwdep_dsp_image_get_index(const snd_hwdep_dsp_image_t *obj); +const char *snd_hwdep_dsp_image_get_name(const snd_hwdep_dsp_image_t *obj); +const void *snd_hwdep_dsp_image_get_image(const snd_hwdep_dsp_image_t *obj); +size_t snd_hwdep_dsp_image_get_length(const snd_hwdep_dsp_image_t *obj); + +void snd_hwdep_dsp_image_set_index(snd_hwdep_dsp_image_t *obj, unsigned int _index); +void snd_hwdep_dsp_image_set_name(snd_hwdep_dsp_image_t *obj, const char *name); +void snd_hwdep_dsp_image_set_image(snd_hwdep_dsp_image_t *obj, void *buffer); +void snd_hwdep_dsp_image_set_length(snd_hwdep_dsp_image_t *obj, size_t length); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_HWDEP_H */ + diff --git a/include/iatomic.h b/include/iatomic.h new file mode 100644 index 0000000..e92dbfd --- /dev/null +++ b/include/iatomic.h @@ -0,0 +1,1198 @@ +#ifndef __ALSA_IATOMIC_H +#define __ALSA_IATOMIC_H + +#if defined(__i386__) || defined(__x86_64__) + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ + +#define ATOMIC_SMP_LOCK "lock ; " + +/* + * Make sure gcc doesn't try to be clever and move things around + * on us. We need to use _exactly_ the address the user gave us, + * not some alias that contains the same information. + */ +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_read(v) ((v)->counter) + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_set(v,i) (((v)->counter) = (i)) + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. Note that the guaranteed useful range + * of an atomic_t is only 24 bits. + */ +static __inline__ void atomic_add(int i, atomic_t *v) +{ + __asm__ __volatile__( + ATOMIC_SMP_LOCK "addl %1,%0" + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); +} + +/** + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ void atomic_sub(int i, atomic_t *v) +{ + __asm__ __volatile__( + ATOMIC_SMP_LOCK "subl %1,%0" + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ int atomic_sub_and_test(int i, atomic_t *v) +{ + unsigned char c; + + __asm__ __volatile__( + ATOMIC_SMP_LOCK "subl %2,%0; sete %1" + :"=m" (v->counter), "=qm" (c) + :"ir" (i), "m" (v->counter) : "memory"); + return c; +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ void atomic_inc(atomic_t *v) +{ + __asm__ __volatile__( + ATOMIC_SMP_LOCK "incl %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ void atomic_dec(atomic_t *v) +{ + __asm__ __volatile__( + ATOMIC_SMP_LOCK "decl %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ int atomic_dec_and_test(atomic_t *v) +{ + unsigned char c; + + __asm__ __volatile__( + ATOMIC_SMP_LOCK "decl %0; sete %1" + :"=m" (v->counter), "=qm" (c) + :"m" (v->counter) : "memory"); + return c != 0; +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ int atomic_inc_and_test(atomic_t *v) +{ + unsigned char c; + + __asm__ __volatile__( + ATOMIC_SMP_LOCK "incl %0; sete %1" + :"=m" (v->counter), "=qm" (c) + :"m" (v->counter) : "memory"); + return c != 0; +} + +/** + * atomic_add_negative - add and test if negative + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +static __inline__ int atomic_add_negative(int i, atomic_t *v) +{ + unsigned char c; + + __asm__ __volatile__( + ATOMIC_SMP_LOCK "addl %2,%0; sets %1" + :"=m" (v->counter), "=qm" (c) + :"ir" (i), "m" (v->counter) : "memory"); + return c; +} + +/* These are x86-specific, used by some header files */ +#define atomic_clear_mask(mask, addr) \ +__asm__ __volatile__(ATOMIC_SMP_LOCK "andl %0,%1" \ +: : "r" (~(mask)),"m" (*addr) : "memory") + +#define atomic_set_mask(mask, addr) \ +__asm__ __volatile__(ATOMIC_SMP_LOCK "orl %0,%1" \ +: : "r" (mask),"m" (*addr) : "memory") + +/* + * Force strict CPU ordering. + * And yes, this is required on UP too when we're talking + * to devices. + * + * For now, "wmb()" doesn't actually do anything, as all + * Intel CPU's follow what Intel calls a *Processor Order*, + * in which all writes are seen in the program order even + * outside the CPU. + * + * I expect future Intel CPU's to have a weaker ordering, + * but I'd also expect them to finally get their act together + * and add some real memory barriers if so. + */ + +#ifdef __i386__ +#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") +#define rmb() mb() +#define wmb() __asm__ __volatile__ ("": : :"memory") +#else +#define mb() asm volatile("mfence":::"memory") +#define rmb() asm volatile("lfence":::"memory") +#define wmb() asm volatile("sfence":::"memory") +#endif + +#undef ATOMIC_SMP_LOCK + +#define IATOMIC_DEFINED 1 + +#endif /* __i386__ */ + +#ifdef __ia64__ + +/* + * On IA-64, counter must always be volatile to ensure that that the + * memory accesses are ordered. + */ +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) ((atomic_t) { (i) }) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +/* stripped version - we need only 4byte version */ +#define ia64_cmpxchg(sem,ptr,old,new,size) \ +({ \ + __typeof__(ptr) _p_ = (ptr); \ + __typeof__(new) _n_ = (new); \ + unsigned long _o_, _r_; \ + _o_ = (unsigned int) (long) (old); \ + __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ + __asm__ __volatile__ ("cmpxchg4."sem" %0=[%1],%2,ar.ccv" \ + : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \ + (__typeof__(old)) _r_; \ +}) + +static __inline__ int +ia64_atomic_add (int i, atomic_t *v) +{ + int old, new; + // CMPXCHG_BUGCHECK_DECL + + do { + // CMPXCHG_BUGCHECK(v); + old = atomic_read(v); + new = old + i; + } while (ia64_cmpxchg("acq", v, old, old + i, sizeof(atomic_t)) != old); + return new; +} + +static __inline__ int +ia64_atomic_sub (int i, atomic_t *v) +{ + int old, new; + // CMPXCHG_BUGCHECK_DECL + + do { + // CMPXCHG_BUGCHECK(v); + old = atomic_read(v); + new = old - i; + } while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old); + return new; +} + +#define IA64_FETCHADD(tmp,v,n,sz) \ +({ \ + switch (sz) { \ + case 4: \ + __asm__ __volatile__ ("fetchadd4.rel %0=[%1],%2" \ + : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \ + break; \ + \ + case 8: \ + __asm__ __volatile__ ("fetchadd8.rel %0=[%1],%2" \ + : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \ + break; \ + } \ +}) + +#define ia64_fetch_and_add(i,v) \ +({ \ + unsigned long _tmp; \ + volatile __typeof__(*(v)) *_v = (v); \ + switch (i) { \ + case -16: IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v))); break; \ + case -8: IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v))); break; \ + case -4: IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v))); break; \ + case -1: IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v))); break; \ + case 1: IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v))); break; \ + case 4: IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v))); break; \ + case 8: IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v))); break; \ + case 16: IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v))); break; \ + } \ + (__typeof__(*v)) (_tmp + (i)); /* return new value */ \ +}) + +/* + * Atomically add I to V and return TRUE if the resulting value is + * negative. + */ +static __inline__ int +atomic_add_negative (int i, atomic_t *v) +{ + return ia64_atomic_add(i, v) < 0; +} + +#define atomic_add_return(i,v) \ + ((__builtin_constant_p(i) && \ + ( (i == 1) || (i == 4) || (i == 8) || (i == 16) \ + || (i == -1) || (i == -4) || (i == -8) || (i == -16))) \ + ? ia64_fetch_and_add(i, &(v)->counter) \ + : ia64_atomic_add(i, v)) + +#define atomic_sub_return(i,v) \ + ((__builtin_constant_p(i) && \ + ( (i == 1) || (i == 4) || (i == 8) || (i == 16) \ + || (i == -1) || (i == -4) || (i == -8) || (i == -16))) \ + ? ia64_fetch_and_add(-(i), &(v)->counter) \ + : ia64_atomic_sub(i, v)) + +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) + +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) != 0) + +#define atomic_add(i,v) atomic_add_return((i), (v)) +#define atomic_sub(i,v) atomic_sub_return((i), (v)) +#define atomic_inc(v) atomic_add(1, (v)) +#define atomic_dec(v) atomic_sub(1, (v)) + +/* + * Macros to force memory ordering. In these descriptions, "previous" + * and "subsequent" refer to program order; "visible" means that all + * architecturally visible effects of a memory access have occurred + * (at a minimum, this means the memory has been read or written). + * + * wmb(): Guarantees that all preceding stores to memory- + * like regions are visible before any subsequent + * stores and that all following stores will be + * visible only after all previous stores. + * rmb(): Like wmb(), but for reads. + * mb(): wmb()/rmb() combo, i.e., all previous memory + * accesses are visible before all subsequent + * accesses and vice versa. This is also known as + * a "fence." + * + * Note: "mb()" and its variants cannot be used as a fence to order + * accesses to memory mapped I/O registers. For that, mf.a needs to + * be used. However, we don't want to always use mf.a because (a) + * it's (presumably) much slower than mf and (b) mf.a is supported for + * sequential memory pages only. + */ +#define mb() __asm__ __volatile__ ("mf" ::: "memory") +#define rmb() mb() +#define wmb() mb() + +#define IATOMIC_DEFINED 1 + +#endif /* __ia64__ */ + +#ifdef __alpha__ + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc... + * + * But use these as seldom as possible since they are much slower + * than regular operations. + */ + + +/* + * Counter is volatile to make sure gcc doesn't try to be clever + * and move things around on us. We need to use _exactly_ the address + * the user gave us, not some alias that contains the same information. + */ +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) ((v)->counter = (i)) + +/* + * To get proper branch prediction for the main line, we must branch + * forward to code at the end of this object's .text section, then + * branch back to restart the operation. + */ + +static __inline__ void atomic_add(int i, atomic_t * v) +{ + unsigned long temp; + __asm__ __volatile__( + "1: ldl_l %0,%1\n" + " addl %0,%2,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter) + :"Ir" (i), "m" (v->counter)); +} + +static __inline__ void atomic_sub(int i, atomic_t * v) +{ + unsigned long temp; + __asm__ __volatile__( + "1: ldl_l %0,%1\n" + " subl %0,%2,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter) + :"Ir" (i), "m" (v->counter)); +} + +/* + * Same as above, but return the result value + */ +static __inline__ long atomic_add_return(int i, atomic_t * v) +{ + long temp, result; + __asm__ __volatile__( + "1: ldl_l %0,%1\n" + " addl %0,%3,%2\n" + " addl %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + " mb\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter), "=&r" (result) + :"Ir" (i), "m" (v->counter) : "memory"); + return result; +} + +static __inline__ long atomic_sub_return(int i, atomic_t * v) +{ + long temp, result; + __asm__ __volatile__( + "1: ldl_l %0,%1\n" + " subl %0,%3,%2\n" + " subl %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + " mb\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter), "=&r" (result) + :"Ir" (i), "m" (v->counter) : "memory"); + return result; +} + +#define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) + +#define atomic_inc(v) atomic_add(1,(v)) +#define atomic_dec(v) atomic_sub(1,(v)) + +#define mb() \ +__asm__ __volatile__("mb": : :"memory") + +#define rmb() \ +__asm__ __volatile__("mb": : :"memory") + +#define wmb() \ +__asm__ __volatile__("wmb": : :"memory") + +#define IATOMIC_DEFINED 1 + +#endif /* __alpha__ */ + +#ifdef __powerpc__ + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); +extern void atomic_set_mask(unsigned long mask, unsigned long *addr); + +#define SMP_ISYNC "\n\tisync" + +static __inline__ void atomic_add(int a, atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%3 # atomic_add\n\ + add %0,%2,%0\n\ + stwcx. %0,0,%3\n\ + bne- 1b" + : "=&r" (t), "=m" (v->counter) + : "r" (a), "r" (&v->counter), "m" (v->counter) + : "cc"); +} + +static __inline__ int atomic_add_return(int a, atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%2 # atomic_add_return\n\ + add %0,%1,%0\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + SMP_ISYNC + : "=&r" (t) + : "r" (a), "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +static __inline__ void atomic_sub(int a, atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%3 # atomic_sub\n\ + subf %0,%2,%0\n\ + stwcx. %0,0,%3\n\ + bne- 1b" + : "=&r" (t), "=m" (v->counter) + : "r" (a), "r" (&v->counter), "m" (v->counter) + : "cc"); +} + +static __inline__ int atomic_sub_return(int a, atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%2 # atomic_sub_return\n\ + subf %0,%1,%0\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + SMP_ISYNC + : "=&r" (t) + : "r" (a), "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +static __inline__ void atomic_inc(atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%2 # atomic_inc\n\ + addic %0,%0,1\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + : "=&r" (t), "=m" (v->counter) + : "r" (&v->counter), "m" (v->counter) + : "cc"); +} + +static __inline__ int atomic_inc_return(atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%1 # atomic_inc_return\n\ + addic %0,%0,1\n\ + stwcx. %0,0,%1\n\ + bne- 1b" + SMP_ISYNC + : "=&r" (t) + : "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +static __inline__ void atomic_dec(atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%2 # atomic_dec\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%2\n\ + bne- 1b" + : "=&r" (t), "=m" (v->counter) + : "r" (&v->counter), "m" (v->counter) + : "cc"); +} + +static __inline__ int atomic_dec_return(atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%1 # atomic_dec_return\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%1\n\ + bne- 1b" + SMP_ISYNC + : "=&r" (t) + : "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +#define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) + +/* + * Atomically test *v and decrement if it is greater than 0. + * The function returns the old value of *v minus 1. + */ +static __inline__ int atomic_dec_if_positive(atomic_t *v) +{ + int t; + + __asm__ __volatile__( +"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\ + addic. %0,%0,-1\n\ + blt- 2f\n\ + stwcx. %0,0,%1\n\ + bne- 1b" + SMP_ISYNC + "\n\ +2:" : "=&r" (t) + : "r" (&v->counter) + : "cc", "memory"); + + return t; +} + +/* + * Memory barrier. + * The sync instruction guarantees that all memory accesses initiated + * by this processor have been performed (with respect to all other + * mechanisms that access memory). The eieio instruction is a barrier + * providing an ordering (separately) for (a) cacheable stores and (b) + * loads and stores to non-cacheable memory (e.g. I/O devices). + * + * mb() prevents loads and stores being reordered across this point. + * rmb() prevents loads being reordered across this point. + * wmb() prevents stores being reordered across this point. + * + * We can use the eieio instruction for wmb, but since it doesn't + * give any ordering guarantees about loads, we have to use the + * stronger but slower sync instruction for mb and rmb. + */ +#define mb() __asm__ __volatile__ ("sync" : : : "memory") +#define rmb() __asm__ __volatile__ ("sync" : : : "memory") +#define wmb() __asm__ __volatile__ ("eieio" : : : "memory") + +#define IATOMIC_DEFINED 1 + +#endif /* __powerpc__ */ + +#ifdef __mips__ + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +/* + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_read(v) ((v)->counter) + +/* + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_set(v,i) ((v)->counter = (i)) + +/* + * for MIPS II and better we can use ll/sc instruction, and kernel 2.4.3+ + * will emulate it on MIPS I. + */ + +/* + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. Note that the guaranteed useful range + * of an atomic_t is only 24 bits. + */ +extern __inline__ void atomic_add(int i, atomic_t * v) +{ + unsigned long temp; + + __asm__ __volatile__( + ".set push \n" + ".set mips2 \n" + "1: ll %0, %1 # atomic_add\n" + " addu %0, %2 \n" + " sc %0, %1 \n" + " beqz %0, 1b \n" + ".set pop \n" + : "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter)); +} + +/* + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +extern __inline__ void atomic_sub(int i, atomic_t * v) +{ + unsigned long temp; + + __asm__ __volatile__( + ".set push \n" + ".set mips2 \n" + "1: ll %0, %1 # atomic_sub\n" + " subu %0, %2 \n" + " sc %0, %1 \n" + " beqz %0, 1b \n" + ".set pop \n" + : "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter)); +} + +/* + * Same as above, but return the result value + */ +extern __inline__ int atomic_add_return(int i, atomic_t * v) +{ + unsigned long temp, result; + + __asm__ __volatile__( + ".set push # atomic_add_return\n" + ".set noreorder \n" + ".set mips2 \n" + "1: ll %1, %2 \n" + " addu %0, %1, %3 \n" + " sc %0, %2 \n" + " beqz %0, 1b \n" + " addu %0, %1, %3 \n" + ".set pop \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); + + return result; +} + +extern __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + unsigned long temp, result; + + __asm__ __volatile__( + ".set push \n" + ".set mips2 \n" + ".set noreorder # atomic_sub_return\n" + "1: ll %1, %2 \n" + " subu %0, %1, %3 \n" + " sc %0, %2 \n" + " beqz %0, 1b \n" + " subu %0, %1, %3 \n" + ".set pop \n" + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "Ir" (i), "m" (v->counter) + : "memory"); + + return result; +} + +#define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +/* + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) + +/* + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0) + +/* + * atomic_dec_and_test - decrement by 1 and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) + +/* + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_inc(v) atomic_add(1,(v)) + +/* + * atomic_dec - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ +#define atomic_dec(v) atomic_sub(1,(v)) + +/* + * atomic_add_negative - add and test if negative + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + * + * Currently not implemented for MIPS. + */ + +#define mb() \ +__asm__ __volatile__( \ + "# prevent instructions being moved around\n\t" \ + ".set\tnoreorder\n\t" \ + "# 8 nops to fool the R4400 pipeline\n\t" \ + "nop;nop;nop;nop;nop;nop;nop;nop\n\t" \ + ".set\treorder" \ + : /* no output */ \ + : /* no input */ \ + : "memory") +#define rmb() mb() +#define wmb() mb() + +#define IATOMIC_DEFINED 1 + +#endif /* __mips__ */ + +#ifdef __arm__ + +/* + * FIXME: bellow code is valid only for SA11xx + */ + +/* + * Save the current interrupt enable state & disable IRQs + */ +#define local_irq_save(x) \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ local_irq_save\n" \ +" orr %1, %0, #128\n" \ +" msr cpsr_c, %1" \ + : "=r" (x), "=r" (temp) \ + : \ + : "memory"); \ + }) + +/* + * restore saved IRQ & FIQ state + */ +#define local_irq_restore(x) \ + __asm__ __volatile__( \ + "msr cpsr_c, %0 @ local_irq_restore\n" \ + : \ + : "r" (x) \ + : "memory") + +#define __save_flags_cli(x) local_irq_save(x) +#define __restore_flags(x) local_irq_restore(x) + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +static __inline__ void atomic_add(int i, volatile atomic_t *v) +{ + unsigned long flags; + + __save_flags_cli(flags); + v->counter += i; + __restore_flags(flags); +} + +static __inline__ void atomic_sub(int i, volatile atomic_t *v) +{ + unsigned long flags; + + __save_flags_cli(flags); + v->counter -= i; + __restore_flags(flags); +} + +static __inline__ void atomic_inc(volatile atomic_t *v) +{ + unsigned long flags; + + __save_flags_cli(flags); + v->counter += 1; + __restore_flags(flags); +} + +static __inline__ void atomic_dec(volatile atomic_t *v) +{ + unsigned long flags; + + __save_flags_cli(flags); + v->counter -= 1; + __restore_flags(flags); +} + +static __inline__ int atomic_dec_and_test(volatile atomic_t *v) +{ + unsigned long flags; + int result; + + __save_flags_cli(flags); + v->counter -= 1; + result = (v->counter == 0); + __restore_flags(flags); + + return result; +} + +static inline int atomic_add_negative(int i, volatile atomic_t *v) +{ + unsigned long flags; + int result; + + __save_flags_cli(flags); + v->counter += i; + result = (v->counter < 0); + __restore_flags(flags); + + return result; +} + +static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *addr) +{ + unsigned long flags; + + __save_flags_cli(flags); + *addr &= ~mask; + __restore_flags(flags); +} + +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() mb() +#define wmb() mb() + +#define IATOMIC_DEFINED 1 + +#endif /* __arm__ */ + +#ifdef __sh__ + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +#define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) != 0) + +#define atomic_add(i,v) atomic_add_return((i),(v)) +#define atomic_sub(i,v) atomic_sub_return((i),(v)) +#define atomic_inc(v) atomic_add(1,(v)) +#define atomic_dec(v) atomic_sub(1,(v)) + +static __inline__ int atomic_add_return(int i, volatile atomic_t *v) +{ + int result; + + asm volatile ( + " .align 2\n" + " mova 99f, r0\n" + " mov r15, r1\n" + " mov #-6, r15\n" + " mov.l @%2, %0\n" + " add %1, %0\n" + " mov.l %0, @%2\n" + "99: mov r1, r15" + : "=&r"(result) + : "r"(i), "r"(v) + : "r0", "r1"); + + return result; +} + +static __inline__ int atomic_sub_return(int i, volatile atomic_t *v) +{ + int result; + + asm volatile ( + " .align 2\n" + " mova 99f, r0\n" + " mov r15, r1\n" + " mov #-6, r15\n" + " mov.l @%2, %0\n" + " sub %1, %0\n" + " mov.l %0, @%2\n" + "99: mov r1, r15" + : "=&r"(result) + : "r"(i), "r"(v) + : "r0", "r1"); + + return result; +} + +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() mb() +#define wmb() mb() + +#define IATOMIC_DEFINED 1 + +#endif /* __sh__ */ + +#ifdef __bfin__ + +#include + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) +#define atomic_add(i,v) bfin_atomic_add32(&(v)->counter, i) +#define atomic_sub(i,v) bfin_atomic_sub32(&(v)->counter, i) +#define atomic_inc(v) bfin_atomic_inc32(&(v)->counter); +#define atomic_dec(v) bfin_atomic_dec32(&(v)->counter); + +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() mb() +#define wmb() mb() + +#define IATOMIC_DEFINED 1 + +#endif /* __bfin__ */ + +#ifndef IATOMIC_DEFINED +/* + * non supported architecture. + */ +#warning "Atomic operations are not supported on this architecture." + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) +#define atomic_add(i,v) (((v)->counter) += (i)) +#define atomic_sub(i,v) (((v)->counter) -= (i)) +#define atomic_inc(v) (((v)->counter)++) +#define atomic_dec(v) (((v)->counter)--) + +#define mb() +#define rmb() +#define wmb() + +#define IATOMIC_DEFINED 1 + +#endif /* IATOMIC_DEFINED */ + +/* + * Atomic read/write + * Copyright (c) 2001 by Abramo Bagnara + */ + +/* Max number of times we must spin on a spin-lock calling sched_yield(). + After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */ + +#ifndef MAX_SPIN_COUNT +#define MAX_SPIN_COUNT 50 +#endif + +/* Duration of sleep (in nanoseconds) when we can't acquire a spin-lock + after MAX_SPIN_COUNT iterations of sched_yield(). + This MUST BE > 2ms. + (Otherwise the kernel does busy-waiting for real-time threads, + giving other threads no chance to run.) */ + +#ifndef SPIN_SLEEP_DURATION +#define SPIN_SLEEP_DURATION 2000001 +#endif + +typedef struct { + unsigned int begin, end; +} snd_atomic_write_t; + +typedef struct { + volatile const snd_atomic_write_t *write; + unsigned int end; +} snd_atomic_read_t; + +void snd_atomic_read_wait(snd_atomic_read_t *t); + +static inline void snd_atomic_write_init(snd_atomic_write_t *w) +{ + w->begin = 0; + w->end = 0; +} + +static inline void snd_atomic_write_begin(snd_atomic_write_t *w) +{ + w->begin++; + wmb(); +} + +static inline void snd_atomic_write_end(snd_atomic_write_t *w) +{ + wmb(); + w->end++; +} + +static inline void snd_atomic_read_init(snd_atomic_read_t *r, snd_atomic_write_t *w) +{ + r->write = w; +} + +static inline void snd_atomic_read_begin(snd_atomic_read_t *r) +{ + r->end = r->write->end; + rmb(); +} + +static inline int snd_atomic_read_ok(snd_atomic_read_t *r) +{ + rmb(); + return r->end == r->write->begin; +} + +#endif /* __ALSA_IATOMIC_H */ diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..fc5d0e6 --- /dev/null +++ b/include/input.h @@ -0,0 +1,83 @@ +/** + * \file include/input.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_INPUT_H +#define __ALSA_INPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Input Input Interface + * + * The input functions present an interface similar to the stdio functions + * on top of different underlying input sources. + * + * The #snd_config_load function uses such an input handle to be able to + * load configurations not only from standard files but also from other + * sources, e.g. from memory buffers. + * + * \{ + */ + +/** + * \brief Internal structure for an input object. + * + * The ALSA library uses a pointer to this structure as a handle to an + * input object. Applications don't access its contents directly. + */ +typedef struct _snd_input snd_input_t; + +/** Input type. */ +typedef enum _snd_input_type { + /** Input from a stdio stream. */ + SND_INPUT_STDIO, + /** Input from a memory buffer. */ + SND_INPUT_BUFFER +} snd_input_type_t; + +int snd_input_stdio_open(snd_input_t **inputp, const char *file, const char *mode); +int snd_input_stdio_attach(snd_input_t **inputp, FILE *fp, int _close); +int snd_input_buffer_open(snd_input_t **inputp, const char *buffer, ssize_t size); +int snd_input_close(snd_input_t *input); +int snd_input_scanf(snd_input_t *input, const char *format, ...) +#ifndef DOC_HIDDEN + __attribute__ ((format (scanf, 2, 3))) +#endif + ; +char *snd_input_gets(snd_input_t *input, char *str, size_t size); +int snd_input_getc(snd_input_t *input); +int snd_input_ungetc(snd_input_t *input, int c); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_INPUT_H */ diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..4d9895f --- /dev/null +++ b/include/list.h @@ -0,0 +1,174 @@ +#ifndef _LIST_H +#define _LIST_H + +/* + * This code was taken from the Linux 2.4.0 kernel. [jaroslav] + */ + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#ifndef LIST_HEAD_IS_DEFINED +struct list_head { + struct list_head *next, *prev; +}; +#endif + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __list_add(struct list_head * _new, + struct list_head * prev, + struct list_head * next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static __inline__ void list_add(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static __inline__ void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __list_del(struct list_head * prev, + struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + */ +static __inline__ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list.n + */ +static __inline__ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static __inline__ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static __inline__ void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next ; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safely (actual pointer can be invalidated) + * @pos: the &struct list_head to use as a loop counter. + * @next: the &struct list_head to use to save next. + * @head: the head for your list. + */ +#define list_for_each_safe(pos, npos, head) \ + for (pos = (head)->next, npos = pos->next ; pos != (head); pos = npos, npos = pos->next) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @offset: offset of entry inside a struct + */ +#define list_entry_offset(ptr, type, offset) \ + ((type *)((char *)(ptr)-(offset))) + +#endif /* _LIST_H */ diff --git a/include/local.h b/include/local.h new file mode 100644 index 0000000..e00598a --- /dev/null +++ b/include/local.h @@ -0,0 +1,283 @@ +/* + * ALSA lib - local header file + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __LOCAL_H +#define __LOCAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#ifdef SUPPORT_RESMGR +#include +#endif +#ifdef HAVE_LIBDL +#include +#else +#define RTLD_NOW 0 +#endif + +#define _snd_config_iterator list_head +#define _snd_interval sndrv_interval +#define _snd_pcm_info sndrv_pcm_info +#define _snd_pcm_hw_params sndrv_pcm_hw_params +#define _snd_pcm_sw_params sndrv_pcm_sw_params +#define _snd_pcm_status sndrv_pcm_status + +#define _snd_ctl_card_info sndrv_ctl_card_info +#define _snd_ctl_elem_id sndrv_ctl_elem_id +#define _snd_ctl_elem_list sndrv_ctl_elem_list +#define _snd_ctl_elem_info sndrv_ctl_elem_info +#define _snd_ctl_elem_value sndrv_ctl_elem_value +#define _snd_ctl_event sndrv_ctl_event + +#define _snd_rawmidi_info sndrv_rawmidi_info +#define _snd_rawmidi_params sndrv_rawmidi_params +#define _snd_rawmidi_status sndrv_rawmidi_status + +#define _snd_hwdep_info sndrv_hwdep_info +#define _snd_hwdep_dsp_status sndrv_hwdep_dsp_status +#define _snd_hwdep_dsp_image sndrv_hwdep_dsp_image + +#define _snd_seq_queue_tempo sndrv_seq_queue_tempo +#define _snd_seq_client_info sndrv_seq_client_info +#define _snd_seq_port_info sndrv_seq_port_info +#define _snd_seq_system_info sndrv_seq_system_info +#define _snd_seq_queue_info sndrv_seq_queue_info +#define _snd_seq_queue_status sndrv_seq_queue_status +#define _snd_seq_queue_timer sndrv_seq_queue_timer +#define _snd_seq_port_subscribe sndrv_seq_port_subscribe +#define _snd_seq_query_subscribe sndrv_seq_query_subs +#define _snd_seq_client_pool sndrv_seq_client_pool +#define _snd_seq_remove_events sndrv_seq_remove_events + +#define sndrv_seq_addr snd_seq_addr +#define sndrv_seq_tick_time_t snd_seq_tick_time_t +#define sndrv_seq_real_time snd_seq_real_time +#define sndrv_seq_timestamp snd_seq_timestamp +#define sndrv_seq_event snd_seq_event + +#if 0 +typedef struct sndrv_seq_addr snd_seq_addr_t; +#define snd_seq_tick_time_t sndrv_seq_tick_time_t +typedef struct sndrv_seq_real_time snd_seq_real_time_t; +typedef union sndrv_seq_timestamp snd_seq_timestamp_t; +typedef struct sndrv_seq_event snd_seq_event_t; +#endif + +#define _snd_timer_id sndrv_timer_id +#define _snd_timer_ginfo sndrv_timer_ginfo +#define _snd_timer_gparams sndrv_timer_gparams +#define _snd_timer_gstatus sndrv_timer_gstatus +#define _snd_timer_select sndrv_timer_select +#define _snd_timer_info sndrv_timer_info +#define _snd_timer_params sndrv_timer_params +#define _snd_timer_status sndrv_timer_status + +#define ALSA_LIBRARY_BUILD + +#include +#include +#include "alsa-symbols.h" +#include "version.h" +#include "global.h" +#include "input.h" +#include "output.h" +#include "error.h" +#include "conf.h" +#include "pcm.h" +#include "pcm_plugin.h" +#include "rawmidi.h" +#include "timer.h" +#include "hwdep.h" +#include "control.h" +#include "mixer.h" +#include "seq_event.h" +#include "seq.h" +#include "seqmid.h" +#include "seq_midi_event.h" +#include "list.h" + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SND_LITTLE_ENDIAN +#endif +#if __BYTE_ORDER == __BIG_ENDIAN +#define SND_BIG_ENDIAN +#endif + +struct _snd_async_handler { + enum { + SND_ASYNC_HANDLER_GENERIC, + SND_ASYNC_HANDLER_CTL, + SND_ASYNC_HANDLER_PCM, + SND_ASYNC_HANDLER_TIMER, + } type; + int fd; + union { + snd_ctl_t *ctl; + snd_pcm_t *pcm; + snd_timer_t *timer; + } u; + snd_async_callback_t callback; + void *private_data; + struct list_head glist; + struct list_head hlist; +}; + +typedef enum _snd_set_mode { + SND_CHANGE, + SND_TRY, + SND_TEST, +} snd_set_mode_t; + +size_t page_align(size_t size); +size_t page_size(void); +size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset); + +int safe_strtol(const char *str, long *val); + +int snd_send_fd(int sock, void *data, size_t len, int fd); +int snd_receive_fd(int sock, void *data, size_t len, int *fd); + +/* + * error messages + */ +#ifndef NDEBUG +#define CHECK_SANITY(x) x +extern snd_lib_error_handler_t snd_err_msg; +#define SNDMSG(args...) snd_err_msg(__FILE__, __LINE__, __FUNCTION__, 0, ##args) +#define SYSMSG(args...) snd_err_msg(__FILE__, __LINE__, __FUNCTION__, errno, ##args) +#else +#define CHECK_SANITY(x) 0 /* not evaluated */ +#define SNDMSG(args...) /* nop */ +#define SYSMSG(args...) /* nop */ +#endif + +/* + */ +#define HAVE_GNU_LD +#define HAVE_ELF +#define HAVE_ASM_PREVIOUS_DIRECTIVE + +/* Stolen from libc-symbols.h in GNU glibc */ + +/* When a reference to SYMBOL is encountered, the linker will emit a + warning message MSG. */ + +#define ASM_NAME(name) __SYMBOL_PREFIX name + +#ifdef HAVE_GNU_LD +# ifdef HAVE_ELF + +/* We want the .gnu.warning.SYMBOL section to be unallocated. */ +# ifdef HAVE_ASM_PREVIOUS_DIRECTIVE +# define __make_section_unallocated(section_string) \ + asm (".section " section_string "\n\t.previous"); +# elif defined HAVE_ASM_POPSECTION_DIRECTIVE +# define __make_section_unallocated(section_string) \ + asm (".pushsection " section_string "\n\t.popsection"); +# else +# define __make_section_unallocated(section_string) +# endif + +/* Tacking on "\n\t#" to the section name makes gcc put it's bogus + section attributes on what looks like a comment to the assembler. */ +# ifdef HAVE_SECTION_QUOTES +# define link_warning(symbol, msg) \ + __make_section_unallocated (".gnu.warning." ASM_NAME(#symbol)) \ + static const char __evoke_link_warning_##symbol[] \ + __attribute__ ((section (".gnu.warning." ASM_NAME(#symbol) "\"\n\t#\""))) = msg; +# else +# define link_warning(symbol, msg) \ + __make_section_unallocated (".gnu.warning." ASM_NAME(#symbol)) \ + static const char __evoke_link_warning_##symbol[] \ + __attribute__ ((section (".gnu.warning." ASM_NAME(#symbol) "\n\t#"))) = msg; +# endif +# else +# define link_warning(symbol, msg) \ + asm (".stabs \"" msg "\",30,0,0,0\n\t" \ + ".stabs \"" ASM_NAME(#symbol) "\",1,0,0,0\n"); +# endif +#else +/* We will never be heard; they will all die horribly. */ +# define link_warning(symbol, msg) +#endif + +static inline int snd_open_device(const char *filename, int fmode) +{ + int fd; + +#ifdef O_CLOEXEC + fmode |= O_CLOEXEC; +#endif + fd = open(filename, fmode); + +/* open with resmgr */ +#ifdef SUPPORT_RESMGR + if (fd < 0) { + if (errno == EAGAIN || errno == EBUSY) + return fd; + if (! access(filename, F_OK)) + fd = rsm_open_device(filename, fmode); + } +#endif + if (fd >= 0) + fcntl(fd, F_SETFD, FD_CLOEXEC); + return fd; +} + +/* make local functions really local */ +#define snd_dlobj_cache_get \ + snd1_dlobj_cache_get +#define snd_dlobj_cache_put \ + snd1_dlobj_cache_put +#define snd_dlobj_cache_cleanup \ + snd1_dlobj_cache_cleanup +#define snd_config_set_hop \ + snd1_config_set_hop +#define snd_config_check_hop \ + snd1_config_check_hop +#define snd_config_search_alias_hooks \ + snd1_config_search_alias_hooks + +/* dlobj cache */ +void *snd_dlobj_cache_get(const char *lib, const char *name, const char *version, int verbose); +int snd_dlobj_cache_put(void *open_func); +void snd_dlobj_cache_cleanup(void); + +/* for recursive checks */ +void snd_config_set_hop(snd_config_t *conf, int hop); +int snd_config_check_hop(snd_config_t *conf); +#define SND_CONF_MAX_HOPS 64 + +int snd_config_search_alias_hooks(snd_config_t *config, + const char *base, const char *key, + snd_config_t **result); + +#endif diff --git a/include/mixer.h b/include/mixer.h new file mode 100644 index 0000000..58256a6 --- /dev/null +++ b/include/mixer.h @@ -0,0 +1,317 @@ +/** + * \file include/mixer.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_MIXER_H +#define __ALSA_MIXER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Mixer Mixer Interface + * The mixer interface. + * \{ + */ + +/** Mixer handle */ +typedef struct _snd_mixer snd_mixer_t; +/** Mixer elements class handle */ +typedef struct _snd_mixer_class snd_mixer_class_t; +/** Mixer element handle */ +typedef struct _snd_mixer_elem snd_mixer_elem_t; + +/** + * \brief Mixer callback function + * \param mixer Mixer handle + * \param mask event mask + * \param elem related mixer element (if any) + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_mixer_callback_t)(snd_mixer_t *ctl, + unsigned int mask, + snd_mixer_elem_t *elem); + +/** + * \brief Mixer element callback function + * \param elem Mixer element + * \param mask event mask + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem, + unsigned int mask); + +/** + * \brief Compare function for sorting mixer elements + * \param e1 First element + * \param e2 Second element + * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 + */ +typedef int (*snd_mixer_compare_t)(const snd_mixer_elem_t *e1, + const snd_mixer_elem_t *e2); + +/** + * \brief Event callback for the mixer class + * \param class_ Mixer class + * \param mask Event mask (SND_CTL_EVENT_*) + * \param helem HCTL element which invoked the event + * \param melem Mixer element associated to HCTL element + * \return zero if success, otherwise a negative error value + */ +typedef int (*snd_mixer_event_t)(snd_mixer_class_t *class_, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem); + + +/** Mixer element type */ +typedef enum _snd_mixer_elem_type { + /* Simple mixer elements */ + SND_MIXER_ELEM_SIMPLE, + SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE +} snd_mixer_elem_type_t; + +int snd_mixer_open(snd_mixer_t **mixer, int mode); +int snd_mixer_close(snd_mixer_t *mixer); +snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer); +snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer); +int snd_mixer_handle_events(snd_mixer_t *mixer); +int snd_mixer_attach(snd_mixer_t *mixer, const char *name); +int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); +int snd_mixer_detach(snd_mixer_t *mixer, const char *name); +int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); +int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl); +int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer); +int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space); +int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_mixer_load(snd_mixer_t *mixer); +void snd_mixer_free(snd_mixer_t *mixer); +int snd_mixer_wait(snd_mixer_t *mixer, int timeout); +int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort); +void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val); +void * snd_mixer_get_callback_private(const snd_mixer_t *obj); +void snd_mixer_set_callback_private(snd_mixer_t *obj, void * val); +unsigned int snd_mixer_get_count(const snd_mixer_t *obj); +int snd_mixer_class_unregister(snd_mixer_class_t *clss); + +snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem); +snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem); +void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val); +void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *obj); +void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *obj, void * val); +snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *obj); + +int snd_mixer_class_register(snd_mixer_class_t *class_, snd_mixer_t *mixer); +int snd_mixer_elem_new(snd_mixer_elem_t **elem, + snd_mixer_elem_type_t type, + int compare_weight, + void *private_data, + void (*private_free)(snd_mixer_elem_t *elem)); +int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class_); +int snd_mixer_elem_remove(snd_mixer_elem_t *elem); +void snd_mixer_elem_free(snd_mixer_elem_t *elem); +int snd_mixer_elem_info(snd_mixer_elem_t *elem); +int snd_mixer_elem_value(snd_mixer_elem_t *elem); +int snd_mixer_elem_attach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem); +int snd_mixer_elem_detach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem); +int snd_mixer_elem_empty(snd_mixer_elem_t *melem); +void *snd_mixer_elem_get_private(const snd_mixer_elem_t *melem); + +size_t snd_mixer_class_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_mixer_class_t using standard alloca + * \param ptr returned pointer + */ +#define snd_mixer_class_alloca(ptr) __snd_alloca(ptr, snd_mixer_class) +int snd_mixer_class_malloc(snd_mixer_class_t **ptr); +void snd_mixer_class_free(snd_mixer_class_t *obj); +void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src); +snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *class_); +snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *class_); +void *snd_mixer_class_get_private(const snd_mixer_class_t *class_); +snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *class_); +int snd_mixer_class_set_event(snd_mixer_class_t *class_, snd_mixer_event_t event); +int snd_mixer_class_set_private(snd_mixer_class_t *class_, void *private_data); +int snd_mixer_class_set_private_free(snd_mixer_class_t *class_, void (*private_free)(snd_mixer_class_t *class_)); +int snd_mixer_class_set_compare(snd_mixer_class_t *class_, snd_mixer_compare_t compare); + +/** + * \defgroup SimpleMixer Simple Mixer Interface + * \ingroup Mixer + * The simple mixer interface. + * \{ + */ + +/* Simple mixer elements API */ + +/** Mixer simple element channel identifier */ +typedef enum _snd_mixer_selem_channel_id { + /** Unknown */ + SND_MIXER_SCHN_UNKNOWN = -1, + /** Front left */ + SND_MIXER_SCHN_FRONT_LEFT = 0, + /** Front right */ + SND_MIXER_SCHN_FRONT_RIGHT, + /** Rear left */ + SND_MIXER_SCHN_REAR_LEFT, + /** Rear right */ + SND_MIXER_SCHN_REAR_RIGHT, + /** Front center */ + SND_MIXER_SCHN_FRONT_CENTER, + /** Woofer */ + SND_MIXER_SCHN_WOOFER, + /** Side Left */ + SND_MIXER_SCHN_SIDE_LEFT, + /** Side Right */ + SND_MIXER_SCHN_SIDE_RIGHT, + /** Rear Center */ + SND_MIXER_SCHN_REAR_CENTER, + SND_MIXER_SCHN_LAST = 31, + /** Mono (Front left alias) */ + SND_MIXER_SCHN_MONO = SND_MIXER_SCHN_FRONT_LEFT +} snd_mixer_selem_channel_id_t; + +/** Mixer simple element - register options - abstraction level */ +enum snd_mixer_selem_regopt_abstract { + /** no abstraction - try use all universal controls from driver */ + SND_MIXER_SABSTRACT_NONE = 0, + /** basic abstraction - Master,PCM,CD,Aux,Record-Gain etc. */ + SND_MIXER_SABSTRACT_BASIC, +}; + +/** Mixer simple element - register options */ +struct snd_mixer_selem_regopt { + /** structure version */ + int ver; + /** v1: abstract layer selection */ + enum snd_mixer_selem_regopt_abstract abstract; + /** v1: device name (must be NULL when playback_pcm or capture_pcm != NULL) */ + const char *device; + /** v1: playback PCM connected to mixer device (NULL == none) */ + snd_pcm_t *playback_pcm; + /** v1: capture PCM connected to mixer device (NULL == none) */ + snd_pcm_t *capture_pcm; +}; + +/** Mixer simple element identifier */ +typedef struct _snd_mixer_selem_id snd_mixer_selem_id_t; + +const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel); + +int snd_mixer_selem_register(snd_mixer_t *mixer, + struct snd_mixer_selem_regopt *options, + snd_mixer_class_t **classp); +void snd_mixer_selem_get_id(snd_mixer_elem_t *element, + snd_mixer_selem_id_t *id); +const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem); +unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem); +snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, + const snd_mixer_selem_id_t *id); + +int snd_mixer_selem_is_active(snd_mixer_elem_t *elem); +int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); +int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); +int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem); + +int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); +int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); +int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); +int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); +int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); +int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); +int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); +int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); +int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); +int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); +int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value); +int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value); +int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir); +int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir); +int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); +int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); +int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value); +int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value); +int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, + long min, long max); +int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, + long min, long max); + +int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem); +int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem); +int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem); +int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem); +int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str); +int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp); +int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx); + +size_t snd_mixer_selem_id_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca + * \param ptr returned pointer + */ +#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id) +int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr); +void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj); +void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src); +const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj); +unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj); +void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val); +void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val); + +/** \} */ + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_MIXER_H */ + diff --git a/include/mixer_abst.h b/include/mixer_abst.h new file mode 100644 index 0000000..7844b19 --- /dev/null +++ b/include/mixer_abst.h @@ -0,0 +1,112 @@ +/** + * \file include/mixer_abst.h + * \brief Mixer abstract implementation interface library for the ALSA library + * \author Jaroslav Kysela + * \date 2005 + * + * Mixer abstact implementation interface library for the ALSA library + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_MIXER_ABST_H +#define __ALSA_MIXER_ABST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Mixer_Abstract Mixer Abstact Module Interface + * The mixer abstact module interface. + * \{ + */ + +#define SM_PLAY 0 +#define SM_CAPT 1 + +#define SM_CAP_GVOLUME (1<<1) +#define SM_CAP_GSWITCH (1<<2) +#define SM_CAP_PVOLUME (1<<3) +#define SM_CAP_PVOLUME_JOIN (1<<4) +#define SM_CAP_PSWITCH (1<<5) +#define SM_CAP_PSWITCH_JOIN (1<<6) +#define SM_CAP_CVOLUME (1<<7) +#define SM_CAP_CVOLUME_JOIN (1<<8) +#define SM_CAP_CSWITCH (1<<9) +#define SM_CAP_CSWITCH_JOIN (1<<10) +#define SM_CAP_CSWITCH_EXCL (1<<11) +#define SM_CAP_PENUM (1<<12) +#define SM_CAP_CENUM (1<<13) +/* SM_CAP_* 24-31 => private for module use */ + +#define SM_OPS_IS_ACTIVE 0 +#define SM_OPS_IS_MONO 1 +#define SM_OPS_IS_CHANNEL 2 +#define SM_OPS_IS_ENUMERATED 3 +#define SM_OPS_IS_ENUMCNT 4 + +#define sm_selem(x) ((sm_selem_t *)((x)->private_data)) +#define sm_selem_ops(x) ((sm_selem_t *)((x)->private_data))->ops + +typedef struct _sm_selem { + snd_mixer_selem_id_t *id; + struct sm_elem_ops *ops; + unsigned int caps; + unsigned int capture_group; +} sm_selem_t; + +typedef struct _sm_class_basic { + char *device; + snd_ctl_t *ctl; + snd_hctl_t *hctl; + snd_ctl_card_info_t *info; +} sm_class_basic_t; + +struct sm_elem_ops { + int (*is)(snd_mixer_elem_t *elem, int dir, int cmd, int val); + int (*get_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max); + int (*set_range)(snd_mixer_elem_t *elem, int dir, long min, long max); + int (*get_dB_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max); + int (*ask_vol_dB)(snd_mixer_elem_t *elem, int dir, long value, long *dbValue); + int (*ask_dB_vol)(snd_mixer_elem_t *elem, int dir, long dbValue, long *value, int xdir); + int (*get_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value); + int (*get_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value); + int (*set_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value); + int (*set_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value, int xdir); + int (*get_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int *value); + int (*set_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value); + int (*enum_item_name)(snd_mixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf); + int (*get_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *itemp); + int (*set_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int item); +}; + +int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2); + +int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info); +void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class); +void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data); +void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class)); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_MIXER_ABST_H */ + diff --git a/include/output.h b/include/output.h new file mode 100644 index 0000000..5279aa2 --- /dev/null +++ b/include/output.h @@ -0,0 +1,86 @@ +/** + * \file include/output.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_OUTPUT_H +#define __ALSA_OUTPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Output Output Interface + * + * The output functions present an interface similar to the stdio functions + * on top of different underlying output destinations. + * + * Many PCM debugging functions (\c snd_pcm_xxx_dump_xxx) use such an output + * handle to be able to write not only to the screen but also to other + * destinations, e.g. to files or to memory buffers. + * + * \{ + */ + +/** + * \brief Internal structure for an output object. + * + * The ALSA library uses a pointer to this structure as a handle to an + * output object. Applications don't access its contents directly. + */ +typedef struct _snd_output snd_output_t; + +/** Output type. */ +typedef enum _snd_output_type { + /** Output to a stdio stream. */ + SND_OUTPUT_STDIO, + /** Output to a memory buffer. */ + SND_OUTPUT_BUFFER +} snd_output_type_t; + +int snd_output_stdio_open(snd_output_t **outputp, const char *file, const char *mode); +int snd_output_stdio_attach(snd_output_t **outputp, FILE *fp, int _close); +int snd_output_buffer_open(snd_output_t **outputp); +size_t snd_output_buffer_string(snd_output_t *output, char **buf); +int snd_output_close(snd_output_t *output); +int snd_output_printf(snd_output_t *output, const char *format, ...) +#ifndef DOC_HIDDEN + __attribute__ ((format (printf, 2, 3))) +#endif + ; +int snd_output_vprintf(snd_output_t *output, const char *format, va_list args); +int snd_output_puts(snd_output_t *output, const char *str); +int snd_output_putc(snd_output_t *output, int c); +int snd_output_flush(snd_output_t *output); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_OUTPUT_H */ + diff --git a/include/pcm.h b/include/pcm.h new file mode 100644 index 0000000..7243ffb --- /dev/null +++ b/include/pcm.h @@ -0,0 +1,1142 @@ +/** + * \file include/pcm.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver. + * See the \ref pcm page for more details. + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_PCM_H +#define __ALSA_PCM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup PCM PCM Interface + * See the \ref pcm page for more details. + * \{ + */ + +/** dlsym version for interface entry callback */ +#define SND_PCM_DLSYM_VERSION _dlsym_pcm_001 + +/** PCM generic info container */ +typedef struct _snd_pcm_info snd_pcm_info_t; +/** PCM hardware configuration space container */ +typedef struct _snd_pcm_hw_params snd_pcm_hw_params_t; +/** PCM software configuration container */ +typedef struct _snd_pcm_sw_params snd_pcm_sw_params_t; +/** PCM status container */ + typedef struct _snd_pcm_status snd_pcm_status_t; +/** PCM access types mask */ +typedef struct _snd_pcm_access_mask snd_pcm_access_mask_t; +/** PCM formats mask */ +typedef struct _snd_pcm_format_mask snd_pcm_format_mask_t; +/** PCM subformats mask */ +typedef struct _snd_pcm_subformat_mask snd_pcm_subformat_mask_t; + +/** PCM class */ +typedef enum _snd_pcm_class { + /** standard device */ + + SND_PCM_CLASS_GENERIC = 0, + /** multichannel device */ + SND_PCM_CLASS_MULTI, + /** software modem device */ + SND_PCM_CLASS_MODEM, + /** digitizer device */ + SND_PCM_CLASS_DIGITIZER, + SND_PCM_CLASS_LAST = SND_PCM_CLASS_DIGITIZER +} snd_pcm_class_t; + +/** PCM subclass */ +typedef enum _snd_pcm_subclass { + /** subdevices are mixed together */ + SND_PCM_SUBCLASS_GENERIC_MIX = 0, + /** multichannel subdevices are mixed together */ + SND_PCM_SUBCLASS_MULTI_MIX, + SND_PCM_SUBCLASS_LAST = SND_PCM_SUBCLASS_MULTI_MIX +} snd_pcm_subclass_t; + +/** PCM stream (direction) */ +typedef enum _snd_pcm_stream { + /** Playback stream */ + SND_PCM_STREAM_PLAYBACK = 0, + /** Capture stream */ + SND_PCM_STREAM_CAPTURE, + SND_PCM_STREAM_LAST = SND_PCM_STREAM_CAPTURE +} snd_pcm_stream_t; + +/** PCM access type */ +typedef enum _snd_pcm_access { + /** mmap access with simple interleaved channels */ + SND_PCM_ACCESS_MMAP_INTERLEAVED = 0, + /** mmap access with simple non interleaved channels */ + SND_PCM_ACCESS_MMAP_NONINTERLEAVED, + /** mmap access with complex placement */ + SND_PCM_ACCESS_MMAP_COMPLEX, + /** snd_pcm_readi/snd_pcm_writei access */ + SND_PCM_ACCESS_RW_INTERLEAVED, + /** snd_pcm_readn/snd_pcm_writen access */ + SND_PCM_ACCESS_RW_NONINTERLEAVED, + SND_PCM_ACCESS_LAST = SND_PCM_ACCESS_RW_NONINTERLEAVED +} snd_pcm_access_t; + +/** PCM sample format */ +typedef enum _snd_pcm_format { + /** Unknown */ + SND_PCM_FORMAT_UNKNOWN = -1, + /** Signed 8 bit */ + SND_PCM_FORMAT_S8 = 0, + /** Unsigned 8 bit */ + SND_PCM_FORMAT_U8, + /** Signed 16 bit Little Endian */ + SND_PCM_FORMAT_S16_LE, + /** Signed 16 bit Big Endian */ + SND_PCM_FORMAT_S16_BE, + /** Unsigned 16 bit Little Endian */ + SND_PCM_FORMAT_U16_LE, + /** Unsigned 16 bit Big Endian */ + SND_PCM_FORMAT_U16_BE, + /** Signed 24 bit Little Endian using low three bytes in 32-bit word */ + SND_PCM_FORMAT_S24_LE, + /** Signed 24 bit Big Endian using low three bytes in 32-bit word */ + SND_PCM_FORMAT_S24_BE, + /** Unsigned 24 bit Little Endian using low three bytes in 32-bit word */ + SND_PCM_FORMAT_U24_LE, + /** Unsigned 24 bit Big Endian using low three bytes in 32-bit word */ + SND_PCM_FORMAT_U24_BE, + /** Signed 32 bit Little Endian */ + SND_PCM_FORMAT_S32_LE, + /** Signed 32 bit Big Endian */ + SND_PCM_FORMAT_S32_BE, + /** Unsigned 32 bit Little Endian */ + SND_PCM_FORMAT_U32_LE, + /** Unsigned 32 bit Big Endian */ + SND_PCM_FORMAT_U32_BE, + /** Float 32 bit Little Endian, Range -1.0 to 1.0 */ + SND_PCM_FORMAT_FLOAT_LE, + /** Float 32 bit Big Endian, Range -1.0 to 1.0 */ + SND_PCM_FORMAT_FLOAT_BE, + /** Float 64 bit Little Endian, Range -1.0 to 1.0 */ + SND_PCM_FORMAT_FLOAT64_LE, + /** Float 64 bit Big Endian, Range -1.0 to 1.0 */ + SND_PCM_FORMAT_FLOAT64_BE, + /** IEC-958 Little Endian */ + SND_PCM_FORMAT_IEC958_SUBFRAME_LE, + /** IEC-958 Big Endian */ + SND_PCM_FORMAT_IEC958_SUBFRAME_BE, + /** Mu-Law */ + SND_PCM_FORMAT_MU_LAW, + /** A-Law */ + SND_PCM_FORMAT_A_LAW, + /** Ima-ADPCM */ + SND_PCM_FORMAT_IMA_ADPCM, + /** MPEG */ + SND_PCM_FORMAT_MPEG, + /** GSM */ + SND_PCM_FORMAT_GSM, + /** Special */ + SND_PCM_FORMAT_SPECIAL = 31, + /** Signed 24bit Little Endian in 3bytes format */ + SND_PCM_FORMAT_S24_3LE = 32, + /** Signed 24bit Big Endian in 3bytes format */ + SND_PCM_FORMAT_S24_3BE, + /** Unsigned 24bit Little Endian in 3bytes format */ + SND_PCM_FORMAT_U24_3LE, + /** Unsigned 24bit Big Endian in 3bytes format */ + SND_PCM_FORMAT_U24_3BE, + /** Signed 20bit Little Endian in 3bytes format */ + SND_PCM_FORMAT_S20_3LE, + /** Signed 20bit Big Endian in 3bytes format */ + SND_PCM_FORMAT_S20_3BE, + /** Unsigned 20bit Little Endian in 3bytes format */ + SND_PCM_FORMAT_U20_3LE, + /** Unsigned 20bit Big Endian in 3bytes format */ + SND_PCM_FORMAT_U20_3BE, + /** Signed 18bit Little Endian in 3bytes format */ + SND_PCM_FORMAT_S18_3LE, + /** Signed 18bit Big Endian in 3bytes format */ + SND_PCM_FORMAT_S18_3BE, + /** Unsigned 18bit Little Endian in 3bytes format */ + SND_PCM_FORMAT_U18_3LE, + /** Unsigned 18bit Big Endian in 3bytes format */ + SND_PCM_FORMAT_U18_3BE, + SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_U18_3BE, + +#if __BYTE_ORDER == __LITTLE_ENDIAN + /** Signed 16 bit CPU endian */ + SND_PCM_FORMAT_S16 = SND_PCM_FORMAT_S16_LE, + /** Unsigned 16 bit CPU endian */ + SND_PCM_FORMAT_U16 = SND_PCM_FORMAT_U16_LE, + /** Signed 24 bit CPU endian */ + SND_PCM_FORMAT_S24 = SND_PCM_FORMAT_S24_LE, + /** Unsigned 24 bit CPU endian */ + SND_PCM_FORMAT_U24 = SND_PCM_FORMAT_U24_LE, + /** Signed 32 bit CPU endian */ + SND_PCM_FORMAT_S32 = SND_PCM_FORMAT_S32_LE, + /** Unsigned 32 bit CPU endian */ + SND_PCM_FORMAT_U32 = SND_PCM_FORMAT_U32_LE, + /** Float 32 bit CPU endian */ + SND_PCM_FORMAT_FLOAT = SND_PCM_FORMAT_FLOAT_LE, + /** Float 64 bit CPU endian */ + SND_PCM_FORMAT_FLOAT64 = SND_PCM_FORMAT_FLOAT64_LE, + /** IEC-958 CPU Endian */ + SND_PCM_FORMAT_IEC958_SUBFRAME = SND_PCM_FORMAT_IEC958_SUBFRAME_LE +#elif __BYTE_ORDER == __BIG_ENDIAN + /** Signed 16 bit CPU endian */ + SND_PCM_FORMAT_S16 = SND_PCM_FORMAT_S16_BE, + /** Unsigned 16 bit CPU endian */ + SND_PCM_FORMAT_U16 = SND_PCM_FORMAT_U16_BE, + /** Signed 24 bit CPU endian */ + SND_PCM_FORMAT_S24 = SND_PCM_FORMAT_S24_BE, + /** Unsigned 24 bit CPU endian */ + SND_PCM_FORMAT_U24 = SND_PCM_FORMAT_U24_BE, + /** Signed 32 bit CPU endian */ + SND_PCM_FORMAT_S32 = SND_PCM_FORMAT_S32_BE, + /** Unsigned 32 bit CPU endian */ + SND_PCM_FORMAT_U32 = SND_PCM_FORMAT_U32_BE, + /** Float 32 bit CPU endian */ + SND_PCM_FORMAT_FLOAT = SND_PCM_FORMAT_FLOAT_BE, + /** Float 64 bit CPU endian */ + SND_PCM_FORMAT_FLOAT64 = SND_PCM_FORMAT_FLOAT64_BE, + /** IEC-958 CPU Endian */ + SND_PCM_FORMAT_IEC958_SUBFRAME = SND_PCM_FORMAT_IEC958_SUBFRAME_BE +#else +#error "Unknown endian" +#endif +} snd_pcm_format_t; + +/** PCM sample subformat */ +typedef enum _snd_pcm_subformat { + /** Standard */ + SND_PCM_SUBFORMAT_STD = 0, + SND_PCM_SUBFORMAT_LAST = SND_PCM_SUBFORMAT_STD +} snd_pcm_subformat_t; + +/** PCM state */ +typedef enum _snd_pcm_state { + /** Open */ + SND_PCM_STATE_OPEN = 0, + /** Setup installed */ + SND_PCM_STATE_SETUP, + /** Ready to start */ + SND_PCM_STATE_PREPARED, + /** Running */ + SND_PCM_STATE_RUNNING, + /** Stopped: underrun (playback) or overrun (capture) detected */ + SND_PCM_STATE_XRUN, + /** Draining: running (playback) or stopped (capture) */ + SND_PCM_STATE_DRAINING, + /** Paused */ + SND_PCM_STATE_PAUSED, + /** Hardware is suspended */ + SND_PCM_STATE_SUSPENDED, + /** Hardware is disconnected */ + SND_PCM_STATE_DISCONNECTED, + SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED +} snd_pcm_state_t; + +/** PCM start mode */ +typedef enum _snd_pcm_start { + /** Automatic start on data read/write */ + SND_PCM_START_DATA = 0, + /** Explicit start */ + SND_PCM_START_EXPLICIT, + SND_PCM_START_LAST = SND_PCM_START_EXPLICIT +} snd_pcm_start_t; + +/** PCM xrun mode */ +typedef enum _snd_pcm_xrun { + /** Xrun detection disabled */ + SND_PCM_XRUN_NONE = 0, + /** Stop on xrun detection */ + SND_PCM_XRUN_STOP, + SND_PCM_XRUN_LAST = SND_PCM_XRUN_STOP +} snd_pcm_xrun_t; + +/** PCM timestamp mode */ +typedef enum _snd_pcm_tstamp { + /** No timestamp */ + SND_PCM_TSTAMP_NONE = 0, + /** Update timestamp at every hardware position update */ + SND_PCM_TSTAMP_ENABLE, + /** Equivalent with #SND_PCM_TSTAMP_ENABLE, + * just for compatibility with older versions + */ + SND_PCM_TSTAMP_MMAP = SND_PCM_TSTAMP_ENABLE, + SND_PCM_TSTAMP_LAST = SND_PCM_TSTAMP_ENABLE +} snd_pcm_tstamp_t; + +/** Unsigned frames quantity */ +typedef unsigned long snd_pcm_uframes_t; +/** Signed frames quantity */ +typedef long snd_pcm_sframes_t; + +/** Non blocking mode (flag for open mode) \hideinitializer */ +#define SND_PCM_NONBLOCK 0x00000001 +/** Async notification (flag for open mode) \hideinitializer */ +#define SND_PCM_ASYNC 0x00000002 +/** Disable automatic (but not forced!) rate resamplinig */ +#define SND_PCM_NO_AUTO_RESAMPLE 0x00010000 +/** Disable automatic (but not forced!) channel conversion */ +#define SND_PCM_NO_AUTO_CHANNELS 0x00020000 +/** Disable automatic (but not forced!) format conversion */ +#define SND_PCM_NO_AUTO_FORMAT 0x00040000 +/** Disable soft volume control */ +#define SND_PCM_NO_SOFTVOL 0x00080000 + +/** PCM handle */ +typedef struct _snd_pcm snd_pcm_t; + +/** PCM type */ +enum _snd_pcm_type { + /** Kernel level PCM */ + SND_PCM_TYPE_HW = 0, + /** Hooked PCM */ + SND_PCM_TYPE_HOOKS, + /** One or more linked PCM with exclusive access to selected + channels */ + SND_PCM_TYPE_MULTI, + /** File writing plugin */ + SND_PCM_TYPE_FILE, + /** Null endpoint PCM */ + SND_PCM_TYPE_NULL, + /** Shared memory client PCM */ + SND_PCM_TYPE_SHM, + /** INET client PCM (not yet implemented) */ + SND_PCM_TYPE_INET, + /** Copying plugin */ + SND_PCM_TYPE_COPY, + /** Linear format conversion PCM */ + SND_PCM_TYPE_LINEAR, + /** A-Law format conversion PCM */ + SND_PCM_TYPE_ALAW, + /** Mu-Law format conversion PCM */ + SND_PCM_TYPE_MULAW, + /** IMA-ADPCM format conversion PCM */ + SND_PCM_TYPE_ADPCM, + /** Rate conversion PCM */ + SND_PCM_TYPE_RATE, + /** Attenuated static route PCM */ + SND_PCM_TYPE_ROUTE, + /** Format adjusted PCM */ + SND_PCM_TYPE_PLUG, + /** Sharing PCM */ + SND_PCM_TYPE_SHARE, + /** Meter plugin */ + SND_PCM_TYPE_METER, + /** Mixing PCM */ + SND_PCM_TYPE_MIX, + /** Attenuated dynamic route PCM (not yet implemented) */ + SND_PCM_TYPE_DROUTE, + /** Loopback server plugin (not yet implemented) */ + SND_PCM_TYPE_LBSERVER, + /** Linear Integer <-> Linear Float format conversion PCM */ + SND_PCM_TYPE_LINEAR_FLOAT, + /** LADSPA integration plugin */ + SND_PCM_TYPE_LADSPA, + /** Direct Mixing plugin */ + SND_PCM_TYPE_DMIX, + /** Jack Audio Connection Kit plugin */ + SND_PCM_TYPE_JACK, + /** Direct Snooping plugin */ + SND_PCM_TYPE_DSNOOP, + /** Direct Sharing plugin */ + SND_PCM_TYPE_DSHARE, + /** IEC958 subframe plugin */ + SND_PCM_TYPE_IEC958, + /** Soft volume plugin */ + SND_PCM_TYPE_SOFTVOL, + /** External I/O plugin */ + SND_PCM_TYPE_IOPLUG, + /** External filter plugin */ + SND_PCM_TYPE_EXTPLUG, + /** Mmap-emulation plugin */ + SND_PCM_TYPE_MMAP_EMUL, + SND_PCM_TYPE_LAST = SND_PCM_TYPE_MMAP_EMUL +}; + +/** PCM type */ +typedef enum _snd_pcm_type snd_pcm_type_t; + +/** PCM area specification */ +typedef struct _snd_pcm_channel_area { + /** base address of channel samples */ + void *addr; + /** offset to first sample in bits */ + unsigned int first; + /** samples distance in bits */ + unsigned int step; +} snd_pcm_channel_area_t; + +/** PCM synchronization ID */ +typedef union _snd_pcm_sync_id { + /** 8-bit ID */ + unsigned char id[16]; + /** 16-bit ID */ + unsigned short id16[8]; + /** 32-bit ID */ + unsigned int id32[4]; +} snd_pcm_sync_id_t; + +/** #SND_PCM_TYPE_METER scope handle */ +typedef struct _snd_pcm_scope snd_pcm_scope_t; + +int snd_pcm_open(snd_pcm_t **pcm, const char *name, + snd_pcm_stream_t stream, int mode); +int snd_pcm_open_lconf(snd_pcm_t **pcm, const char *name, + snd_pcm_stream_t stream, int mode, + snd_config_t *lconf); + +int snd_pcm_close(snd_pcm_t *pcm); +const char *snd_pcm_name(snd_pcm_t *pcm); +snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm); +snd_pcm_stream_t snd_pcm_stream(snd_pcm_t *pcm); +int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm); +int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); +int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock); +int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm, + snd_async_callback_t callback, void *private_data); +snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler); +int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info); +int snd_pcm_hw_params_current(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_free(snd_pcm_t *pcm); +int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); +int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); +int snd_pcm_prepare(snd_pcm_t *pcm); +int snd_pcm_reset(snd_pcm_t *pcm); +int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status); +int snd_pcm_start(snd_pcm_t *pcm); +int snd_pcm_drop(snd_pcm_t *pcm); +int snd_pcm_drain(snd_pcm_t *pcm); +int snd_pcm_pause(snd_pcm_t *pcm, int enable); +snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm); +int snd_pcm_hwsync(snd_pcm_t *pcm); +int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); +int snd_pcm_resume(snd_pcm_t *pcm); +int snd_pcm_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, snd_htimestamp_t *tstamp); +snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm); +snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm); +int snd_pcm_avail_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *availp, snd_pcm_sframes_t *delayp); +snd_pcm_sframes_t snd_pcm_rewindable(snd_pcm_t *pcm); +snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_forwardable(snd_pcm_t *pcm); +snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); +int snd_pcm_wait(snd_pcm_t *pcm, int timeout); + +int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2); +int snd_pcm_unlink(snd_pcm_t *pcm); + +//int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem); + +/* + * application helpers - these functions are implemented on top + * of the basic API + */ + +int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent); +int snd_pcm_set_params(snd_pcm_t *pcm, + snd_pcm_format_t format, + snd_pcm_access_t access, + unsigned int channels, + unsigned int rate, + int soft_resample, + unsigned int latency); +int snd_pcm_get_params(snd_pcm_t *pcm, + snd_pcm_uframes_t *buffer_size, + snd_pcm_uframes_t *period_size); + +/** \} */ + +/** + * \defgroup PCM_Info Stream Information + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +size_t snd_pcm_info_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_pcm_info_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_info_alloca(ptr) __snd_alloca(ptr, snd_pcm_info) +int snd_pcm_info_malloc(snd_pcm_info_t **ptr); +void snd_pcm_info_free(snd_pcm_info_t *obj); +void snd_pcm_info_copy(snd_pcm_info_t *dst, const snd_pcm_info_t *src); +unsigned int snd_pcm_info_get_device(const snd_pcm_info_t *obj); +unsigned int snd_pcm_info_get_subdevice(const snd_pcm_info_t *obj); +snd_pcm_stream_t snd_pcm_info_get_stream(const snd_pcm_info_t *obj); +int snd_pcm_info_get_card(const snd_pcm_info_t *obj); +const char *snd_pcm_info_get_id(const snd_pcm_info_t *obj); +const char *snd_pcm_info_get_name(const snd_pcm_info_t *obj); +const char *snd_pcm_info_get_subdevice_name(const snd_pcm_info_t *obj); +snd_pcm_class_t snd_pcm_info_get_class(const snd_pcm_info_t *obj); +snd_pcm_subclass_t snd_pcm_info_get_subclass(const snd_pcm_info_t *obj); +unsigned int snd_pcm_info_get_subdevices_count(const snd_pcm_info_t *obj); +unsigned int snd_pcm_info_get_subdevices_avail(const snd_pcm_info_t *obj); +snd_pcm_sync_id_t snd_pcm_info_get_sync(const snd_pcm_info_t *obj); +void snd_pcm_info_set_device(snd_pcm_info_t *obj, unsigned int val); +void snd_pcm_info_set_subdevice(snd_pcm_info_t *obj, unsigned int val); +void snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val); + +/** \} */ + +/** + * \defgroup PCM_HW_Params Hardware Parameters + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +int snd_pcm_hw_params_can_mmap_sample_resolution(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_is_double(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_is_batch(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_is_block_transfer(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_is_monotonic(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_can_overrange(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_can_resume(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params, + unsigned int *rate_num, + unsigned int *rate_den); +int snd_pcm_hw_params_get_sbits(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_get_fifo_size(const snd_pcm_hw_params_t *params); + +#if 0 +typedef struct _snd_pcm_hw_strategy snd_pcm_hw_strategy_t; + +/* choices need to be sorted on ascending badness */ +typedef struct _snd_pcm_hw_strategy_simple_choices_list { + unsigned int value; + unsigned int badness; +} snd_pcm_hw_strategy_simple_choices_list_t; + +int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + const snd_pcm_hw_strategy_t *strategy, + unsigned int badness_min, + unsigned int badness_max); + +void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy); +int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp, + unsigned int badness_min, + unsigned int badness_max); +int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm, + snd_pcm_hw_params_t *fail, + snd_pcm_hw_params_t *success, + unsigned int depth, + snd_output_t *out); + +#endif + +size_t snd_pcm_hw_params_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_pcm_hw_params_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params) +int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr); +void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj); +void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src); + +#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_HW_PARAMS_API) + +int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); +int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); +int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); +int snd_pcm_hw_params_set_access_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); +int snd_pcm_hw_params_set_access_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); +int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); +int snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); + +int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val); +int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +int snd_pcm_hw_params_set_format_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); +int snd_pcm_hw_params_set_format_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); +int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); +void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); + +int snd_pcm_hw_params_get_subformat(const snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); +int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat); +int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat); +int snd_pcm_hw_params_set_subformat_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); +int snd_pcm_hw_params_set_subformat_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); +int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); +void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); + +int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max); +int snd_pcm_hw_params_set_channels_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); + +int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_get_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_get_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); + +int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_period_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); + +int snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); +int snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); +int snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); +int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir); +int snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_periods_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_periods_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_buffer_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_get_buffer_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); + +int snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max); +int snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); + +#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_HW_PARAMS_API */ + +int snd_pcm_hw_params_get_min_align(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); + +/** \} */ + +/** + * \defgroup PCM_SW_Params Software Parameters + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +size_t snd_pcm_sw_params_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_pcm_sw_params_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_sw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_sw_params) +int snd_pcm_sw_params_malloc(snd_pcm_sw_params_t **ptr); +void snd_pcm_sw_params_free(snd_pcm_sw_params_t *obj); +void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t *src); +int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); + +#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_SW_PARAMS_API) + +int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val); +int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val); +int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val); +int snd_pcm_sw_params_get_period_event(const snd_pcm_sw_params_t *params, int *val); +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *paramsm, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_silence_size(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); + +#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_SW_PARAMS_API */ + +/** \} */ + +/* include old API */ +#ifndef ALSA_LIBRARY_BUILD +#if defined(ALSA_PCM_OLD_HW_PARAMS_API) || defined(ALSA_PCM_OLD_SW_PARAMS_API) +#include "pcm_old.h" +#endif +#endif + +/** + * \defgroup PCM_Access Access Mask Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +size_t snd_pcm_access_mask_sizeof(void); +/** \hideinitializer + * \brief allocate an empty #snd_pcm_access_mask_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_access_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_access_mask) +int snd_pcm_access_mask_malloc(snd_pcm_access_mask_t **ptr); +void snd_pcm_access_mask_free(snd_pcm_access_mask_t *obj); +void snd_pcm_access_mask_copy(snd_pcm_access_mask_t *dst, const snd_pcm_access_mask_t *src); +void snd_pcm_access_mask_none(snd_pcm_access_mask_t *mask); +void snd_pcm_access_mask_any(snd_pcm_access_mask_t *mask); +int snd_pcm_access_mask_test(const snd_pcm_access_mask_t *mask, snd_pcm_access_t val); +int snd_pcm_access_mask_empty(const snd_pcm_access_mask_t *mask); +void snd_pcm_access_mask_set(snd_pcm_access_mask_t *mask, snd_pcm_access_t val); +void snd_pcm_access_mask_reset(snd_pcm_access_mask_t *mask, snd_pcm_access_t val); + +/** \} */ + +/** + * \defgroup PCM_Format Format Mask Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +size_t snd_pcm_format_mask_sizeof(void); +/** \hideinitializer + * \brief allocate an empty #snd_pcm_format_mask_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_format_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_format_mask) +int snd_pcm_format_mask_malloc(snd_pcm_format_mask_t **ptr); +void snd_pcm_format_mask_free(snd_pcm_format_mask_t *obj); +void snd_pcm_format_mask_copy(snd_pcm_format_mask_t *dst, const snd_pcm_format_mask_t *src); +void snd_pcm_format_mask_none(snd_pcm_format_mask_t *mask); +void snd_pcm_format_mask_any(snd_pcm_format_mask_t *mask); +int snd_pcm_format_mask_test(const snd_pcm_format_mask_t *mask, snd_pcm_format_t val); +int snd_pcm_format_mask_empty(const snd_pcm_format_mask_t *mask); +void snd_pcm_format_mask_set(snd_pcm_format_mask_t *mask, snd_pcm_format_t val); +void snd_pcm_format_mask_reset(snd_pcm_format_mask_t *mask, snd_pcm_format_t val); + +/** \} */ + +/** + * \defgroup PCM_SubFormat Subformat Mask Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +size_t snd_pcm_subformat_mask_sizeof(void); +/** \hideinitializer + * \brief allocate an empty #snd_pcm_subformat_mask_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_subformat_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_subformat_mask) +int snd_pcm_subformat_mask_malloc(snd_pcm_subformat_mask_t **ptr); +void snd_pcm_subformat_mask_free(snd_pcm_subformat_mask_t *obj); +void snd_pcm_subformat_mask_copy(snd_pcm_subformat_mask_t *dst, const snd_pcm_subformat_mask_t *src); +void snd_pcm_subformat_mask_none(snd_pcm_subformat_mask_t *mask); +void snd_pcm_subformat_mask_any(snd_pcm_subformat_mask_t *mask); +int snd_pcm_subformat_mask_test(const snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val); +int snd_pcm_subformat_mask_empty(const snd_pcm_subformat_mask_t *mask); +void snd_pcm_subformat_mask_set(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val); +void snd_pcm_subformat_mask_reset(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val); + +/** \} */ + +/** + * \defgroup PCM_Status Status Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +size_t snd_pcm_status_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_pcm_status_t using standard alloca + * \param ptr returned pointer + */ +#define snd_pcm_status_alloca(ptr) __snd_alloca(ptr, snd_pcm_status) +int snd_pcm_status_malloc(snd_pcm_status_t **ptr); +void snd_pcm_status_free(snd_pcm_status_t *obj); +void snd_pcm_status_copy(snd_pcm_status_t *dst, const snd_pcm_status_t *src); +snd_pcm_state_t snd_pcm_status_get_state(const snd_pcm_status_t *obj); +void snd_pcm_status_get_trigger_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr); +void snd_pcm_status_get_trigger_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); +void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr); +void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); +snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj); +snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj); +snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj); +snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj); + +/** \} */ + +/** + * \defgroup PCM_Description Description Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +const char *snd_pcm_type_name(snd_pcm_type_t type); +const char *snd_pcm_stream_name(const snd_pcm_stream_t stream); +const char *snd_pcm_access_name(const snd_pcm_access_t _access); +const char *snd_pcm_format_name(const snd_pcm_format_t format); +const char *snd_pcm_format_description(const snd_pcm_format_t format); +const char *snd_pcm_subformat_name(const snd_pcm_subformat_t subformat); +const char *snd_pcm_subformat_description(const snd_pcm_subformat_t subformat); +snd_pcm_format_t snd_pcm_format_value(const char* name); +const char *snd_pcm_tstamp_mode_name(const snd_pcm_tstamp_t mode); +const char *snd_pcm_state_name(const snd_pcm_state_t state); + +/** \} */ + +/** + * \defgroup PCM_Dump Debug Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +int snd_pcm_dump(snd_pcm_t *pcm, snd_output_t *out); +int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, snd_output_t *out); +int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out); +int snd_pcm_dump_setup(snd_pcm_t *pcm, snd_output_t *out); +int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params, snd_output_t *out); +int snd_pcm_sw_params_dump(snd_pcm_sw_params_t *params, snd_output_t *out); +int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out); + +/** \} */ + +/** + * \defgroup PCM_Direct Direct Access (MMAP) Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +int snd_pcm_mmap_begin(snd_pcm_t *pcm, + const snd_pcm_channel_area_t **areas, + snd_pcm_uframes_t *offset, + snd_pcm_uframes_t *frames); +snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); + +/** \} */ + +/** + * \defgroup PCM_Helpers Helper Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +int snd_pcm_format_signed(snd_pcm_format_t format); +int snd_pcm_format_unsigned(snd_pcm_format_t format); +int snd_pcm_format_linear(snd_pcm_format_t format); +int snd_pcm_format_float(snd_pcm_format_t format); +int snd_pcm_format_little_endian(snd_pcm_format_t format); +int snd_pcm_format_big_endian(snd_pcm_format_t format); +int snd_pcm_format_cpu_endian(snd_pcm_format_t format); +int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ +int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ +snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian); +ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); +u_int8_t snd_pcm_format_silence(snd_pcm_format_t format); +u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format); +u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format); +u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format); +int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int samples); + +snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes); +ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames); +long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes); +ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples); + +int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, snd_pcm_uframes_t dst_offset, + unsigned int samples, snd_pcm_format_t format); +int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_channels, snd_pcm_uframes_t dst_offset, + unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format); +int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_channel, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_channel, snd_pcm_uframes_t src_offset, + unsigned int samples, snd_pcm_format_t format); +int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_channels, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_channels, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format); + +/** \} */ + +/** + * \defgroup PCM_Hook Hook Extension + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +/** type of pcm hook */ +typedef enum _snd_pcm_hook_type { + SND_PCM_HOOK_TYPE_HW_PARAMS = 0, + SND_PCM_HOOK_TYPE_HW_FREE, + SND_PCM_HOOK_TYPE_CLOSE, + SND_PCM_HOOK_TYPE_LAST = SND_PCM_HOOK_TYPE_CLOSE +} snd_pcm_hook_type_t; + +/** PCM hook container */ +typedef struct _snd_pcm_hook snd_pcm_hook_t; +/** PCM hook callback function */ +typedef int (*snd_pcm_hook_func_t)(snd_pcm_hook_t *hook); +snd_pcm_t *snd_pcm_hook_get_pcm(snd_pcm_hook_t *hook); +void *snd_pcm_hook_get_private(snd_pcm_hook_t *hook); +void snd_pcm_hook_set_private(snd_pcm_hook_t *hook, void *private_data); +int snd_pcm_hook_add(snd_pcm_hook_t **hookp, snd_pcm_t *pcm, + snd_pcm_hook_type_t type, + snd_pcm_hook_func_t func, void *private_data); +int snd_pcm_hook_remove(snd_pcm_hook_t *hook); + +/** \} */ + +/** + * \defgroup PCM_Scope Scope Plugin Extension + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +/** #SND_PCM_TYPE_METER scope functions */ +typedef struct _snd_pcm_scope_ops { + /** \brief Enable and prepare it using current params + * \param scope scope handle + */ + int (*enable)(snd_pcm_scope_t *scope); + /** \brief Disable + * \param scope scope handle + */ + void (*disable)(snd_pcm_scope_t *scope); + /** \brief PCM has been started + * \param scope scope handle + */ + void (*start)(snd_pcm_scope_t *scope); + /** \brief PCM has been stopped + * \param scope scope handle + */ + void (*stop)(snd_pcm_scope_t *scope); + /** \brief New frames are present + * \param scope scope handle + */ + void (*update)(snd_pcm_scope_t *scope); + /** \brief Reset status + * \param scope scope handle + */ + void (*reset)(snd_pcm_scope_t *scope); + /** \brief PCM is closing + * \param scope scope handle + */ + void (*close)(snd_pcm_scope_t *scope); +} snd_pcm_scope_ops_t; + +snd_pcm_uframes_t snd_pcm_meter_get_bufsize(snd_pcm_t *pcm); +unsigned int snd_pcm_meter_get_channels(snd_pcm_t *pcm); +unsigned int snd_pcm_meter_get_rate(snd_pcm_t *pcm); +snd_pcm_uframes_t snd_pcm_meter_get_now(snd_pcm_t *pcm); +snd_pcm_uframes_t snd_pcm_meter_get_boundary(snd_pcm_t *pcm); +int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope); +snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name); +int snd_pcm_scope_malloc(snd_pcm_scope_t **ptr); +void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, + const snd_pcm_scope_ops_t *val); +void snd_pcm_scope_set_name(snd_pcm_scope_t *scope, const char *val); +const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope); +void *snd_pcm_scope_get_callback_private(snd_pcm_scope_t *scope); +void snd_pcm_scope_set_callback_private(snd_pcm_scope_t *scope, void *val); +int snd_pcm_scope_s16_open(snd_pcm_t *pcm, const char *name, + snd_pcm_scope_t **scopep); +int16_t *snd_pcm_scope_s16_get_channel_buffer(snd_pcm_scope_t *scope, + unsigned int channel); + +/** \} */ + +/** + * \defgroup PCM_Simple Simple setup functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +/** Simple PCM latency type */ +typedef enum _snd_spcm_latency { + /** standard latency - for standard playback or capture + (estimated latency in one direction 350ms) */ + SND_SPCM_LATENCY_STANDARD = 0, + /** medium latency - software phones etc. + (estimated latency in one direction maximally 25ms */ + SND_SPCM_LATENCY_MEDIUM, + /** realtime latency - realtime applications (effect processors etc.) + (estimated latency in one direction 5ms and better) */ + SND_SPCM_LATENCY_REALTIME +} snd_spcm_latency_t; + +/** Simple PCM xrun type */ +typedef enum _snd_spcm_xrun_type { + /** driver / library will ignore all xruns, the stream runs forever */ + SND_SPCM_XRUN_IGNORE = 0, + /** driver / library stops the stream when an xrun occurs */ + SND_SPCM_XRUN_STOP +} snd_spcm_xrun_type_t; + +/** Simple PCM duplex type */ +typedef enum _snd_spcm_duplex_type { + /** liberal duplex - the buffer and period sizes might not match */ + SND_SPCM_DUPLEX_LIBERAL = 0, + /** pedantic duplex - the buffer and period sizes MUST match */ + SND_SPCM_DUPLEX_PEDANTIC +} snd_spcm_duplex_type_t; + +int snd_spcm_init(snd_pcm_t *pcm, + unsigned int rate, + unsigned int channels, + snd_pcm_format_t format, + snd_pcm_subformat_t subformat, + snd_spcm_latency_t latency, + snd_pcm_access_t _access, + snd_spcm_xrun_type_t xrun_type); + +int snd_spcm_init_duplex(snd_pcm_t *playback_pcm, + snd_pcm_t *capture_pcm, + unsigned int rate, + unsigned int channels, + snd_pcm_format_t format, + snd_pcm_subformat_t subformat, + snd_spcm_latency_t latency, + snd_pcm_access_t _access, + snd_spcm_xrun_type_t xrun_type, + snd_spcm_duplex_type_t duplex_type); + +int snd_spcm_init_get_params(snd_pcm_t *pcm, + unsigned int *rate, + snd_pcm_uframes_t *buffer_size, + snd_pcm_uframes_t *period_size); + +/** \} */ + +/** + * \defgroup PCM_Deprecated Deprecated Functions + * \ingroup PCM + * See the \ref pcm page for more details. + * \{ + */ + +/* Deprecated functions, for compatibility */ +const char *snd_pcm_start_mode_name(snd_pcm_start_t mode) __attribute__((deprecated)); +const char *snd_pcm_xrun_mode_name(snd_pcm_xrun_t mode) __attribute__((deprecated)); +int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_start_t val) __attribute__((deprecated)); +snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *params) __attribute__((deprecated)); +int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val) __attribute__((deprecated)); +snd_pcm_xrun_t snd_pcm_sw_params_get_xrun_mode(const snd_pcm_sw_params_t *params) __attribute__((deprecated)); +#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_SW_PARAMS_API) +int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) __attribute__((deprecated)); +int snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) __attribute__((deprecated)); +int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, unsigned int val) __attribute__((deprecated)); +int snd_pcm_sw_params_get_sleep_min(const snd_pcm_sw_params_t *params, unsigned int *val) __attribute__((deprecated)); +#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_SW_PARAMS_API */ +#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_HW_PARAMS_API) +int snd_pcm_hw_params_get_tick_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_get_tick_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_get_tick_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_test_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +int snd_pcm_hw_params_set_tick_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); +#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_HW_PARAMS_API */ + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_PCM_H */ diff --git a/include/pcm_external.h b/include/pcm_external.h new file mode 100644 index 0000000..5750418 --- /dev/null +++ b/include/pcm_external.h @@ -0,0 +1,70 @@ +/** + * \file include/pcm_external.h + * \brief External PCM plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * Extern PCM plugin SDK. + */ + +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __ALSA_PCM_EXTERNAL_H +#define __ALSA_PCM_EXTERNAL_H + +#include "pcm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Plugin_SDK External PCM plugin SDK + * \{ + */ + +/** + * Define the object entry for external PCM plugins + */ +#define SND_PCM_PLUGIN_ENTRY(name) _snd_pcm_##name##_open + +/** + * Define the symbols of the given plugin with versions + */ +#define SND_PCM_PLUGIN_SYMBOL(name) SND_DLSYM_BUILD_VERSION(SND_PCM_PLUGIN_ENTRY(name), SND_PCM_DLSYM_VERSION); + +/** + * Define the plugin + */ +#define SND_PCM_PLUGIN_DEFINE_FUNC(plugin) \ +int SND_PCM_PLUGIN_ENTRY(plugin) (snd_pcm_t **pcmp, const char *name,\ + snd_config_t *root, snd_config_t *conf, \ + snd_pcm_stream_t stream, int mode) + +#include "pcm_ioplug.h" +#include "pcm_extplug.h" + +int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, + int *cchannelsp, int *hwctlp); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_PCM_EXTERNAL_H */ diff --git a/include/pcm_extplug.h b/include/pcm_extplug.h new file mode 100644 index 0000000..b14c5be --- /dev/null +++ b/include/pcm_extplug.h @@ -0,0 +1,189 @@ +/** + * \file include/pcm_extplug.h + * \brief External Filter-Plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * External Filter-Plugin SDK + */ + +/* + * ALSA external PCM plugin SDK (draft version) + * + * Copyright (c) 2005 Takashi Iwai + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_PCM_EXTPLUG_H +#define __ALSA_PCM_EXTPLUG_H + +/** + * \defgroup PCM_ExtPlug External Filter plugin SDK + * \ingroup Plugin_SDK + * See the \ref pcm page for more details. + * \{ + */ + +/** hw constraints for extplug */ +enum { + SND_PCM_EXTPLUG_HW_FORMAT, /**< format */ + SND_PCM_EXTPLUG_HW_CHANNELS, /**< channels */ + SND_PCM_EXTPLUG_HW_PARAMS /**< max number of hw constraints */ +}; + +/** Handle of external filter plugin */ +typedef struct snd_pcm_extplug snd_pcm_extplug_t; +/** Callback table of extplug */ +typedef struct snd_pcm_extplug_callback snd_pcm_extplug_callback_t; + +/* + * Protocol version + */ +#define SND_PCM_EXTPLUG_VERSION_MAJOR 1 /**< Protocol major version */ +#define SND_PCM_EXTPLUG_VERSION_MINOR 0 /**< Protocol minor version */ +#define SND_PCM_EXTPLUG_VERSION_TINY 1 /**< Protocol tiny version */ +/** + * Filter-plugin protocol version + */ +#define SND_PCM_EXTPLUG_VERSION ((SND_PCM_EXTPLUG_VERSION_MAJOR<<16) |\ + (SND_PCM_EXTPLUG_VERSION_MINOR<<8) |\ + (SND_PCM_EXTPLUG_VERSION_TINY)) + +/** Handle of extplug */ +struct snd_pcm_extplug { + /** + * protocol version; #SND_PCM_EXTPLUG_VERSION must be filled here + * before calling #snd_pcm_extplug_create() + */ + unsigned int version; + /** + * name of this plugin; must be filled before calling #snd_pcm_extplug_create() + */ + const char *name; + /** + * callbacks of this plugin; must be filled before calling #snd_pcm_extplug_create() + */ + const snd_pcm_extplug_callback_t *callback; + /** + * private data, which can be used freely in the driver callbacks + */ + void *private_data; + /** + * PCM handle filled by #snd_pcm_extplug_create() + */ + snd_pcm_t *pcm; + /** + * stream direction; read-only status + */ + snd_pcm_stream_t stream; + /** + * format hw parameter; filled after hw_params is caled + */ + snd_pcm_format_t format; + /** + * subformat hw parameter; filled after hw_params is caled + */ + snd_pcm_subformat_t subformat; + /** + * channels hw parameter; filled after hw_params is caled + */ + unsigned int channels; + /** + * rate hw parameter; filled after hw_params is caled + */ + unsigned int rate; + /** + * slave_format hw parameter; filled after hw_params is caled + */ + snd_pcm_format_t slave_format; + /** + * slave_subformat hw parameter; filled after hw_params is caled + */ + snd_pcm_subformat_t slave_subformat; + /** + * slave_channels hw parameter; filled after hw_params is caled + */ + unsigned int slave_channels; +}; + +/** Callback table of extplug */ +struct snd_pcm_extplug_callback { + /** + * transfer between source and destination; this is a required callback + */ + snd_pcm_sframes_t (*transfer)(snd_pcm_extplug_t *ext, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + snd_pcm_uframes_t size); + /** + * close the PCM; optional + */ + int (*close)(snd_pcm_extplug_t *ext); + /** + * hw_params; optional + */ + int (*hw_params)(snd_pcm_extplug_t *ext, snd_pcm_hw_params_t *params); + /** + * hw_free; optional + */ + int (*hw_free)(snd_pcm_extplug_t *ext); + /** + * dump; optional + */ + void (*dump)(snd_pcm_extplug_t *ext, snd_output_t *out); + /** + * init; optional initialization called at prepare or reset + */ + int (*init)(snd_pcm_extplug_t *ext); +}; + + +int snd_pcm_extplug_create(snd_pcm_extplug_t *ext, const char *name, + snd_config_t *root, snd_config_t *slave_conf, + snd_pcm_stream_t stream, int mode); +int snd_pcm_extplug_delete(snd_pcm_extplug_t *ext); + +/* clear hw_parameter setting */ +void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *ext); + +/* hw_parameter setting */ +int snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); +int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); +int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); +int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); + +/** + * set the parameter constraint with a single value + */ +static inline int snd_pcm_extplug_set_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) +{ + return snd_pcm_extplug_set_param_list(extplug, type, 1, &val); +} + +/** + * set the parameter constraint for slave PCM with a single value + */ +static inline int snd_pcm_extplug_set_slave_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) +{ + return snd_pcm_extplug_set_slave_param_list(extplug, type, 1, &val); +} + +/** \} */ + +#endif /* __ALSA_PCM_EXTPLUG_H */ diff --git a/include/pcm_ioplug.h b/include/pcm_ioplug.h new file mode 100644 index 0000000..6331cf0 --- /dev/null +++ b/include/pcm_ioplug.h @@ -0,0 +1,217 @@ +/** + * \file include/pcm_ioplug.h + * \brief External I/O-Plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * External I/O-Plugin SDK + */ + +/* + * ALSA external PCM plugin SDK + * + * Copyright (c) 2005 Takashi Iwai + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_PCM_IOPLUG_H +#define __ALSA_PCM_IOPLUG_H + +/** + * \defgroup PCM_IOPlug External I/O plugin SDK + * \ingroup Plugin_SDK + * See the \ref pcm page for more details. + * \{ + */ + +/** hw constraints for ioplug */ +enum { + SND_PCM_IOPLUG_HW_ACCESS = 0, /**< access type */ + SND_PCM_IOPLUG_HW_FORMAT, /**< format */ + SND_PCM_IOPLUG_HW_CHANNELS, /**< channels */ + SND_PCM_IOPLUG_HW_RATE, /**< rate */ + SND_PCM_IOPLUG_HW_PERIOD_BYTES, /**< period bytes */ + SND_PCM_IOPLUG_HW_BUFFER_BYTES, /**< buffer bytes */ + SND_PCM_IOPLUG_HW_PERIODS, /**< number of periods */ + SND_PCM_IOPLUG_HW_PARAMS /**< max number of hw constraints */ +}; + +/** I/O plugin handle */ +typedef struct snd_pcm_ioplug snd_pcm_ioplug_t; +/** Callback table of ioplug */ +typedef struct snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; + +/* + * bit flags for additional conditions + */ +#define SND_PCM_IOPLUG_FLAG_LISTED (1<<0) /**< list up this PCM */ +#define SND_PCM_IOPLUG_FLAG_MONOTONIC (1<<1) /**< monotonic timestamps */ + +/* + * Protocol version + */ +#define SND_PCM_IOPLUG_VERSION_MAJOR 1 /**< Protocol major version */ +#define SND_PCM_IOPLUG_VERSION_MINOR 0 /**< Protocol minor version */ +#define SND_PCM_IOPLUG_VERSION_TINY 1 /**< Protocol tiny version */ +/** + * IO-plugin protocol version + */ +#define SND_PCM_IOPLUG_VERSION ((SND_PCM_IOPLUG_VERSION_MAJOR<<16) |\ + (SND_PCM_IOPLUG_VERSION_MINOR<<8) |\ + (SND_PCM_IOPLUG_VERSION_TINY)) + +/** Handle of ioplug */ +struct snd_pcm_ioplug { + /** + * protocol version; #SND_PCM_IOPLUG_VERSION must be filled here + * before calling #snd_pcm_ioplug_create() + */ + unsigned int version; + /** + * name of this plugin; must be filled before calling #snd_pcm_ioplug_create() + */ + const char *name; + unsigned int flags; /**< SND_PCM_IOPLUG_FLAG_XXX */ + int poll_fd; /**< poll file descriptor */ + unsigned int poll_events; /**< poll events */ + unsigned int mmap_rw; /**< pseudo mmap mode */ + /** + * callbacks of this plugin; must be filled before calling #snd_pcm_ioplug_create() + */ + const snd_pcm_ioplug_callback_t *callback; + /** + * private data, which can be used freely in the driver callbacks + */ + void *private_data; + /** + * PCM handle filled by #snd_pcm_extplug_create() + */ + snd_pcm_t *pcm; + + snd_pcm_stream_t stream; /**< stream direcion; read-only */ + snd_pcm_state_t state; /**< current PCM state; read-only */ + volatile snd_pcm_uframes_t appl_ptr; /**< application pointer; read-only */ + volatile snd_pcm_uframes_t hw_ptr; /**< hw pointer; read-only */ + int nonblock; /**< non-block mode; read-only */ + + snd_pcm_access_t access; /**< access type; filled after hw_params is called */ + snd_pcm_format_t format; /**< PCM format; filled after hw_params is called */ + unsigned int channels; /**< number of channels; filled after hw_params is called */ + unsigned int rate; /**< rate; filled after hw_params is called */ + snd_pcm_uframes_t period_size; /**< period size; filled after hw_params is called */ + snd_pcm_uframes_t buffer_size; /**< buffer size; filled after hw_params is called */ +}; + +/** Callback table of ioplug */ +struct snd_pcm_ioplug_callback { + /** + * start the PCM; required + */ + int (*start)(snd_pcm_ioplug_t *io); + /** + * stop the PCM; required + */ + int (*stop)(snd_pcm_ioplug_t *io); + /** + * get the current DMA position; required + */ + snd_pcm_sframes_t (*pointer)(snd_pcm_ioplug_t *io); + /** + * transfer the data; optional + */ + snd_pcm_sframes_t (*transfer)(snd_pcm_ioplug_t *io, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size); + /** + * close the PCM; optional + */ + int (*close)(snd_pcm_ioplug_t *io); + /** + * hw_params; optional + */ + int (*hw_params)(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params); + /** + * hw_free; optional + */ + int (*hw_free)(snd_pcm_ioplug_t *io); + /** + * sw_params; optional + */ + int (*sw_params)(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params); + /** + * prepare; optional + */ + int (*prepare)(snd_pcm_ioplug_t *io); + /** + * drain; optional + */ + int (*drain)(snd_pcm_ioplug_t *io); + /** + * toggle pause; optional + */ + int (*pause)(snd_pcm_ioplug_t *io, int enable); + /** + * resume; optional + */ + int (*resume)(snd_pcm_ioplug_t *io); + /** + * poll descriptors count; optional + */ + int (*poll_descriptors_count)(snd_pcm_ioplug_t *io); + /** + * poll descriptors; optional + */ + int (*poll_descriptors)(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space); + /** + * mangle poll events; optional + */ + int (*poll_revents)(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int nfds, unsigned short *revents); + /** + * dump; optional + */ + void (*dump)(snd_pcm_ioplug_t *io, snd_output_t *out); + /** + * get the delay for the running PCM; optional + */ + int (*delay)(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp); +}; + + +int snd_pcm_ioplug_create(snd_pcm_ioplug_t *io, const char *name, + snd_pcm_stream_t stream, int mode); +int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *io); + +/* update poll_fd and mmap_rw */ +int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug); + +/* get a mmap area (for mmap_rw only) */ +const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug); + +/* clear hw_parameter setting */ +void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *io); + +/* hw_parameter setting */ +int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *io, int type, unsigned int min, unsigned int max); +int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *io, int type, unsigned int num_list, const unsigned int *list); + +/* change PCM status */ +int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state); + +/** \} */ + +#endif /* __ALSA_PCM_IOPLUG_H */ diff --git a/include/pcm_old.h b/include/pcm_old.h new file mode 100644 index 0000000..f0de4c3 --- /dev/null +++ b/include/pcm_old.h @@ -0,0 +1,230 @@ +/* + * Old ALSA 0.9.x API + */ + +#ifdef ALSA_PCM_OLD_HW_PARAMS_API + +asm(".symver snd_pcm_hw_params_get_access,snd_pcm_hw_params_get_access@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_access_first,snd_pcm_hw_params_set_access_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_access_last,snd_pcm_hw_params_set_access_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t val); +int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t val); +snd_pcm_access_t snd_pcm_hw_params_set_access_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +snd_pcm_access_t snd_pcm_hw_params_set_access_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); +void snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); + +asm(".symver snd_pcm_hw_params_get_format,snd_pcm_hw_params_get_format@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_format_first,snd_pcm_hw_params_set_format_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_format_last,snd_pcm_hw_params_set_format_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +snd_pcm_format_t snd_pcm_hw_params_set_format_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +snd_pcm_format_t snd_pcm_hw_params_set_format_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); +void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); + +asm(".symver snd_pcm_hw_params_get_subformat,snd_pcm_hw_params_get_subformat@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_subformat_first,snd_pcm_hw_params_set_subformat_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_subformat_last,snd_pcm_hw_params_set_subformat_last@ALSA_0.9"); + +int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t val); +int snd_pcm_hw_params_get_subformat(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t val); +snd_pcm_subformat_t snd_pcm_hw_params_set_subformat_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +snd_pcm_subformat_t snd_pcm_hw_params_set_subformat_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); +void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); + +asm(".symver snd_pcm_hw_params_get_channels,snd_pcm_hw_params_get_channels@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_channels_min,snd_pcm_hw_params_get_channels_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_channels_max,snd_pcm_hw_params_get_channels_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_channels_near,snd_pcm_hw_params_set_channels_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_channels_first,snd_pcm_hw_params_set_channels_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_channels_last,snd_pcm_hw_params_set_channels_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params); +unsigned int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params); +unsigned int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max); +unsigned int snd_pcm_hw_params_set_channels_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +unsigned int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +unsigned int snd_pcm_hw_params_set_channels_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +asm(".symver snd_pcm_hw_params_get_rate,snd_pcm_hw_params_get_rate@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_rate_min,snd_pcm_hw_params_get_rate_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_rate_max,snd_pcm_hw_params_get_rate_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_rate_near,snd_pcm_hw_params_set_rate_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_rate_first,snd_pcm_hw_params_set_rate_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_rate_last,snd_pcm_hw_params_set_rate_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +unsigned int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); +unsigned int snd_pcm_hw_params_set_rate_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_set_rate_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_set_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_get_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); + +asm(".symver snd_pcm_hw_params_get_period_time,snd_pcm_hw_params_get_period_time@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_period_time_min,snd_pcm_hw_params_get_period_time_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_period_time_max,snd_pcm_hw_params_get_period_time_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_period_time_near,snd_pcm_hw_params_set_period_time_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_period_time_first,snd_pcm_hw_params_set_period_time_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_period_time_last,snd_pcm_hw_params_set_period_time_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_period_time_max(const snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +unsigned int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); +unsigned int snd_pcm_hw_params_set_period_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_set_period_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); + +asm(".symver snd_pcm_hw_params_get_period_size,snd_pcm_hw_params_get_period_size@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_period_size_min,snd_pcm_hw_params_get_period_size_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_period_size_max,snd_pcm_hw_params_get_period_size_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_period_size_near,snd_pcm_hw_params_set_period_size_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_period_size_first,snd_pcm_hw_params_set_period_size_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_period_size_last,snd_pcm_hw_params_set_period_size_last@ALSA_0.9"); + +snd_pcm_sframes_t snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, int *dir); +snd_pcm_uframes_t snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, int *dir); +snd_pcm_uframes_t snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir); +snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int *dir); +snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +asm(".symver snd_pcm_hw_params_get_periods,snd_pcm_hw_params_get_periods@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_periods_min,snd_pcm_hw_params_get_periods_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_periods_max,snd_pcm_hw_params_get_periods_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_periods_near,snd_pcm_hw_params_set_periods_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_periods_first,snd_pcm_hw_params_set_periods_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_periods_last,snd_pcm_hw_params_set_periods_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_periods_min(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_periods_max(const snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +unsigned int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); +unsigned int snd_pcm_hw_params_set_periods_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_set_periods_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +asm(".symver snd_pcm_hw_params_get_buffer_time,snd_pcm_hw_params_get_buffer_time@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_buffer_time_min,snd_pcm_hw_params_get_buffer_time_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_buffer_time_max,snd_pcm_hw_params_get_buffer_time_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_buffer_time_near,snd_pcm_hw_params_set_buffer_time_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_buffer_time_first,snd_pcm_hw_params_set_buffer_time_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_buffer_time_last,snd_pcm_hw_params_set_buffer_time_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_buffer_time_min(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_buffer_time_max(const snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +unsigned int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); +unsigned int snd_pcm_hw_params_set_buffer_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_set_buffer_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); + +asm(".symver snd_pcm_hw_params_get_buffer_size,snd_pcm_hw_params_get_buffer_size@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_buffer_size_min,snd_pcm_hw_params_get_buffer_size_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_buffer_size_max,snd_pcm_hw_params_get_buffer_size_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_buffer_size_near,snd_pcm_hw_params_set_buffer_size_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_buffer_size_first,snd_pcm_hw_params_set_buffer_size_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_buffer_size_last,snd_pcm_hw_params_set_buffer_size_last@ALSA_0.9"); + +snd_pcm_sframes_t snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params); +snd_pcm_uframes_t snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params); +snd_pcm_uframes_t snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max); +snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +asm(".symver snd_pcm_hw_params_get_tick_time,snd_pcm_hw_params_get_tick_time@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_tick_time_min,snd_pcm_hw_params_get_tick_time_min@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_get_tick_time_max,snd_pcm_hw_params_get_tick_time_max@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_tick_time_near,snd_pcm_hw_params_set_tick_time_near@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_tick_time_first,snd_pcm_hw_params_set_tick_time_first@ALSA_0.9"); +asm(".symver snd_pcm_hw_params_set_tick_time_last,snd_pcm_hw_params_set_tick_time_last@ALSA_0.9"); + +int snd_pcm_hw_params_get_tick_time(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_tick_time_min(const snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_get_tick_time_max(const snd_pcm_hw_params_t *params, int *dir); +int snd_pcm_hw_params_test_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_tick_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_tick_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_tick_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +unsigned int snd_pcm_hw_params_set_tick_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); +unsigned int snd_pcm_hw_params_set_tick_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); +unsigned int snd_pcm_hw_params_set_tick_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); + +#endif /* ALSA_PCM_OLD_HW_PARAMS_API */ + + +#ifdef ALSA_PCM_OLD_SW_PARAMS_API + +asm(".symver snd_pcm_sw_params_get_tstamp_mode,snd_pcm_sw_params_get_tstamp_mode@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_sleep_min,snd_pcm_sw_params_get_sleep_min@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_avail_min,snd_pcm_sw_params_get_avail_min@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_xfer_align,snd_pcm_sw_params_get_xfer_align@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_start_threshold,snd_pcm_sw_params_get_start_threshold@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_stop_threshold,snd_pcm_sw_params_set_stop_threshold@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_silence_threshold,snd_pcm_sw_params_get_silence_threshold@ALSA_0.9"); +asm(".symver snd_pcm_sw_params_get_silence_size,snd_pcm_sw_params_get_silence_size@ALSA_0.9"); + +int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val); +snd_pcm_tstamp_t snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, unsigned int val); +unsigned int snd_pcm_sw_params_get_sleep_min(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params); +int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +snd_pcm_uframes_t snd_pcm_sw_params_get_silence_size(const snd_pcm_sw_params_t *params); + +#endif /* ALSA_PCM_OLD_SW_PARAMS_API */ diff --git a/include/pcm_plugin.h b/include/pcm_plugin.h new file mode 100644 index 0000000..eea1d82 --- /dev/null +++ b/include/pcm_plugin.h @@ -0,0 +1,202 @@ +/** + * \file include/pcm_plugin.h + * \brief Common PCM plugin code + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2000-2001 + * + * Application interface library for the ALSA driver. + * See the \ref pcm_plugins page for more details. + * + * \warning Using of contents of this header file might be dangerous + * in the sense of compatibility reasons. The contents might be + * freely changed in future. + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_PCM_PLUGIN_H + +/** + * \defgroup PCM_Plugins PCM Plugins + * \ingroup PCM + * See the \ref pcm_plugins page for more details. + * \{ + */ + +#define SND_PCM_PLUGIN_RATE_MIN 4000 /**< minimal rate for the rate plugin */ +#define SND_PCM_PLUGIN_RATE_MAX 192000 /**< maximal rate for the rate plugin */ + +/* ROUTE_FLOAT should be set to 0 for machines without FP unit - like iPAQ */ +#ifdef HAVE_SOFT_FLOAT +#define SND_PCM_PLUGIN_ROUTE_FLOAT 0 /**< use integers for route plugin */ +#else +#define SND_PCM_PLUGIN_ROUTE_FLOAT 1 /**< use floats for route plugin */ +#endif + +#define SND_PCM_PLUGIN_ROUTE_RESOLUTION 16 /**< integer resolution for route plugin */ + +#if SND_PCM_PLUGIN_ROUTE_FLOAT +/** route ttable entry type */ +typedef float snd_pcm_route_ttable_entry_t; +#define SND_PCM_PLUGIN_ROUTE_HALF 0.5 /**< half value */ +#define SND_PCM_PLUGIN_ROUTE_FULL 1.0 /**< full value */ +#else +/** route ttable entry type */ +typedef int snd_pcm_route_ttable_entry_t; +#define SND_PCM_PLUGIN_ROUTE_HALF (SND_PCM_PLUGIN_ROUTE_RESOLUTION / 2) /**< half value */ +#define SND_PCM_PLUGIN_ROUTE_FULL SND_PCM_PLUGIN_ROUTE_RESOLUTION /**< full value */ +#endif + +/* + * Hardware plugin + */ +int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, + int card, int device, int subdevice, + snd_pcm_stream_t stream, int mode, + int mmap_emulation, int sync_ptr_ioctl); +int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Copy plugin + */ +int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_t *slave, int close_slave); +int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Linear conversion plugin + */ +int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, snd_pcm_t *slave, + int close_slave); +int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Linear<->Float conversion plugin + */ +int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, snd_pcm_t *slave, + int close_slave); +int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Linear<->mu-Law conversion plugin + */ +int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, snd_pcm_t *slave, + int close_slave); +int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Linear<->a-Law conversion plugin + */ +int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, snd_pcm_t *slave, + int close_slave); +int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Linear<->Ima-ADPCM conversion plugin + */ +int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, snd_pcm_t *slave, + int close_slave); +int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Route plugin for linear formats + */ +int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_csize, unsigned int tt_ssize, + unsigned int *tt_cused, unsigned int *tt_sused, + int schannels); +int snd_pcm_route_determine_ttable(snd_config_t *tt, + unsigned int *tt_csize, + unsigned int *tt_ssize); +int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, int schannels, + snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_ssize, + unsigned int tt_cused, unsigned int tt_sused, + snd_pcm_t *slave, int close_slave); +int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Rate plugin for linear formats + */ +int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, unsigned int srate, + const snd_config_t *converter, + snd_pcm_t *slave, int close_slave); +int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Hooks plugin + */ +int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_t *slave, int close_slave); +int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * LADSPA plugin + */ +int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, + const char *ladspa_path, + unsigned int channels, + snd_config_t *ladspa_pplugins, + snd_config_t *ladspa_cplugins, + snd_pcm_t *slave, int close_slave); +int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + +/* + * Jack plugin + */ +int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *playback_conf, + snd_config_t *capture_conf, + snd_pcm_stream_t stream, int mode); +int _snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode); + + +/** \} */ + +#endif /* __ALSA_PCM_PLUGIN_H */ diff --git a/include/pcm_rate.h b/include/pcm_rate.h new file mode 100644 index 0000000..4d70df2 --- /dev/null +++ b/include/pcm_rate.h @@ -0,0 +1,153 @@ +/** + * \file include/pcm_rate.h + * \brief External Rate-Converter-Plugin SDK + * \author Takashi Iwai + * \date 2006 + * + * External Rate-Converter-Plugin SDK + */ + +/* + * ALSA external PCM rate-converter plugin SDK (draft version) + * + * Copyright (c) 2006 Takashi Iwai + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_PCM_RATE_H +#define __ALSA_PCM_RATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Protocol version + */ +#define SND_PCM_RATE_PLUGIN_VERSION 0x010002 + +/** hw_params information for a single side */ +typedef struct snd_pcm_rate_side_info { + snd_pcm_format_t format; + unsigned int rate; + snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t period_size; +} snd_pcm_rate_side_info_t; + +/** hw_params information */ +typedef struct snd_pcm_rate_info { + struct snd_pcm_rate_side_info in; + struct snd_pcm_rate_side_info out; + unsigned int channels; +} snd_pcm_rate_info_t; + +/** Callback table of rate-converter */ +typedef struct snd_pcm_rate_ops { + /** + * close the converter; optional + */ + void (*close)(void *obj); + /** + * initialize the converter, called at hw_params + */ + int (*init)(void *obj, snd_pcm_rate_info_t *info); + /** + * free the converter; optional + */ + void (*free)(void *obj); + /** + * reset the converter, called at prepare; optional + */ + void (*reset)(void *obj); + /** + * adjust the pitch, called at sw_params; optional + */ + int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info); + /** + * convert the data + */ + void (*convert)(void *obj, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames); + /** + * convert an s16 interleaved-data array; exclusive with convert + */ + void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames, + const int16_t *src, unsigned int src_frames); + /** + * compute the frame size for input + */ + snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); + /** + * compute the frame size for output + */ + snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); + /** + * the protocol version the plugin supports; + * new field since version 0x010002 + */ + unsigned int version; + /** + * return the supported min / max sample rates; + * new ops since version 0x010002 + */ + int (*get_supported_rates)(void *obj, unsigned int *rate_min, + unsigned int *rate_max); + /** + * show some status messages for verbose mode; + * new ops since version 0x010002 + */ + void (*dump)(void *obj, snd_output_t *out); +} snd_pcm_rate_ops_t; + +/** open function type */ +typedef int (*snd_pcm_rate_open_func_t)(unsigned int version, void **objp, + snd_pcm_rate_ops_t *opsp); + +/** + * Define the object entry for external PCM rate-converter plugins + */ +#define SND_PCM_RATE_PLUGIN_ENTRY(name) _snd_pcm_rate_##name##_open + + +#ifndef DOC_HIDDEN +/* old rate_ops for protocol version 0x010001 */ +typedef struct snd_pcm_rate_old_ops { + void (*close)(void *obj); + int (*init)(void *obj, snd_pcm_rate_info_t *info); + void (*free)(void *obj); + void (*reset)(void *obj); + int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info); + void (*convert)(void *obj, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames); + void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames, + const int16_t *src, unsigned int src_frames); + snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); + snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); +} snd_pcm_rate_old_ops_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_PCM_RATE_H */ diff --git a/include/rawmidi.h b/include/rawmidi.h new file mode 100644 index 0000000..1d8fd56 --- /dev/null +++ b/include/rawmidi.h @@ -0,0 +1,159 @@ +/** + * \file include/rawmidi.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_RAWMIDI_H +#define __ALSA_RAWMIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup RawMidi RawMidi Interface + * The RawMidi Interface. See \ref rawmidi page for more details. + * \{ + */ + +/** dlsym version for interface entry callback */ +#define SND_RAWMIDI_DLSYM_VERSION _dlsym_rawmidi_001 + +/** RawMidi information container */ +typedef struct _snd_rawmidi_info snd_rawmidi_info_t; +/** RawMidi settings container */ +typedef struct _snd_rawmidi_params snd_rawmidi_params_t; +/** RawMidi status container */ +typedef struct _snd_rawmidi_status snd_rawmidi_status_t; + +/** RawMidi stream (direction) */ +typedef enum _snd_rawmidi_stream { + /** Output stream */ + SND_RAWMIDI_STREAM_OUTPUT = 0, + /** Input stream */ + SND_RAWMIDI_STREAM_INPUT, + SND_RAWMIDI_STREAM_LAST = SND_RAWMIDI_STREAM_INPUT +} snd_rawmidi_stream_t; + +/** Append (flag to open mode) \hideinitializer */ +#define SND_RAWMIDI_APPEND 0x0001 +/** Non blocking mode (flag to open mode) \hideinitializer */ +#define SND_RAWMIDI_NONBLOCK 0x0002 +/** Write sync mode (Flag to open mode) \hideinitializer */ +#define SND_RAWMIDI_SYNC 0x0004 + +/** RawMidi handle */ +typedef struct _snd_rawmidi snd_rawmidi_t; + +/** RawMidi type */ +typedef enum _snd_rawmidi_type { + /** Kernel level RawMidi */ + SND_RAWMIDI_TYPE_HW, + /** Shared memory client RawMidi (not yet implemented) */ + SND_RAWMIDI_TYPE_SHM, + /** INET client RawMidi (not yet implemented) */ + SND_RAWMIDI_TYPE_INET, + /** Virtual (sequencer) RawMidi */ + SND_RAWMIDI_TYPE_VIRTUAL +} snd_rawmidi_type_t; + +int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, + const char *name, int mode); +int snd_rawmidi_open_lconf(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, + const char *name, int mode, snd_config_t *lconf); +int snd_rawmidi_close(snd_rawmidi_t *rmidi); +int snd_rawmidi_poll_descriptors_count(snd_rawmidi_t *rmidi); +int snd_rawmidi_poll_descriptors(snd_rawmidi_t *rmidi, struct pollfd *pfds, unsigned int space); +int snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revent); +int snd_rawmidi_nonblock(snd_rawmidi_t *rmidi, int nonblock); +size_t snd_rawmidi_info_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_rawmidi_info_t using standard alloca + * \param ptr returned pointer + */ +#define snd_rawmidi_info_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_info) +int snd_rawmidi_info_malloc(snd_rawmidi_info_t **ptr); +void snd_rawmidi_info_free(snd_rawmidi_info_t *obj); +void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src); +unsigned int snd_rawmidi_info_get_device(const snd_rawmidi_info_t *obj); +unsigned int snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t *obj); +snd_rawmidi_stream_t snd_rawmidi_info_get_stream(const snd_rawmidi_info_t *obj); +int snd_rawmidi_info_get_card(const snd_rawmidi_info_t *obj); +unsigned int snd_rawmidi_info_get_flags(const snd_rawmidi_info_t *obj); +const char *snd_rawmidi_info_get_id(const snd_rawmidi_info_t *obj); +const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *obj); +const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *obj); +unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *obj); +unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *obj); +void snd_rawmidi_info_set_device(snd_rawmidi_info_t *obj, unsigned int val); +void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *obj, unsigned int val); +void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *obj, snd_rawmidi_stream_t val); +int snd_rawmidi_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info); +size_t snd_rawmidi_params_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_rawmidi_params_t using standard alloca + * \param ptr returned pointer + */ +#define snd_rawmidi_params_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_params) +int snd_rawmidi_params_malloc(snd_rawmidi_params_t **ptr); +void snd_rawmidi_params_free(snd_rawmidi_params_t *obj); +void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src); +int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, size_t val); +size_t snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t *params); +int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, size_t val); +size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params); +int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, int val); +int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params); +int snd_rawmidi_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params); +int snd_rawmidi_params_current(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params); +size_t snd_rawmidi_status_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_rawmidi_status_t using standard alloca + * \param ptr returned pointer + */ +#define snd_rawmidi_status_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_status) +int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr); +void snd_rawmidi_status_free(snd_rawmidi_status_t *obj); +void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src); +void snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t *obj, snd_htimestamp_t *ptr); +size_t snd_rawmidi_status_get_avail(const snd_rawmidi_status_t *obj); +size_t snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t *obj); +int snd_rawmidi_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status); +int snd_rawmidi_drain(snd_rawmidi_t *rmidi); +int snd_rawmidi_drop(snd_rawmidi_t *rmidi); +ssize_t snd_rawmidi_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size); +ssize_t snd_rawmidi_read(snd_rawmidi_t *rmidi, void *buffer, size_t size); +const char *snd_rawmidi_name(snd_rawmidi_t *rmidi); +snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rmidi); +snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RAWMIDI_H */ + diff --git a/include/search.h b/include/search.h new file mode 100644 index 0000000..91e6210 --- /dev/null +++ b/include/search.h @@ -0,0 +1,177 @@ +/* Declarations for System V style searching functions. + Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _SEARCH_H +#define _SEARCH_H 1 + +#include + +#define __need_size_t +#include + +__BEGIN_DECLS + +#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED +/* Prototype structure for a linked-list data structure. + This is the type used by the `insque' and `remque' functions. */ + +# ifdef __USE_GNU +struct qelem + { + struct qelem *q_forw; + struct qelem *q_back; + char q_data[1]; + }; +# endif + + +/* Insert ELEM into a doubly-linked list, after PREV. */ +extern void insque __P ((void *__elem, void *__prev)); + +/* Unlink ELEM from the doubly-linked list that it is in. */ +extern void remque __P ((void *__elem)); +#endif + + +/* For use with hsearch(3). */ +#ifndef __COMPAR_FN_T +# define __COMPAR_FN_T +typedef int (*__compar_fn_t) __PMT ((__const __ptr_t, __const __ptr_t)); + +# ifdef __USE_GNU +typedef __compar_fn_t comparison_fn_t; +# endif +#endif + +/* Action which shall be performed in the call the hsearch. */ +typedef enum + { + FIND, + ENTER + } +ACTION; + +typedef struct entry + { + char *key; + void *data; + } +ENTRY; + +/* Opaque type for internal use. */ +struct _ENTRY; + +/* Family of hash table handling functions. The functions also + have reentrant counterparts ending with _r. The non-reentrant + functions all work on a single internal hashing table. */ + +/* Search for entry matching ITEM.key in internal hash table. If + ACTION is `FIND' return found entry or signal error by returning + NULL. If ACTION is `ENTER' replace existing data (if any) with + ITEM.data. */ +extern ENTRY *hsearch __P ((ENTRY __item, ACTION __action)); + +/* Create a new hashing table which will at most contain NEL elements. */ +extern int hcreate __P ((size_t __nel)); + +/* Destroy current internal hashing table. */ +extern void hdestroy __P ((void)); + +#ifdef __USE_GNU +/* Data type for reentrant functions. */ +struct hsearch_data + { + struct _ENTRY *table; + unsigned int size; + unsigned int filled; + }; + +/* Reentrant versions which can handle multiple hashing tables at the + same time. */ +extern int hsearch_r __P ((ENTRY __item, ACTION __action, ENTRY **__retval, + struct hsearch_data *__htab)); +extern int hcreate_r __P ((size_t __nel, struct hsearch_data *__htab)); +extern void hdestroy_r __P ((struct hsearch_data *__htab)); +#endif + + +/* The tsearch routines are very interesting. They make many + assumptions about the compiler. It assumes that the first field + in node must be the "key" field, which points to the datum. + Everything depends on that. */ +/* For tsearch */ +typedef enum +{ + preorder, + postorder, + endorder, + leaf +} +VISIT; + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP and insert a new element if not found. */ +extern void *tsearch __PMT ((__const void *__key, void **__rootp, + __compar_fn_t __compar)); + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP. If no matching entry is available return NULL. */ +extern void *tfind __PMT ((__const void *__key, void *__const *__rootp, + __compar_fn_t __compar)); + +/* Remove the element matching KEY from the tree pointed to by *ROOTP. */ +extern void *tdelete __PMT ((__const void *__key, void **__rootp, + __compar_fn_t __compar)); + +#ifndef __ACTION_FN_T +# define __ACTION_FN_T +typedef void (*__action_fn_t) __PMT ((__const void *__nodep, + VISIT __value, + int __level)); +#endif + +/* Walk through the whole tree and call the ACTION callback for every node + or leaf. */ +extern void twalk __PMT ((__const void *__root, __action_fn_t __action)); + +#ifdef __USE_GNU +/* Callback type for function to free a tree node. If the keys are atomic + data this function should do nothing. */ +typedef void (*__free_fn_t) __PMT ((void *__nodep)); + +/* Destroy the whole tree, call FREEFCT for each node or leaf. */ +extern void tdestroy __PMT ((void *__root, __free_fn_t __freefct)); +#endif + + +/* Perform linear search for KEY by comparing by COMPAR in an array + [BASE,BASE+NMEMB*SIZE). */ +extern void *lfind __PMT ((__const void *__key, __const void *__base, + size_t *__nmemb, size_t __size, + __compar_fn_t __compar)); + +/* Perform linear search for KEY by comparing by COMPAR function in + array [BASE,BASE+NMEMB*SIZE) and insert entry if not found. */ +extern void *lsearch __PMT ((__const void *__key, void *__base, + size_t *__nmemb, size_t __size, + __compar_fn_t __compar)); + +__END_DECLS + +#endif /* search.h */ diff --git a/include/seq.h b/include/seq.h new file mode 100644 index 0000000..9576822 --- /dev/null +++ b/include/seq.h @@ -0,0 +1,737 @@ +/** + * \file include/seq.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + */ +/* + * Application interface library for the ALSA driver + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_SEQ_H +#define __ALSA_SEQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Sequencer MIDI Sequencer + * MIDI Sequencer Interface. + * See \ref seq page for more details. + * \{ + */ + +/** dlsym version for interface entry callback */ +#define SND_SEQ_DLSYM_VERSION _dlsym_seq_001 + +/** Sequencer handle */ +typedef struct _snd_seq snd_seq_t; + +/** + * sequencer opening stream types + */ +#define SND_SEQ_OPEN_OUTPUT 1 /**< open for output (write) */ +#define SND_SEQ_OPEN_INPUT 2 /**< open for input (read) */ +#define SND_SEQ_OPEN_DUPLEX (SND_SEQ_OPEN_OUTPUT|SND_SEQ_OPEN_INPUT) /**< open for both input and output (read/write) */ + +/** + * sequencer opening mode + */ +#define SND_SEQ_NONBLOCK 0x0001 /**< non-blocking mode (flag to open mode) */ + +/** sequencer handle type */ +typedef enum _snd_seq_type { + SND_SEQ_TYPE_HW, /**< hardware */ + SND_SEQ_TYPE_SHM, /**< shared memory (NYI) */ + SND_SEQ_TYPE_INET /**< network (NYI) */ +} snd_seq_type_t; + +/** special client (port) ids */ +#define SND_SEQ_ADDRESS_UNKNOWN 253 /**< unknown source */ +#define SND_SEQ_ADDRESS_SUBSCRIBERS 254 /**< send event to all subscribed ports */ +#define SND_SEQ_ADDRESS_BROADCAST 255 /**< send event to all queues/clients/ports/channels */ + +/** known client numbers */ +#define SND_SEQ_CLIENT_SYSTEM 0 /**< system client */ + +/* + */ +int snd_seq_open(snd_seq_t **handle, const char *name, int streams, int mode); +int snd_seq_open_lconf(snd_seq_t **handle, const char *name, int streams, int mode, snd_config_t *lconf); +const char *snd_seq_name(snd_seq_t *seq); +snd_seq_type_t snd_seq_type(snd_seq_t *seq); +int snd_seq_close(snd_seq_t *handle); +int snd_seq_poll_descriptors_count(snd_seq_t *handle, short events); +int snd_seq_poll_descriptors(snd_seq_t *handle, struct pollfd *pfds, unsigned int space, short events); +int snd_seq_poll_descriptors_revents(snd_seq_t *seq, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_seq_nonblock(snd_seq_t *handle, int nonblock); +int snd_seq_client_id(snd_seq_t *handle); + +size_t snd_seq_get_output_buffer_size(snd_seq_t *handle); +size_t snd_seq_get_input_buffer_size(snd_seq_t *handle); +int snd_seq_set_output_buffer_size(snd_seq_t *handle, size_t size); +int snd_seq_set_input_buffer_size(snd_seq_t *handle, size_t size); + +/** system information container */ +typedef struct _snd_seq_system_info snd_seq_system_info_t; + +size_t snd_seq_system_info_sizeof(void); +/** allocate a #snd_seq_system_info_t container on stack */ +#define snd_seq_system_info_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_system_info) +int snd_seq_system_info_malloc(snd_seq_system_info_t **ptr); +void snd_seq_system_info_free(snd_seq_system_info_t *ptr); +void snd_seq_system_info_copy(snd_seq_system_info_t *dst, const snd_seq_system_info_t *src); + +int snd_seq_system_info_get_queues(const snd_seq_system_info_t *info); +int snd_seq_system_info_get_clients(const snd_seq_system_info_t *info); +int snd_seq_system_info_get_ports(const snd_seq_system_info_t *info); +int snd_seq_system_info_get_channels(const snd_seq_system_info_t *info); +int snd_seq_system_info_get_cur_clients(const snd_seq_system_info_t *info); +int snd_seq_system_info_get_cur_queues(const snd_seq_system_info_t *info); + +int snd_seq_system_info(snd_seq_t *handle, snd_seq_system_info_t *info); + +/** \} */ + + +/** + * \defgroup SeqClient Sequencer Client Interface + * Sequencer Client Interface + * \ingroup Sequencer + * \{ + */ + +/** client information container */ +typedef struct _snd_seq_client_info snd_seq_client_info_t; + +/** client types */ +typedef enum snd_seq_client_type { + SND_SEQ_USER_CLIENT = 1, /**< user client */ + SND_SEQ_KERNEL_CLIENT = 2 /**< kernel client */ +} snd_seq_client_type_t; + +size_t snd_seq_client_info_sizeof(void); +/** allocate a #snd_seq_client_info_t container on stack */ +#define snd_seq_client_info_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_client_info) +int snd_seq_client_info_malloc(snd_seq_client_info_t **ptr); +void snd_seq_client_info_free(snd_seq_client_info_t *ptr); +void snd_seq_client_info_copy(snd_seq_client_info_t *dst, const snd_seq_client_info_t *src); + +int snd_seq_client_info_get_client(const snd_seq_client_info_t *info); +snd_seq_client_type_t snd_seq_client_info_get_type(const snd_seq_client_info_t *info); +const char *snd_seq_client_info_get_name(snd_seq_client_info_t *info); +int snd_seq_client_info_get_broadcast_filter(const snd_seq_client_info_t *info); +int snd_seq_client_info_get_error_bounce(const snd_seq_client_info_t *info); +const unsigned char *snd_seq_client_info_get_event_filter(const snd_seq_client_info_t *info); +int snd_seq_client_info_get_num_ports(const snd_seq_client_info_t *info); +int snd_seq_client_info_get_event_lost(const snd_seq_client_info_t *info); + +void snd_seq_client_info_set_client(snd_seq_client_info_t *info, int client); +void snd_seq_client_info_set_name(snd_seq_client_info_t *info, const char *name); +void snd_seq_client_info_set_broadcast_filter(snd_seq_client_info_t *info, int val); +void snd_seq_client_info_set_error_bounce(snd_seq_client_info_t *info, int val); +void snd_seq_client_info_set_event_filter(snd_seq_client_info_t *info, unsigned char *filter); + +void snd_seq_client_info_event_filter_clear(snd_seq_client_info_t *info); +void snd_seq_client_info_event_filter_add(snd_seq_client_info_t *info, int event_type); +void snd_seq_client_info_event_filter_del(snd_seq_client_info_t *info, int event_type); +int snd_seq_client_info_event_filter_check(snd_seq_client_info_t *info, int event_type); + +int snd_seq_get_client_info(snd_seq_t *handle, snd_seq_client_info_t *info); +int snd_seq_get_any_client_info(snd_seq_t *handle, int client, snd_seq_client_info_t *info); +int snd_seq_set_client_info(snd_seq_t *handle, snd_seq_client_info_t *info); +int snd_seq_query_next_client(snd_seq_t *handle, snd_seq_client_info_t *info); + +/* + */ + +/** client pool information container */ +typedef struct _snd_seq_client_pool snd_seq_client_pool_t; + +size_t snd_seq_client_pool_sizeof(void); +/** allocate a #snd_seq_client_pool_t container on stack */ +#define snd_seq_client_pool_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_client_pool) +int snd_seq_client_pool_malloc(snd_seq_client_pool_t **ptr); +void snd_seq_client_pool_free(snd_seq_client_pool_t *ptr); +void snd_seq_client_pool_copy(snd_seq_client_pool_t *dst, const snd_seq_client_pool_t *src); + +int snd_seq_client_pool_get_client(const snd_seq_client_pool_t *info); +size_t snd_seq_client_pool_get_output_pool(const snd_seq_client_pool_t *info); +size_t snd_seq_client_pool_get_input_pool(const snd_seq_client_pool_t *info); +size_t snd_seq_client_pool_get_output_room(const snd_seq_client_pool_t *info); +size_t snd_seq_client_pool_get_output_free(const snd_seq_client_pool_t *info); +size_t snd_seq_client_pool_get_input_free(const snd_seq_client_pool_t *info); +void snd_seq_client_pool_set_output_pool(snd_seq_client_pool_t *info, size_t size); +void snd_seq_client_pool_set_input_pool(snd_seq_client_pool_t *info, size_t size); +void snd_seq_client_pool_set_output_room(snd_seq_client_pool_t *info, size_t size); + +int snd_seq_get_client_pool(snd_seq_t *handle, snd_seq_client_pool_t *info); +int snd_seq_set_client_pool(snd_seq_t *handle, snd_seq_client_pool_t *info); + + +/** \} */ + + +/** + * \defgroup SeqPort Sequencer Port Interface + * Sequencer Port Interface + * \ingroup Sequencer + * \{ + */ + +/** port information container */ +typedef struct _snd_seq_port_info snd_seq_port_info_t; + +/** known port numbers */ +#define SND_SEQ_PORT_SYSTEM_TIMER 0 /**< system timer port */ +#define SND_SEQ_PORT_SYSTEM_ANNOUNCE 1 /**< system announce port */ + +/** port capabilities (32 bits) */ +#define SND_SEQ_PORT_CAP_READ (1<<0) /**< readable from this port */ +#define SND_SEQ_PORT_CAP_WRITE (1<<1) /**< writable to this port */ + +#define SND_SEQ_PORT_CAP_SYNC_READ (1<<2) /**< allow read subscriptions */ +#define SND_SEQ_PORT_CAP_SYNC_WRITE (1<<3) /**< allow write subscriptions */ + +#define SND_SEQ_PORT_CAP_DUPLEX (1<<4) /**< allow read/write duplex */ + +#define SND_SEQ_PORT_CAP_SUBS_READ (1<<5) /**< allow read subscription */ +#define SND_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /**< allow write subscription */ +#define SND_SEQ_PORT_CAP_NO_EXPORT (1<<7) /**< routing not allowed */ + +/* port type */ +/** Messages sent from/to this port have device-specific semantics. */ +#define SND_SEQ_PORT_TYPE_SPECIFIC (1<<0) +/** This port understands MIDI messages. */ +#define SND_SEQ_PORT_TYPE_MIDI_GENERIC (1<<1) +/** This port is compatible with the General MIDI specification. */ +#define SND_SEQ_PORT_TYPE_MIDI_GM (1<<2) +/** This port is compatible with the Roland GS standard. */ +#define SND_SEQ_PORT_TYPE_MIDI_GS (1<<3) +/** This port is compatible with the Yamaha XG specification. */ +#define SND_SEQ_PORT_TYPE_MIDI_XG (1<<4) +/** This port is compatible with the Roland MT-32. */ +#define SND_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) +/** This port is compatible with the General MIDI 2 specification. */ +#define SND_SEQ_PORT_TYPE_MIDI_GM2 (1<<6) +/** This port understands SND_SEQ_EVENT_SAMPLE_xxx messages + (these are not MIDI messages). */ +#define SND_SEQ_PORT_TYPE_SYNTH (1<<10) +/** Instruments can be downloaded to this port + (with SND_SEQ_EVENT_INSTR_xxx messages sent directly). */ +#define SND_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) +/** Instruments can be downloaded to this port + (with SND_SEQ_EVENT_INSTR_xxx messages sent directly or through a queue). */ +#define SND_SEQ_PORT_TYPE_SAMPLE (1<<12) +/** This port is implemented in hardware. */ +#define SND_SEQ_PORT_TYPE_HARDWARE (1<<16) +/** This port is implemented in software. */ +#define SND_SEQ_PORT_TYPE_SOFTWARE (1<<17) +/** Messages sent to this port will generate sounds. */ +#define SND_SEQ_PORT_TYPE_SYNTHESIZER (1<<18) +/** This port may connect to other devices + (whose characteristics are not known). */ +#define SND_SEQ_PORT_TYPE_PORT (1<<19) +/** This port belongs to an application, such as a sequencer or editor. */ +#define SND_SEQ_PORT_TYPE_APPLICATION (1<<20) + + +size_t snd_seq_port_info_sizeof(void); +/** allocate a #snd_seq_port_info_t container on stack */ +#define snd_seq_port_info_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_port_info) +int snd_seq_port_info_malloc(snd_seq_port_info_t **ptr); +void snd_seq_port_info_free(snd_seq_port_info_t *ptr); +void snd_seq_port_info_copy(snd_seq_port_info_t *dst, const snd_seq_port_info_t *src); + +int snd_seq_port_info_get_client(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_port(const snd_seq_port_info_t *info); +const snd_seq_addr_t *snd_seq_port_info_get_addr(const snd_seq_port_info_t *info); +const char *snd_seq_port_info_get_name(const snd_seq_port_info_t *info); +unsigned int snd_seq_port_info_get_capability(const snd_seq_port_info_t *info); +unsigned int snd_seq_port_info_get_type(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_midi_channels(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_midi_voices(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_synth_voices(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_read_use(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_write_use(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_port_specified(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_timestamping(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_timestamp_real(const snd_seq_port_info_t *info); +int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info); + +void snd_seq_port_info_set_client(snd_seq_port_info_t *info, int client); +void snd_seq_port_info_set_port(snd_seq_port_info_t *info, int port); +void snd_seq_port_info_set_addr(snd_seq_port_info_t *info, const snd_seq_addr_t *addr); +void snd_seq_port_info_set_name(snd_seq_port_info_t *info, const char *name); +void snd_seq_port_info_set_capability(snd_seq_port_info_t *info, unsigned int capability); +void snd_seq_port_info_set_type(snd_seq_port_info_t *info, unsigned int type); +void snd_seq_port_info_set_midi_channels(snd_seq_port_info_t *info, int channels); +void snd_seq_port_info_set_midi_voices(snd_seq_port_info_t *info, int voices); +void snd_seq_port_info_set_synth_voices(snd_seq_port_info_t *info, int voices); +void snd_seq_port_info_set_port_specified(snd_seq_port_info_t *info, int val); +void snd_seq_port_info_set_timestamping(snd_seq_port_info_t *info, int enable); +void snd_seq_port_info_set_timestamp_real(snd_seq_port_info_t *info, int realtime); +void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue); + +int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t *info); +int snd_seq_delete_port(snd_seq_t *handle, int port); +int snd_seq_get_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t *info); +int snd_seq_get_any_port_info(snd_seq_t *handle, int client, int port, snd_seq_port_info_t *info); +int snd_seq_set_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t *info); +int snd_seq_query_next_port(snd_seq_t *handle, snd_seq_port_info_t *info); + +/** \} */ + + +/** + * \defgroup SeqSubscribe Sequencer Port Subscription + * Sequencer Port Subscription + * \ingroup Sequencer + * \{ + */ + +/** port subscription container */ +typedef struct _snd_seq_port_subscribe snd_seq_port_subscribe_t; + +size_t snd_seq_port_subscribe_sizeof(void); +/** allocate a #snd_seq_port_subscribe_t container on stack */ +#define snd_seq_port_subscribe_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_port_subscribe) +int snd_seq_port_subscribe_malloc(snd_seq_port_subscribe_t **ptr); +void snd_seq_port_subscribe_free(snd_seq_port_subscribe_t *ptr); +void snd_seq_port_subscribe_copy(snd_seq_port_subscribe_t *dst, const snd_seq_port_subscribe_t *src); + +const snd_seq_addr_t *snd_seq_port_subscribe_get_sender(const snd_seq_port_subscribe_t *info); +const snd_seq_addr_t *snd_seq_port_subscribe_get_dest(const snd_seq_port_subscribe_t *info); +int snd_seq_port_subscribe_get_queue(const snd_seq_port_subscribe_t *info); +int snd_seq_port_subscribe_get_exclusive(const snd_seq_port_subscribe_t *info); +int snd_seq_port_subscribe_get_time_update(const snd_seq_port_subscribe_t *info); +int snd_seq_port_subscribe_get_time_real(const snd_seq_port_subscribe_t *info); + +void snd_seq_port_subscribe_set_sender(snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr); +void snd_seq_port_subscribe_set_dest(snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr); +void snd_seq_port_subscribe_set_queue(snd_seq_port_subscribe_t *info, int q); +void snd_seq_port_subscribe_set_exclusive(snd_seq_port_subscribe_t *info, int val); +void snd_seq_port_subscribe_set_time_update(snd_seq_port_subscribe_t *info, int val); +void snd_seq_port_subscribe_set_time_real(snd_seq_port_subscribe_t *info, int val); + +int snd_seq_get_port_subscription(snd_seq_t *handle, snd_seq_port_subscribe_t *sub); +int snd_seq_subscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t *sub); +int snd_seq_unsubscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t *sub); + +/* + */ + +/** subscription query container */ +typedef struct _snd_seq_query_subscribe snd_seq_query_subscribe_t; + +/** type of query subscription */ +typedef enum { + SND_SEQ_QUERY_SUBS_READ, /**< query read subscriptions */ + SND_SEQ_QUERY_SUBS_WRITE /**< query write subscriptions */ +} snd_seq_query_subs_type_t; + +size_t snd_seq_query_subscribe_sizeof(void); +/** allocate a #snd_seq_query_subscribe_t container on stack */ +#define snd_seq_query_subscribe_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_query_subscribe) +int snd_seq_query_subscribe_malloc(snd_seq_query_subscribe_t **ptr); +void snd_seq_query_subscribe_free(snd_seq_query_subscribe_t *ptr); +void snd_seq_query_subscribe_copy(snd_seq_query_subscribe_t *dst, const snd_seq_query_subscribe_t *src); + +int snd_seq_query_subscribe_get_client(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_port(const snd_seq_query_subscribe_t *info); +const snd_seq_addr_t *snd_seq_query_subscribe_get_root(const snd_seq_query_subscribe_t *info); +snd_seq_query_subs_type_t snd_seq_query_subscribe_get_type(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_index(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_num_subs(const snd_seq_query_subscribe_t *info); +const snd_seq_addr_t *snd_seq_query_subscribe_get_addr(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_queue(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_exclusive(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_time_update(const snd_seq_query_subscribe_t *info); +int snd_seq_query_subscribe_get_time_real(const snd_seq_query_subscribe_t *info); + +void snd_seq_query_subscribe_set_client(snd_seq_query_subscribe_t *info, int client); +void snd_seq_query_subscribe_set_port(snd_seq_query_subscribe_t *info, int port); +void snd_seq_query_subscribe_set_root(snd_seq_query_subscribe_t *info, const snd_seq_addr_t *addr); +void snd_seq_query_subscribe_set_type(snd_seq_query_subscribe_t *info, snd_seq_query_subs_type_t type); +void snd_seq_query_subscribe_set_index(snd_seq_query_subscribe_t *info, int _index); + +int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subscribe_t * subs); + +/** \} */ + + +/** + * \defgroup SeqQueue Sequencer Queue Interface + * Sequencer Queue Interface + * \ingroup Sequencer + * \{ + */ + +/** queue information container */ +typedef struct _snd_seq_queue_info snd_seq_queue_info_t; +/** queue status container */ +typedef struct _snd_seq_queue_status snd_seq_queue_status_t; +/** queue tempo container */ +typedef struct _snd_seq_queue_tempo snd_seq_queue_tempo_t; +/** queue timer information container */ +typedef struct _snd_seq_queue_timer snd_seq_queue_timer_t; + +/** special queue ids */ +#define SND_SEQ_QUEUE_DIRECT 253 /**< direct dispatch */ + +size_t snd_seq_queue_info_sizeof(void); +/** allocate a #snd_seq_queue_info_t container on stack */ +#define snd_seq_queue_info_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_queue_info) +int snd_seq_queue_info_malloc(snd_seq_queue_info_t **ptr); +void snd_seq_queue_info_free(snd_seq_queue_info_t *ptr); +void snd_seq_queue_info_copy(snd_seq_queue_info_t *dst, const snd_seq_queue_info_t *src); + +int snd_seq_queue_info_get_queue(const snd_seq_queue_info_t *info); +const char *snd_seq_queue_info_get_name(const snd_seq_queue_info_t *info); +int snd_seq_queue_info_get_owner(const snd_seq_queue_info_t *info); +int snd_seq_queue_info_get_locked(const snd_seq_queue_info_t *info); +unsigned int snd_seq_queue_info_get_flags(const snd_seq_queue_info_t *info); + +void snd_seq_queue_info_set_name(snd_seq_queue_info_t *info, const char *name); +void snd_seq_queue_info_set_owner(snd_seq_queue_info_t *info, int owner); +void snd_seq_queue_info_set_locked(snd_seq_queue_info_t *info, int locked); +void snd_seq_queue_info_set_flags(snd_seq_queue_info_t *info, unsigned int flags); + +int snd_seq_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info); +int snd_seq_alloc_named_queue(snd_seq_t *seq, const char *name); +int snd_seq_alloc_queue(snd_seq_t *handle); +int snd_seq_free_queue(snd_seq_t *handle, int q); +int snd_seq_get_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info); +int snd_seq_set_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info); +int snd_seq_query_named_queue(snd_seq_t *seq, const char *name); + +int snd_seq_get_queue_usage(snd_seq_t *handle, int q); +int snd_seq_set_queue_usage(snd_seq_t *handle, int q, int used); + +/* + */ +size_t snd_seq_queue_status_sizeof(void); +/** allocate a #snd_seq_queue_status_t container on stack */ +#define snd_seq_queue_status_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_queue_status) +int snd_seq_queue_status_malloc(snd_seq_queue_status_t **ptr); +void snd_seq_queue_status_free(snd_seq_queue_status_t *ptr); +void snd_seq_queue_status_copy(snd_seq_queue_status_t *dst, const snd_seq_queue_status_t *src); + +int snd_seq_queue_status_get_queue(const snd_seq_queue_status_t *info); +int snd_seq_queue_status_get_events(const snd_seq_queue_status_t *info); +snd_seq_tick_time_t snd_seq_queue_status_get_tick_time(const snd_seq_queue_status_t *info); +const snd_seq_real_time_t *snd_seq_queue_status_get_real_time(const snd_seq_queue_status_t *info); +unsigned int snd_seq_queue_status_get_status(const snd_seq_queue_status_t *info); + +int snd_seq_get_queue_status(snd_seq_t *handle, int q, snd_seq_queue_status_t *status); + +/* + */ +size_t snd_seq_queue_tempo_sizeof(void); +/** allocate a #snd_seq_queue_tempo_t container on stack */ +#define snd_seq_queue_tempo_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_queue_tempo) +int snd_seq_queue_tempo_malloc(snd_seq_queue_tempo_t **ptr); +void snd_seq_queue_tempo_free(snd_seq_queue_tempo_t *ptr); +void snd_seq_queue_tempo_copy(snd_seq_queue_tempo_t *dst, const snd_seq_queue_tempo_t *src); + +int snd_seq_queue_tempo_get_queue(const snd_seq_queue_tempo_t *info); +unsigned int snd_seq_queue_tempo_get_tempo(const snd_seq_queue_tempo_t *info); +int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info); +unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info); +unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info); +void snd_seq_queue_tempo_set_tempo(snd_seq_queue_tempo_t *info, unsigned int tempo); +void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq); +void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew); +void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base); + +int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo); +int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo); + +/* + */ + +/** sequencer timer sources */ +typedef enum { + SND_SEQ_TIMER_ALSA = 0, /* ALSA timer */ + SND_SEQ_TIMER_MIDI_CLOCK = 1, /* Midi Clock (CLOCK event) */ + SND_SEQ_TIMER_MIDI_TICK = 2 /* Midi Timer Tick (TICK event */ +} snd_seq_queue_timer_type_t; + +size_t snd_seq_queue_timer_sizeof(void); +/** allocate a #snd_seq_queue_timer_t container on stack */ +#define snd_seq_queue_timer_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_queue_timer) +int snd_seq_queue_timer_malloc(snd_seq_queue_timer_t **ptr); +void snd_seq_queue_timer_free(snd_seq_queue_timer_t *ptr); +void snd_seq_queue_timer_copy(snd_seq_queue_timer_t *dst, const snd_seq_queue_timer_t *src); + +int snd_seq_queue_timer_get_queue(const snd_seq_queue_timer_t *info); +snd_seq_queue_timer_type_t snd_seq_queue_timer_get_type(const snd_seq_queue_timer_t *info); +const snd_timer_id_t *snd_seq_queue_timer_get_id(const snd_seq_queue_timer_t *info); +unsigned int snd_seq_queue_timer_get_resolution(const snd_seq_queue_timer_t *info); + +void snd_seq_queue_timer_set_type(snd_seq_queue_timer_t *info, snd_seq_queue_timer_type_t type); +void snd_seq_queue_timer_set_id(snd_seq_queue_timer_t *info, const snd_timer_id_t *id); +void snd_seq_queue_timer_set_resolution(snd_seq_queue_timer_t *info, unsigned int resolution); + +int snd_seq_get_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t *timer); +int snd_seq_set_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t *timer); + +/** \} */ + +/** + * \defgroup SeqEvent Sequencer Event API + * Sequencer Event API + * \ingroup Sequencer + * \{ + */ + +int snd_seq_free_event(snd_seq_event_t *ev); +ssize_t snd_seq_event_length(snd_seq_event_t *ev); +int snd_seq_event_output(snd_seq_t *handle, snd_seq_event_t *ev); +int snd_seq_event_output_buffer(snd_seq_t *handle, snd_seq_event_t *ev); +int snd_seq_event_output_direct(snd_seq_t *handle, snd_seq_event_t *ev); +int snd_seq_event_input(snd_seq_t *handle, snd_seq_event_t **ev); +int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer); +int snd_seq_drain_output(snd_seq_t *handle); +int snd_seq_event_output_pending(snd_seq_t *seq); +int snd_seq_extract_output(snd_seq_t *handle, snd_seq_event_t **ev); +int snd_seq_drop_output(snd_seq_t *handle); +int snd_seq_drop_output_buffer(snd_seq_t *handle); +int snd_seq_drop_input(snd_seq_t *handle); +int snd_seq_drop_input_buffer(snd_seq_t *handle); + +/** event removal conditionals */ +typedef struct _snd_seq_remove_events snd_seq_remove_events_t; + +/** Remove conditional flags */ +#define SND_SEQ_REMOVE_INPUT (1<<0) /**< Flush input queues */ +#define SND_SEQ_REMOVE_OUTPUT (1<<1) /**< Flush output queues */ +#define SND_SEQ_REMOVE_DEST (1<<2) /**< Restrict by destination q:client:port */ +#define SND_SEQ_REMOVE_DEST_CHANNEL (1<<3) /**< Restrict by channel */ +#define SND_SEQ_REMOVE_TIME_BEFORE (1<<4) /**< Restrict to before time */ +#define SND_SEQ_REMOVE_TIME_AFTER (1<<5) /**< Restrict to time or after */ +#define SND_SEQ_REMOVE_TIME_TICK (1<<6) /**< Time is in ticks */ +#define SND_SEQ_REMOVE_EVENT_TYPE (1<<7) /**< Restrict to event type */ +#define SND_SEQ_REMOVE_IGNORE_OFF (1<<8) /**< Do not flush off events */ +#define SND_SEQ_REMOVE_TAG_MATCH (1<<9) /**< Restrict to events with given tag */ + +size_t snd_seq_remove_events_sizeof(void); +/** allocate a #snd_seq_remove_events_t container on stack */ +#define snd_seq_remove_events_alloca(ptr) \ + __snd_alloca(ptr, snd_seq_remove_events) +int snd_seq_remove_events_malloc(snd_seq_remove_events_t **ptr); +void snd_seq_remove_events_free(snd_seq_remove_events_t *ptr); +void snd_seq_remove_events_copy(snd_seq_remove_events_t *dst, const snd_seq_remove_events_t *src); + +unsigned int snd_seq_remove_events_get_condition(const snd_seq_remove_events_t *info); +int snd_seq_remove_events_get_queue(const snd_seq_remove_events_t *info); +const snd_seq_timestamp_t *snd_seq_remove_events_get_time(const snd_seq_remove_events_t *info); +const snd_seq_addr_t *snd_seq_remove_events_get_dest(const snd_seq_remove_events_t *info); +int snd_seq_remove_events_get_channel(const snd_seq_remove_events_t *info); +int snd_seq_remove_events_get_event_type(const snd_seq_remove_events_t *info); +int snd_seq_remove_events_get_tag(const snd_seq_remove_events_t *info); + +void snd_seq_remove_events_set_condition(snd_seq_remove_events_t *info, unsigned int flags); +void snd_seq_remove_events_set_queue(snd_seq_remove_events_t *info, int queue); +void snd_seq_remove_events_set_time(snd_seq_remove_events_t *info, const snd_seq_timestamp_t *time); +void snd_seq_remove_events_set_dest(snd_seq_remove_events_t *info, const snd_seq_addr_t *addr); +void snd_seq_remove_events_set_channel(snd_seq_remove_events_t *info, int channel); +void snd_seq_remove_events_set_event_type(snd_seq_remove_events_t *info, int type); +void snd_seq_remove_events_set_tag(snd_seq_remove_events_t *info, int tag); + +int snd_seq_remove_events(snd_seq_t *handle, snd_seq_remove_events_t *info); + +/** \} */ + +/** + * \defgroup SeqMisc Sequencer Miscellaneous + * Sequencer Miscellaneous + * \ingroup Sequencer + * \{ + */ + +void snd_seq_set_bit(int nr, void *array); +void snd_seq_unset_bit(int nr, void *array); +int snd_seq_change_bit(int nr, void *array); +int snd_seq_get_bit(int nr, void *array); + +/** \} */ + + +/** + * \defgroup SeqEvType Sequencer Event Type Checks + * Sequencer Event Type Checks + * \ingroup Sequencer + * \{ + */ + +/* event type macros */ +enum { + SND_SEQ_EVFLG_RESULT, + SND_SEQ_EVFLG_NOTE, + SND_SEQ_EVFLG_CONTROL, + SND_SEQ_EVFLG_QUEUE, + SND_SEQ_EVFLG_SYSTEM, + SND_SEQ_EVFLG_MESSAGE, + SND_SEQ_EVFLG_CONNECTION, + SND_SEQ_EVFLG_SAMPLE, + SND_SEQ_EVFLG_USERS, + SND_SEQ_EVFLG_INSTR, + SND_SEQ_EVFLG_QUOTE, + SND_SEQ_EVFLG_NONE, + SND_SEQ_EVFLG_RAW, + SND_SEQ_EVFLG_FIXED, + SND_SEQ_EVFLG_VARIABLE, + SND_SEQ_EVFLG_VARUSR +}; + +enum { + SND_SEQ_EVFLG_NOTE_ONEARG, + SND_SEQ_EVFLG_NOTE_TWOARG +}; + +enum { + SND_SEQ_EVFLG_QUEUE_NOARG, + SND_SEQ_EVFLG_QUEUE_TICK, + SND_SEQ_EVFLG_QUEUE_TIME, + SND_SEQ_EVFLG_QUEUE_VALUE +}; + +/** + * Exported event type table + * + * This table is referred by snd_seq_ev_is_xxx. + */ +extern const unsigned int snd_seq_event_types[]; + +#define _SND_SEQ_TYPE(x) (1<<(x)) /**< master type - 24bit */ +#define _SND_SEQ_TYPE_OPT(x) ((x)<<24) /**< optional type - 8bit */ + +/** check the event type */ +#define snd_seq_type_check(ev,x) (snd_seq_event_types[(ev)->type] & _SND_SEQ_TYPE(x)) + +/** event type check: result events */ +#define snd_seq_ev_is_result_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_RESULT) +/** event type check: note events */ +#define snd_seq_ev_is_note_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_NOTE) +/** event type check: control events */ +#define snd_seq_ev_is_control_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_CONTROL) +/** event type check: channel specific events */ +#define snd_seq_ev_is_channel_type(ev) \ + (snd_seq_event_types[(ev)->type] & (_SND_SEQ_TYPE(SND_SEQ_EVFLG_NOTE) | _SND_SEQ_TYPE(SND_SEQ_EVFLG_CONTROL))) + +/** event type check: queue control events */ +#define snd_seq_ev_is_queue_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_QUEUE) +/** event type check: system status messages */ +#define snd_seq_ev_is_message_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_MESSAGE) +/** event type check: system status messages */ +#define snd_seq_ev_is_subscribe_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_CONNECTION) +/** event type check: sample messages */ +#define snd_seq_ev_is_sample_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_SAMPLE) +/** event type check: user-defined messages */ +#define snd_seq_ev_is_user_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_USERS) +/** event type check: instrument layer events */ +#define snd_seq_ev_is_instr_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_INSTR) +/** event type check: fixed length events */ +#define snd_seq_ev_is_fixed_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_FIXED) +/** event type check: variable length events */ +#define snd_seq_ev_is_variable_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_VARIABLE) +/** event type check: user pointer events */ +#define snd_seq_ev_is_varusr_type(ev) \ + snd_seq_type_check(ev, SND_SEQ_EVFLG_VARUSR) +/** event type check: reserved for kernel */ +#define snd_seq_ev_is_reserved(ev) \ + (! snd_seq_event_types[(ev)->type]) + +/** + * macros to check event flags + */ +/** prior events */ +#define snd_seq_ev_is_prior(ev) \ + (((ev)->flags & SND_SEQ_PRIORITY_MASK) == SND_SEQ_PRIORITY_HIGH) + +/** get the data length type */ +#define snd_seq_ev_length_type(ev) \ + ((ev)->flags & SND_SEQ_EVENT_LENGTH_MASK) +/** fixed length events */ +#define snd_seq_ev_is_fixed(ev) \ + (snd_seq_ev_length_type(ev) == SND_SEQ_EVENT_LENGTH_FIXED) +/** variable length events */ +#define snd_seq_ev_is_variable(ev) \ + (snd_seq_ev_length_type(ev) == SND_SEQ_EVENT_LENGTH_VARIABLE) +/** variable length on user-space */ +#define snd_seq_ev_is_varusr(ev) \ + (snd_seq_ev_length_type(ev) == SND_SEQ_EVENT_LENGTH_VARUSR) + +/** time-stamp type */ +#define snd_seq_ev_timestamp_type(ev) \ + ((ev)->flags & SND_SEQ_TIME_STAMP_MASK) +/** event is in tick time */ +#define snd_seq_ev_is_tick(ev) \ + (snd_seq_ev_timestamp_type(ev) == SND_SEQ_TIME_STAMP_TICK) +/** event is in real-time */ +#define snd_seq_ev_is_real(ev) \ + (snd_seq_ev_timestamp_type(ev) == SND_SEQ_TIME_STAMP_REAL) + +/** time-mode type */ +#define snd_seq_ev_timemode_type(ev) \ + ((ev)->flags & SND_SEQ_TIME_MODE_MASK) +/** scheduled in absolute time */ +#define snd_seq_ev_is_abstime(ev) \ + (snd_seq_ev_timemode_type(ev) == SND_SEQ_TIME_MODE_ABS) +/** scheduled in relative time */ +#define snd_seq_ev_is_reltime(ev) \ + (snd_seq_ev_timemode_type(ev) == SND_SEQ_TIME_MODE_REL) + +/** direct dispatched events */ +#define snd_seq_ev_is_direct(ev) \ + ((ev)->queue == SND_SEQ_QUEUE_DIRECT) + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_SEQ_H */ + diff --git a/include/seq_event.h b/include/seq_event.h new file mode 100644 index 0000000..583f1d0 --- /dev/null +++ b/include/seq_event.h @@ -0,0 +1,319 @@ +/** + * \file include/seq_event.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_SEQ_EVENT_H +#define __ALSA_SEQ_EVENT_H + +/** + * \defgroup SeqEvents Sequencer Event Definitions + * Sequencer Event Definitions + * \ingroup Sequencer + * \{ + */ + +/** + * Sequencer event data type + */ +typedef unsigned char snd_seq_event_type_t; + +/** Sequencer event type */ +enum snd_seq_event_type { + /** system status; event data type = #snd_seq_result_t */ + SND_SEQ_EVENT_SYSTEM = 0, + /** returned result status; event data type = #snd_seq_result_t */ + SND_SEQ_EVENT_RESULT, + + /** note on and off with duration; event data type = #snd_seq_ev_note_t */ + SND_SEQ_EVENT_NOTE = 5, + /** note on; event data type = #snd_seq_ev_note_t */ + SND_SEQ_EVENT_NOTEON, + /** note off; event data type = #snd_seq_ev_note_t */ + SND_SEQ_EVENT_NOTEOFF, + /** key pressure change (aftertouch); event data type = #snd_seq_ev_note_t */ + SND_SEQ_EVENT_KEYPRESS, + + /** controller; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_CONTROLLER = 10, + /** program change; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_PGMCHANGE, + /** channel pressure; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_CHANPRESS, + /** pitchwheel; event data type = #snd_seq_ev_ctrl_t; data is from -8192 to 8191) */ + SND_SEQ_EVENT_PITCHBEND, + /** 14 bit controller value; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_CONTROL14, + /** 14 bit NRPN; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_NONREGPARAM, + /** 14 bit RPN; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_REGPARAM, + + /** SPP with LSB and MSB values; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_SONGPOS = 20, + /** Song Select with song ID number; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_SONGSEL, + /** midi time code quarter frame; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_QFRAME, + /** SMF Time Signature event; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_TIMESIGN, + /** SMF Key Signature event; event data type = #snd_seq_ev_ctrl_t */ + SND_SEQ_EVENT_KEYSIGN, + + /** MIDI Real Time Start message; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_START = 30, + /** MIDI Real Time Continue message; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_CONTINUE, + /** MIDI Real Time Stop message; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_STOP, + /** Set tick queue position; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_SETPOS_TICK, + /** Set real-time queue position; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_SETPOS_TIME, + /** (SMF) Tempo event; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_TEMPO, + /** MIDI Real Time Clock message; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_CLOCK, + /** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_TICK, + /** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_QUEUE_SKEW, + /** Sync position changed; event data type = #snd_seq_ev_queue_control_t */ + SND_SEQ_EVENT_SYNC_POS, + + /** Tune request; event data type = none */ + SND_SEQ_EVENT_TUNE_REQUEST = 40, + /** Reset to power-on state; event data type = none */ + SND_SEQ_EVENT_RESET, + /** Active sensing event; event data type = none */ + SND_SEQ_EVENT_SENSING, + + /** Echo-back event; event data type = any type */ + SND_SEQ_EVENT_ECHO = 50, + /** OSS emulation raw event; event data type = any type */ + SND_SEQ_EVENT_OSS, + + /** New client has connected; event data type = #snd_seq_addr_t */ + SND_SEQ_EVENT_CLIENT_START = 60, + /** Client has left the system; event data type = #snd_seq_addr_t */ + SND_SEQ_EVENT_CLIENT_EXIT, + /** Client status/info has changed; event data type = #snd_seq_addr_t */ + SND_SEQ_EVENT_CLIENT_CHANGE, + /** New port was created; event data type = #snd_seq_addr_t */ + SND_SEQ_EVENT_PORT_START, + /** Port was deleted from system; event data type = #snd_seq_addr_t */ + SND_SEQ_EVENT_PORT_EXIT, + /** Port status/info has changed; event data type = #snd_seq_addr_t */ + SND_SEQ_EVENT_PORT_CHANGE, + + /** Ports connected; event data type = #snd_seq_connect_t */ + SND_SEQ_EVENT_PORT_SUBSCRIBED, + /** Ports disconnected; event data type = #snd_seq_connect_t */ + SND_SEQ_EVENT_PORT_UNSUBSCRIBED, + + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR0 = 90, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR1, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR2, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR3, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR4, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR5, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR6, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR7, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR8, + /** user-defined event; event data type = any (fixed size) */ + SND_SEQ_EVENT_USR9, + + /** system exclusive data (variable length); event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_SYSEX = 130, + /** error event; event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_BOUNCE, + /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_USR_VAR0 = 135, + /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_USR_VAR1, + /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_USR_VAR2, + /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_USR_VAR3, + /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ + SND_SEQ_EVENT_USR_VAR4, + + /** NOP; ignored in any case */ + SND_SEQ_EVENT_NONE = 255 +}; + + +/** Sequencer event address */ +typedef struct snd_seq_addr { + unsigned char client; /**< Client id */ + unsigned char port; /**< Port id */ +} snd_seq_addr_t; + +/** Connection (subscription) between ports */ +typedef struct snd_seq_connect { + snd_seq_addr_t sender; /**< sender address */ + snd_seq_addr_t dest; /**< destination address */ +} snd_seq_connect_t; + + +/** Real-time data record */ +typedef struct snd_seq_real_time { + unsigned int tv_sec; /**< seconds */ + unsigned int tv_nsec; /**< nanoseconds */ +} snd_seq_real_time_t; + +/** (MIDI) Tick-time data record */ +typedef unsigned int snd_seq_tick_time_t; + +/** unioned time stamp */ +typedef union snd_seq_timestamp { + snd_seq_tick_time_t tick; /**< tick-time */ + struct snd_seq_real_time time; /**< real-time */ +} snd_seq_timestamp_t; + + +/** + * Event mode flags + * + * NOTE: only 8 bits available! + */ +#define SND_SEQ_TIME_STAMP_TICK (0<<0) /**< timestamp in clock ticks */ +#define SND_SEQ_TIME_STAMP_REAL (1<<0) /**< timestamp in real time */ +#define SND_SEQ_TIME_STAMP_MASK (1<<0) /**< mask for timestamp bits */ + +#define SND_SEQ_TIME_MODE_ABS (0<<1) /**< absolute timestamp */ +#define SND_SEQ_TIME_MODE_REL (1<<1) /**< relative to current time */ +#define SND_SEQ_TIME_MODE_MASK (1<<1) /**< mask for time mode bits */ + +#define SND_SEQ_EVENT_LENGTH_FIXED (0<<2) /**< fixed event size */ +#define SND_SEQ_EVENT_LENGTH_VARIABLE (1<<2) /**< variable event size */ +#define SND_SEQ_EVENT_LENGTH_VARUSR (2<<2) /**< variable event size - user memory space */ +#define SND_SEQ_EVENT_LENGTH_MASK (3<<2) /**< mask for event length bits */ + +#define SND_SEQ_PRIORITY_NORMAL (0<<4) /**< normal priority */ +#define SND_SEQ_PRIORITY_HIGH (1<<4) /**< event should be processed before others */ +#define SND_SEQ_PRIORITY_MASK (1<<4) /**< mask for priority bits */ + + +/** Note event */ +typedef struct snd_seq_ev_note { + unsigned char channel; /**< channel number */ + unsigned char note; /**< note */ + unsigned char velocity; /**< velocity */ + unsigned char off_velocity; /**< note-off velocity; only for #SND_SEQ_EVENT_NOTE */ + unsigned int duration; /**< duration until note-off; only for #SND_SEQ_EVENT_NOTE */ +} snd_seq_ev_note_t; + +/** Controller event */ +typedef struct snd_seq_ev_ctrl { + unsigned char channel; /**< channel number */ + unsigned char unused[3]; /**< reserved */ + unsigned int param; /**< control parameter */ + signed int value; /**< control value */ +} snd_seq_ev_ctrl_t; + +/** generic set of bytes (12x8 bit) */ +typedef struct snd_seq_ev_raw8 { + unsigned char d[12]; /**< 8 bit value */ +} snd_seq_ev_raw8_t; + +/** generic set of integers (3x32 bit) */ +typedef struct snd_seq_ev_raw32 { + unsigned int d[3]; /**< 32 bit value */ +} snd_seq_ev_raw32_t; + +/** external stored data */ +typedef struct snd_seq_ev_ext { + unsigned int len; /**< length of data */ + void *ptr; /**< pointer to data (note: can be 64-bit) */ +} __attribute__((packed)) snd_seq_ev_ext_t; + +/** Result events */ +typedef struct snd_seq_result { + int event; /**< processed event type */ + int result; /**< status */ +} snd_seq_result_t; + +/** Queue skew values */ +typedef struct snd_seq_queue_skew { + unsigned int value; /**< skew value */ + unsigned int base; /**< skew base */ +} snd_seq_queue_skew_t; + +/** queue timer control */ +typedef struct snd_seq_ev_queue_control { + unsigned char queue; /**< affected queue */ + unsigned char unused[3]; /**< reserved */ + union { + signed int value; /**< affected value (e.g. tempo) */ + snd_seq_timestamp_t time; /**< time */ + unsigned int position; /**< sync position */ + snd_seq_queue_skew_t skew; /**< queue skew */ + unsigned int d32[2]; /**< any data */ + unsigned char d8[8]; /**< any data */ + } param; /**< data value union */ +} snd_seq_ev_queue_control_t; + + +/** Sequencer event */ +typedef struct snd_seq_event { + snd_seq_event_type_t type; /**< event type */ + unsigned char flags; /**< event flags */ + unsigned char tag; /**< tag */ + + unsigned char queue; /**< schedule queue */ + snd_seq_timestamp_t time; /**< schedule time */ + + snd_seq_addr_t source; /**< source address */ + snd_seq_addr_t dest; /**< destination address */ + + union { + snd_seq_ev_note_t note; /**< note information */ + snd_seq_ev_ctrl_t control; /**< MIDI control information */ + snd_seq_ev_raw8_t raw8; /**< raw8 data */ + snd_seq_ev_raw32_t raw32; /**< raw32 data */ + snd_seq_ev_ext_t ext; /**< external data */ + snd_seq_ev_queue_control_t queue; /**< queue control */ + snd_seq_timestamp_t time; /**< timestamp */ + snd_seq_addr_t addr; /**< address */ + snd_seq_connect_t connect; /**< connect information */ + snd_seq_result_t result; /**< operation result code */ + } data; /**< event data... */ +} snd_seq_event_t; + + +/** \} */ + +#endif /* __ALSA_SEQ_EVENT_H */ + diff --git a/include/seq_midi_event.h b/include/seq_midi_event.h new file mode 100644 index 0000000..9b8ee59 --- /dev/null +++ b/include/seq_midi_event.h @@ -0,0 +1,65 @@ +/** + * \file include/seq_midi_event.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_SEQ_MIDI_EVENT_H +#define __ALSA_SEQ_MIDI_EVENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup MIDI_Event Sequencer event <-> MIDI byte stream coder + * \ingroup Sequencer + * Sequencer event <-> MIDI byte stream coder + * \{ + */ + +/** container for sequencer midi event parsers */ +typedef struct snd_midi_event snd_midi_event_t; + +int snd_midi_event_new(size_t bufsize, snd_midi_event_t **rdev); +int snd_midi_event_resize_buffer(snd_midi_event_t *dev, size_t bufsize); +void snd_midi_event_free(snd_midi_event_t *dev); +void snd_midi_event_init(snd_midi_event_t *dev); +void snd_midi_event_reset_encode(snd_midi_event_t *dev); +void snd_midi_event_reset_decode(snd_midi_event_t *dev); +void snd_midi_event_no_status(snd_midi_event_t *dev, int on); +/* encode from byte stream - return number of written bytes if success */ +long snd_midi_event_encode(snd_midi_event_t *dev, const unsigned char *buf, long count, snd_seq_event_t *ev); +int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev); +/* decode from event to bytes - return number of written bytes if success */ +long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count, const snd_seq_event_t *ev); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_SEQ_MIDI_EVENT_H */ + diff --git a/include/seqmid.h b/include/seqmid.h new file mode 100644 index 0000000..68069b2 --- /dev/null +++ b/include/seqmid.h @@ -0,0 +1,490 @@ +/** + * \file include/seqmid.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_SEQMID_H +#define __ALSA_SEQMID_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup SeqMiddle Sequencer Middle Level Interface + * Sequencer Middle Level Interface + * \ingroup Sequencer + * \{ + */ + +/** + * \brief initialize event record + * \param ev event record pointer + * + * This macro clears the given event record pointer to the default status. + */ +#define snd_seq_ev_clear(ev) \ + memset(ev, 0, sizeof(snd_seq_event_t)) + +/** + * \brief set the tag for given event + * \param ev event record + * \param t event tag + * + * This macro sets the tag to the given event record. + */ +#define snd_seq_ev_set_tag(ev,t) \ + ((ev)->tag = (t)) + +/** + * \brief set the explicit destination + * \param ev event record + * \param c destination client id + * \param p destination port id + * + * This macro sets the client and port id numbers to the given event record. + * + * \sa snd_seq_ev_set_subs() + */ +#define snd_seq_ev_set_dest(ev,c,p) \ + ((ev)->dest.client = (c), (ev)->dest.port = (p)) + +/** + * \brief set broadcasting to subscribers + * \param ev event record + * + * This macro sets the destination as the subscribers. + * + * \sa snd_seq_ev_set_dest() + */ +#define snd_seq_ev_set_subs(ev) \ + ((ev)->dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS,\ + (ev)->dest.port = SND_SEQ_ADDRESS_UNKNOWN) + +/** + * \brief set broadcasting to all clients/ports + * \param ev event record + * + * This macro sets the destination as the broadcasting. + * + * \sa snd_seq_ev_set_dest() + */ +#define snd_seq_ev_set_broadcast(ev) \ + ((ev)->dest.client = SND_SEQ_ADDRESS_BROADCAST,\ + (ev)->dest.port = SND_SEQ_ADDRESS_BROADCAST) + +/** + * \brief set the source port + * \param ev event record + * \param p source port id + * + * This macro sets the source port id number. + */ +#define snd_seq_ev_set_source(ev,p) \ + ((ev)->source.port = (p)) + +/** + * \brief set direct passing mode (without queued) + * \param ev event instance + * + * This macro sets the event to the direct passing mode + * to be delivered immediately without queueing. + * + * \sa snd_seq_ev_schedule_tick(), snd_seq_ev_schedule_real() + */ +#define snd_seq_ev_set_direct(ev) \ + ((ev)->queue = SND_SEQ_QUEUE_DIRECT) + +/** + * \brief set tick-scheduling mode on queue + * \param ev event instance + * \param q queue id to schedule + * \param relative relative time-stamp if non-zero + * \param ttick tick time-stamp to be delivered + * + * This macro sets the scheduling of the event in the + * MIDI tick mode. + * + * \sa snd_seq_ev_schedule_real(), snd_seq_ev_set_direct() + */ +#define snd_seq_ev_schedule_tick(ev, q, relative, ttick) \ + ((ev)->flags &= ~(SND_SEQ_TIME_STAMP_MASK | SND_SEQ_TIME_MODE_MASK),\ + (ev)->flags |= SND_SEQ_TIME_STAMP_TICK,\ + (ev)->flags |= (relative) ? SND_SEQ_TIME_MODE_REL : SND_SEQ_TIME_MODE_ABS,\ + (ev)->time.tick = (ttick),\ + (ev)->queue = (q)) + +/** + * \brief set real-time-scheduling mode on queue + * \param ev event instance + * \param q queue id to schedule + * \param relative relative time-stamp if non-zero + * \param rtime time-stamp to be delivered + * + * This macro sets the scheduling of the event in the + * realtime mode. + * + * \sa snd_seq_ev_schedule_tick(), snd_seq_ev_set_direct() + */ +#define snd_seq_ev_schedule_real(ev, q, relative, rtime) \ + ((ev)->flags &= ~(SND_SEQ_TIME_STAMP_MASK | SND_SEQ_TIME_MODE_MASK),\ + (ev)->flags |= SND_SEQ_TIME_STAMP_REAL,\ + (ev)->flags |= (relative) ? SND_SEQ_TIME_MODE_REL : SND_SEQ_TIME_MODE_ABS,\ + (ev)->time.time = *(rtime),\ + (ev)->queue = (q)) + +/** + * \brief set event priority + * \param ev event instance + * \param high_prior 1 for high priority mode + */ +#define snd_seq_ev_set_priority(ev, high_prior) \ + ((ev)->flags &= ~SND_SEQ_PRIORITY_MASK,\ + (ev)->flags |= (high_prior) ? SND_SEQ_PRIORITY_HIGH : SND_SEQ_PRIORITY_NORMAL) + +/** + * \brief set fixed data + * \param ev event instance + * + * Sets the event length mode as fixed size. + * + * \sa snd_seq_ev_set_variable(), snd_seq_ev_set_varusr() + */ +#define snd_seq_ev_set_fixed(ev) \ + ((ev)->flags &= ~SND_SEQ_EVENT_LENGTH_MASK,\ + (ev)->flags |= SND_SEQ_EVENT_LENGTH_FIXED) + +/** + * \brief set variable data + * \param ev event instance + * \param datalen length of the external data + * \param dataptr pointer of the external data + * + * Sets the event length mode as variable length and stores the data. + * + * \sa snd_seq_ev_set_fixed(), snd_seq_ev_set_varusr() + */ +#define snd_seq_ev_set_variable(ev, datalen, dataptr) \ + ((ev)->flags &= ~SND_SEQ_EVENT_LENGTH_MASK,\ + (ev)->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE,\ + (ev)->data.ext.len = (datalen),\ + (ev)->data.ext.ptr = (dataptr)) + +/** + * \brief set varusr data + * \param ev event instance + * \param datalen length of the external data + * \param dataptr pointer of the external data + * + * Sets the event length mode as variable user-space data and stores the data. + * + * \sa snd_seq_ev_set_fixed(), snd_seq_ev_set_variable() + */ +#define snd_seq_ev_set_varusr(ev, datalen, dataptr) \ + ((ev)->flags &= ~SND_SEQ_EVENT_LENGTH_MASK,\ + (ev)->flags |= SND_SEQ_EVENT_LENGTH_VARUSR,\ + (ev)->data.ext.len = (datalen),\ + (ev)->data.ext.ptr = (dataptr)) + +/** + * \brief set queue controls + * \param ev event record + * \param typ event type + * \param q queue id + * \param val control value + */ +#define snd_seq_ev_set_queue_control(ev, typ, q, val) \ + ((ev)->type = (typ),\ + snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\ + (ev)->data.queue.queue = (q),\ + (ev)->data.queue.param.value = (val)) + +/** + * \brief set the start queue event + * \param ev event record + * \param q queue id to start + * + * \sa snd_seq_ev_set_queue_stop(), snd_seq_ev_set_queue_continue() + */ +#define snd_seq_ev_set_queue_start(ev, q) \ + snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_START, q, 0) + +/** + * \brief set the stop queue event + * \param ev event record + * \param q queue id to stop + * + * \sa snd_seq_ev_set_queue_start(), snd_seq_ev_set_queue_continue() + */ +#define snd_seq_ev_set_queue_stop(ev, q) \ + snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_STOP, q, 0) + +/** + * \brief set the stop queue event + * \param ev event record + * \param q queue id to continue + * + * \sa snd_seq_ev_set_queue_start(), snd_seq_ev_set_queue_stop() + */ +#define snd_seq_ev_set_queue_continue(ev, q) \ + snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_CONTINUE, q, 0) + +/** + * \brief set the stop queue event + * \param ev event record + * \param q queue id to change tempo + * \param val the new tempo value + */ +#define snd_seq_ev_set_queue_tempo(ev, q, val) \ + snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_TEMPO, q, val) + +/** + * \brief set the real-time position of a queue + * \param ev event record + * \param q queue id to change tempo + * \param rtime the new real-time pointer + */ +#define snd_seq_ev_set_queue_pos_real(ev, q, rtime) \ + ((ev)->type = SND_SEQ_EVENT_SETPOS_TIME,\ + snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\ + (ev)->data.queue.queue = (q),\ + (ev)->data.queue.param.time.time = *(rtime)) + +/** + * \brief set the tick-time position of a queue + * \param ev event record + * \param q queue id to change tempo + * \param ttime the new tick-time + */ +#define snd_seq_ev_set_queue_pos_tick(ev, q, ttime) \ + ((ev)->type = SND_SEQ_EVENT_SETPOS_TICK,\ + snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\ + (ev)->data.queue.queue = (q),\ + (ev)->data.queue.param.time.tick = (ttime)) + +/* set and send a queue control event */ +int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev); + +/** + * \brief start the specified queue + * \param seq sequencer handle + * \param q queue id to start + * \param ev optional event record (see #snd_seq_control_queue) + */ +#define snd_seq_start_queue(seq, q, ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_START, 0, ev) + +/** + * \brief stop the specified queue + * \param seq sequencer handle + * \param q queue id to stop + * \param ev optional event record (see #snd_seq_control_queue) + */ +#define snd_seq_stop_queue(seq, q, ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_STOP, 0, ev) + +/** + * \brief continue the specified queue + * \param seq sequencer handle + * \param q queue id to continue + * \param ev optional event record (see #snd_seq_control_queue) + */ +#define snd_seq_continue_queue(seq, q, ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_CONTINUE, 0, ev) + +/** + * \brief change the tempo of the specified queue + * \param seq sequencer handle + * \param q queue id + * \param tempo the new tempo value + * \param ev optional event record (see #snd_seq_control_queue) + */ +#define snd_seq_change_queue_tempo(seq, q, tempo, ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_TEMPO, tempo, ev) + +/* create a port - simple version - return the port number */ +int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, + unsigned int caps, unsigned int type); +/* delete the port */ +int snd_seq_delete_simple_port(snd_seq_t *seq, int port); + +/* simple subscription between this port and another port + (w/o exclusive & time conversion) + */ +int snd_seq_connect_from(snd_seq_t *seq, int my_port, int src_client, int src_port); +int snd_seq_connect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port); +int snd_seq_disconnect_from(snd_seq_t *seq, int my_port, int src_client, int src_port); +int snd_seq_disconnect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port); + +/* + * set client information + */ +int snd_seq_set_client_name(snd_seq_t *seq, const char *name); +int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type); +int snd_seq_set_client_pool_output(snd_seq_t *seq, size_t size); +int snd_seq_set_client_pool_output_room(snd_seq_t *seq, size_t size); +int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size); +/* sync output queue */ +int snd_seq_sync_output_queue(snd_seq_t *seq); + +/* + * parse the given string and get the sequencer address + */ +int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *str); + +/* + * reset client input/output pool + */ +int snd_seq_reset_pool_output(snd_seq_t *seq); +int snd_seq_reset_pool_input(snd_seq_t *seq); + +/** + * \brief set note event + * \param ev event record + * \param ch channel number + * \param key note key + * \param vel velocity + * \param dur duration (in tick or msec) + */ +#define snd_seq_ev_set_note(ev, ch, key, vel, dur) \ + ((ev)->type = SND_SEQ_EVENT_NOTE,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.note.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel),\ + (ev)->data.note.duration = (dur)) + +/** + * \brief set note-on event + * \param ev event record + * \param ch channel number + * \param key note key + * \param vel velocity + */ +#define snd_seq_ev_set_noteon(ev, ch, key, vel) \ + ((ev)->type = SND_SEQ_EVENT_NOTEON,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.note.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel)) + +/** + * \brief set note-off event + * \param ev event record + * \param ch channel number + * \param key note key + * \param vel velocity + */ +#define snd_seq_ev_set_noteoff(ev, ch, key, vel) \ + ((ev)->type = SND_SEQ_EVENT_NOTEOFF,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.note.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel)) + +/** + * \brief set key-pressure event + * \param ev event record + * \param ch channel number + * \param key note key + * \param vel velocity + */ +#define snd_seq_ev_set_keypress(ev,ch,key,vel) \ + ((ev)->type = SND_SEQ_EVENT_KEYPRESS,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.note.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel)) + +/** + * \brief set MIDI controller event + * \param ev event record + * \param ch channel number + * \param cc controller number + * \param val control value + */ +#define snd_seq_ev_set_controller(ev,ch,cc,val) \ + ((ev)->type = SND_SEQ_EVENT_CONTROLLER,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.control.channel = (ch),\ + (ev)->data.control.param = (cc),\ + (ev)->data.control.value = (val)) + +/** + * \brief set program change event + * \param ev event record + * \param ch channel number + * \param val program number + */ +#define snd_seq_ev_set_pgmchange(ev,ch,val) \ + ((ev)->type = SND_SEQ_EVENT_PGMCHANGE,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.control.channel = (ch),\ + (ev)->data.control.value = (val)) + +/** + * \brief set pitch-bend event + * \param ev event record + * \param ch channel number + * \param val pitch bend; zero centered from -8192 to 8191 + */ +#define snd_seq_ev_set_pitchbend(ev,ch,val) \ + ((ev)->type = SND_SEQ_EVENT_PITCHBEND,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.control.channel = (ch),\ + (ev)->data.control.value = (val)) + +/** + * \brief set channel pressure event + * \param ev event record + * \param ch channel number + * \param val channel pressure value + */ +#define snd_seq_ev_set_chanpress(ev,ch,val) \ + ((ev)->type = SND_SEQ_EVENT_CHANPRESS,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->data.control.channel = (ch),\ + (ev)->data.control.value = (val)) + +/** + * \brief set sysex event + * \param ev event record + * \param datalen length of sysex data + * \param dataptr sysex data pointer + * + * the sysex data must contain the start byte 0xf0 and the end byte 0xf7. + */ +#define snd_seq_ev_set_sysex(ev,datalen,dataptr) \ + ((ev)->type = SND_SEQ_EVENT_SYSEX,\ + snd_seq_ev_set_variable(ev, datalen, dataptr)) + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_SEQMID_H */ + diff --git a/include/sound/Makefile.am b/include/sound/Makefile.am new file mode 100644 index 0000000..31aa2db --- /dev/null +++ b/include/sound/Makefile.am @@ -0,0 +1,6 @@ +alsasoundincludedir = ${includedir}/alsa/sound + +alsasoundinclude_HEADERS = asound_fm.h hdsp.h hdspm.h sb16_csp.h \ + sscape_ioctl.h emu10k1.h type_compat.h + +noinst_HEADERS = asound.h asoundef.h asequencer.h diff --git a/include/sound/Makefile.in b/include/sound/Makefile.in new file mode 100644 index 0000000..30dc69a --- /dev/null +++ b/include/sound/Makefile.in @@ -0,0 +1,470 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include/sound +DIST_COMMON = $(alsasoundinclude_HEADERS) $(noinst_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(alsasoundincludedir)" +HEADERS = $(alsasoundinclude_HEADERS) $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +alsasoundincludedir = ${includedir}/alsa/sound +alsasoundinclude_HEADERS = asound_fm.h hdsp.h hdspm.h sb16_csp.h \ + sscape_ioctl.h emu10k1.h type_compat.h + +noinst_HEADERS = asound.h asoundef.h asequencer.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/sound/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/sound/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-alsasoundincludeHEADERS: $(alsasoundinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(alsasoundincludedir)" || $(MKDIR_P) "$(DESTDIR)$(alsasoundincludedir)" + @list='$(alsasoundinclude_HEADERS)'; test -n "$(alsasoundincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(alsasoundincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(alsasoundincludedir)" || exit $$?; \ + done + +uninstall-alsasoundincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(alsasoundinclude_HEADERS)'; test -n "$(alsasoundincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(alsasoundincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(alsasoundincludedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(alsasoundincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-alsasoundincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-alsasoundincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-alsasoundincludeHEADERS \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-alsasoundincludeHEADERS uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h new file mode 100644 index 0000000..6d14fb1 --- /dev/null +++ b/include/sound/asequencer.h @@ -0,0 +1,678 @@ +/* + * Main header file for the ALSA sequencer + * Copyright (c) 1998-1999 by Frank van de Pol + * (c) 1998-1999 by Jaroslav Kysela + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __SOUND_ASEQUENCER_H +#define __SOUND_ASEQUENCER_H + +#ifdef __KERNEL__ +#include +#endif + +#include + +/** version of the sequencer */ +#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1) + +#ifdef __KERNEL__ +/** + * definition of sequencer event types + */ + +/** system messages + * event data type = #sndrv_seq_result_t + */ +#define SNDRV_SEQ_EVENT_SYSTEM 0 +#define SNDRV_SEQ_EVENT_RESULT 1 + +/** note messages (channel specific) + * event data type = #sndrv_seq_ev_note + */ +#define SNDRV_SEQ_EVENT_NOTE 5 +#define SNDRV_SEQ_EVENT_NOTEON 6 +#define SNDRV_SEQ_EVENT_NOTEOFF 7 +#define SNDRV_SEQ_EVENT_KEYPRESS 8 + +/** control messages (channel specific) + * event data type = #sndrv_seq_ev_ctrl + */ +#define SNDRV_SEQ_EVENT_CONTROLLER 10 +#define SNDRV_SEQ_EVENT_PGMCHANGE 11 +#define SNDRV_SEQ_EVENT_CHANPRESS 12 +#define SNDRV_SEQ_EVENT_PITCHBEND 13 /**< from -8192 to 8191 */ +#define SNDRV_SEQ_EVENT_CONTROL14 14 /**< 14 bit controller value */ +#define SNDRV_SEQ_EVENT_NONREGPARAM 15 /**< 14 bit NRPN address + 14 bit unsigned value */ +#define SNDRV_SEQ_EVENT_REGPARAM 16 /**< 14 bit RPN address + 14 bit unsigned value */ + +/** synchronisation messages + * event data type = #sndrv_seq_ev_ctrl + */ +#define SNDRV_SEQ_EVENT_SONGPOS 20 /* Song Position Pointer with LSB and MSB values */ +#define SNDRV_SEQ_EVENT_SONGSEL 21 /* Song Select with song ID number */ +#define SNDRV_SEQ_EVENT_QFRAME 22 /* midi time code quarter frame */ +#define SNDRV_SEQ_EVENT_TIMESIGN 23 /* SMF Time Signature event */ +#define SNDRV_SEQ_EVENT_KEYSIGN 24 /* SMF Key Signature event */ + +/** timer messages + * event data type = sndrv_seq_ev_queue_control_t + */ +#define SNDRV_SEQ_EVENT_START 30 /* midi Real Time Start message */ +#define SNDRV_SEQ_EVENT_CONTINUE 31 /* midi Real Time Continue message */ +#define SNDRV_SEQ_EVENT_STOP 32 /* midi Real Time Stop message */ +#define SNDRV_SEQ_EVENT_SETPOS_TICK 33 /* set tick queue position */ +#define SNDRV_SEQ_EVENT_SETPOS_TIME 34 /* set realtime queue position */ +#define SNDRV_SEQ_EVENT_TEMPO 35 /* (SMF) Tempo event */ +#define SNDRV_SEQ_EVENT_CLOCK 36 /* midi Real Time Clock message */ +#define SNDRV_SEQ_EVENT_TICK 37 /* midi Real Time Tick message */ +#define SNDRV_SEQ_EVENT_QUEUE_SKEW 38 /* skew queue tempo */ + +/** others + * event data type = none + */ +#define SNDRV_SEQ_EVENT_TUNE_REQUEST 40 /* tune request */ +#define SNDRV_SEQ_EVENT_RESET 41 /* reset to power-on state */ +#define SNDRV_SEQ_EVENT_SENSING 42 /* "active sensing" event */ + +/** echo back, kernel private messages + * event data type = any type + */ +#define SNDRV_SEQ_EVENT_ECHO 50 /* echo event */ +#define SNDRV_SEQ_EVENT_OSS 51 /* OSS raw event */ + +/** system status messages (broadcast for subscribers) + * event data type = sndrv_seq_addr_t + */ +#define SNDRV_SEQ_EVENT_CLIENT_START 60 /* new client has connected */ +#define SNDRV_SEQ_EVENT_CLIENT_EXIT 61 /* client has left the system */ +#define SNDRV_SEQ_EVENT_CLIENT_CHANGE 62 /* client status/info has changed */ +#define SNDRV_SEQ_EVENT_PORT_START 63 /* new port was created */ +#define SNDRV_SEQ_EVENT_PORT_EXIT 64 /* port was deleted from system */ +#define SNDRV_SEQ_EVENT_PORT_CHANGE 65 /* port status/info has changed */ + +/** port connection changes + * event data type = sndrv_seq_connect_t + */ +#define SNDRV_SEQ_EVENT_PORT_SUBSCRIBED 66 /* ports connected */ +#define SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED 67 /* ports disconnected */ + +/* 70-89: synthesizer events - obsoleted */ + +/** user-defined events with fixed length + * event data type = any + */ +#define SNDRV_SEQ_EVENT_USR0 90 +#define SNDRV_SEQ_EVENT_USR1 91 +#define SNDRV_SEQ_EVENT_USR2 92 +#define SNDRV_SEQ_EVENT_USR3 93 +#define SNDRV_SEQ_EVENT_USR4 94 +#define SNDRV_SEQ_EVENT_USR5 95 +#define SNDRV_SEQ_EVENT_USR6 96 +#define SNDRV_SEQ_EVENT_USR7 97 +#define SNDRV_SEQ_EVENT_USR8 98 +#define SNDRV_SEQ_EVENT_USR9 99 + +/* 100-118: instrument layer - obsoleted */ +/* 119-129: reserved */ + +/* 130-139: variable length events + * event data type = sndrv_seq_ev_ext + * (SNDRV_SEQ_EVENT_LENGTH_VARIABLE must be set) + */ +#define SNDRV_SEQ_EVENT_SYSEX 130 /* system exclusive data (variable length) */ +#define SNDRV_SEQ_EVENT_BOUNCE 131 /* error event */ +/* 132-134: reserved */ +#define SNDRV_SEQ_EVENT_USR_VAR0 135 +#define SNDRV_SEQ_EVENT_USR_VAR1 136 +#define SNDRV_SEQ_EVENT_USR_VAR2 137 +#define SNDRV_SEQ_EVENT_USR_VAR3 138 +#define SNDRV_SEQ_EVENT_USR_VAR4 139 + +/* 150-151: kernel events with quote - DO NOT use in user clients */ +#define SNDRV_SEQ_EVENT_KERNEL_ERROR 150 +#define SNDRV_SEQ_EVENT_KERNEL_QUOTE 151 /* obsolete */ + +/* 152-191: reserved */ + +/* 192-254: hardware specific events */ + +/* 255: special event */ +#define SNDRV_SEQ_EVENT_NONE 255 + + +typedef unsigned char sndrv_seq_event_type_t; + +/** event address */ +struct sndrv_seq_addr { + unsigned char client; /**< Client number: 0..255, 255 = broadcast to all clients */ + unsigned char port; /**< Port within client: 0..255, 255 = broadcast to all ports */ +}; + +/** port connection */ +struct sndrv_seq_connect { + struct sndrv_seq_addr sender; + struct sndrv_seq_addr dest; +}; + + +#define SNDRV_SEQ_ADDRESS_UNKNOWN 253 /* unknown source */ +#define SNDRV_SEQ_ADDRESS_SUBSCRIBERS 254 /* send event to all subscribed ports */ +#define SNDRV_SEQ_ADDRESS_BROADCAST 255 /* send event to all queues/clients/ports/channels */ +#define SNDRV_SEQ_QUEUE_DIRECT 253 /* direct dispatch */ + + /* event mode flag - NOTE: only 8 bits available! */ +#define SNDRV_SEQ_TIME_STAMP_TICK (0<<0) /* timestamp in clock ticks */ +#define SNDRV_SEQ_TIME_STAMP_REAL (1<<0) /* timestamp in real time */ +#define SNDRV_SEQ_TIME_STAMP_MASK (1<<0) + +#define SNDRV_SEQ_TIME_MODE_ABS (0<<1) /* absolute timestamp */ +#define SNDRV_SEQ_TIME_MODE_REL (1<<1) /* relative to current time */ +#define SNDRV_SEQ_TIME_MODE_MASK (1<<1) + +#define SNDRV_SEQ_EVENT_LENGTH_FIXED (0<<2) /* fixed event size */ +#define SNDRV_SEQ_EVENT_LENGTH_VARIABLE (1<<2) /* variable event size */ +#define SNDRV_SEQ_EVENT_LENGTH_VARUSR (2<<2) /* variable event size - user memory space */ +#define SNDRV_SEQ_EVENT_LENGTH_MASK (3<<2) + +#define SNDRV_SEQ_PRIORITY_NORMAL (0<<4) /* normal priority */ +#define SNDRV_SEQ_PRIORITY_HIGH (1<<4) /* event should be processed before others */ +#define SNDRV_SEQ_PRIORITY_MASK (1<<4) + + + /* note event */ +struct sndrv_seq_ev_note { + unsigned char channel; + unsigned char note; + unsigned char velocity; + unsigned char off_velocity; /* only for SNDRV_SEQ_EVENT_NOTE */ + unsigned int duration; /* only for SNDRV_SEQ_EVENT_NOTE */ +}; + + /* controller event */ +struct sndrv_seq_ev_ctrl { + unsigned char channel; + unsigned char unused1, unused2, unused3; /* pad */ + unsigned int param; + signed int value; +}; + + /* generic set of bytes (12x8 bit) */ +struct sndrv_seq_ev_raw8 { + unsigned char d[12]; /* 8 bit value */ +}; + + /* generic set of integers (3x32 bit) */ +struct sndrv_seq_ev_raw32 { + unsigned int d[3]; /* 32 bit value */ +}; + + /* external stored data */ +struct sndrv_seq_ev_ext { + unsigned int len; /* length of data */ + void *ptr; /* pointer to data (note: maybe 64-bit) */ +} __attribute__((packed)); + +struct sndrv_seq_result { + int event; /* processed event type */ + int result; +}; + + +struct sndrv_seq_real_time { + unsigned int tv_sec; /* seconds */ + unsigned int tv_nsec; /* nanoseconds */ +}; + +typedef unsigned int sndrv_seq_tick_time_t; /* midi ticks */ + +union sndrv_seq_timestamp { + sndrv_seq_tick_time_t tick; + struct sndrv_seq_real_time time; +}; + +struct sndrv_seq_queue_skew { + unsigned int value; + unsigned int base; +}; + + /* queue timer control */ +struct sndrv_seq_ev_queue_control { + unsigned char queue; /* affected queue */ + unsigned char pad[3]; /* reserved */ + union { + signed int value; /* affected value (e.g. tempo) */ + union sndrv_seq_timestamp time; /* time */ + unsigned int position; /* sync position */ + struct sndrv_seq_queue_skew skew; + unsigned int d32[2]; + unsigned char d8[8]; + } param; +}; + + /* quoted event - inside the kernel only */ +struct sndrv_seq_ev_quote { + struct sndrv_seq_addr origin; /* original sender */ + unsigned short value; /* optional data */ + struct sndrv_seq_event *event; /* quoted event */ +} __attribute__((packed)); + + + /* sequencer event */ +struct sndrv_seq_event { + sndrv_seq_event_type_t type; /* event type */ + unsigned char flags; /* event flags */ + char tag; + + unsigned char queue; /* schedule queue */ + union sndrv_seq_timestamp time; /* schedule time */ + + + struct sndrv_seq_addr source; /* source address */ + struct sndrv_seq_addr dest; /* destination address */ + + union { /* event data... */ + struct sndrv_seq_ev_note note; + struct sndrv_seq_ev_ctrl control; + struct sndrv_seq_ev_raw8 raw8; + struct sndrv_seq_ev_raw32 raw32; + struct sndrv_seq_ev_ext ext; + struct sndrv_seq_ev_queue_control queue; + union sndrv_seq_timestamp time; + struct sndrv_seq_addr addr; + struct sndrv_seq_connect connect; + struct sndrv_seq_result result; + struct sndrv_seq_ev_quote quote; + } data; +}; + + +/* + * bounce event - stored as variable size data + */ +struct sndrv_seq_event_bounce { + int err; + struct sndrv_seq_event event; + /* external data follows here. */ +}; + +#define sndrv_seq_event_bounce_ext_data(ev) ((void*)((char *)(ev)->data.ext.ptr + sizeof(sndrv_seq_event_bounce_t))) + +/* + * type check macros + */ +/* result events: 0-4 */ +#define sndrv_seq_ev_is_result_type(ev) ((ev)->type < 5) +/* channel specific events: 5-19 */ +#define sndrv_seq_ev_is_channel_type(ev) ((ev)->type >= 5 && (ev)->type < 20) +/* note events: 5-9 */ +#define sndrv_seq_ev_is_note_type(ev) ((ev)->type >= 5 && (ev)->type < 10) +/* control events: 10-19 */ +#define sndrv_seq_ev_is_control_type(ev) ((ev)->type >= 10 && (ev)->type < 20) +/* queue control events: 30-39 */ +#define sndrv_seq_ev_is_queue_type(ev) ((ev)->type >= 30 && (ev)->type < 40) +/* system status messages */ +#define sndrv_seq_ev_is_message_type(ev) ((ev)->type >= 60 && (ev)->type < 69) +/* sample messages */ +#define sndrv_seq_ev_is_sample_type(ev) ((ev)->type >= 70 && (ev)->type < 79) +/* user-defined messages */ +#define sndrv_seq_ev_is_user_type(ev) ((ev)->type >= 90 && (ev)->type < 99) +/* fixed length events: 0-99 */ +#define sndrv_seq_ev_is_fixed_type(ev) ((ev)->type < 100) +/* variable length events: 130-139 */ +#define sndrv_seq_ev_is_variable_type(ev) ((ev)->type >= 130 && (ev)->type < 140) +/* reserved for kernel */ +#define sndrv_seq_ev_is_reserved(ev) ((ev)->type >= 150) + +/* direct dispatched events */ +#define sndrv_seq_ev_is_direct(ev) ((ev)->queue == SNDRV_SEQ_QUEUE_DIRECT) + +/* + * macros to check event flags + */ +/* prior events */ +#define sndrv_seq_ev_is_prior(ev) (((ev)->flags & SNDRV_SEQ_PRIORITY_MASK) == SNDRV_SEQ_PRIORITY_HIGH) + +/* event length type */ +#define sndrv_seq_ev_length_type(ev) ((ev)->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) +#define sndrv_seq_ev_is_fixed(ev) (sndrv_seq_ev_length_type(ev) == SNDRV_SEQ_EVENT_LENGTH_FIXED) +#define sndrv_seq_ev_is_variable(ev) (sndrv_seq_ev_length_type(ev) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE) +#define sndrv_seq_ev_is_varusr(ev) (sndrv_seq_ev_length_type(ev) == SNDRV_SEQ_EVENT_LENGTH_VARUSR) + +/* time-stamp type */ +#define sndrv_seq_ev_timestamp_type(ev) ((ev)->flags & SNDRV_SEQ_TIME_STAMP_MASK) +#define sndrv_seq_ev_is_tick(ev) (sndrv_seq_ev_timestamp_type(ev) == SNDRV_SEQ_TIME_STAMP_TICK) +#define sndrv_seq_ev_is_real(ev) (sndrv_seq_ev_timestamp_type(ev) == SNDRV_SEQ_TIME_STAMP_REAL) + +/* time-mode type */ +#define sndrv_seq_ev_timemode_type(ev) ((ev)->flags & SNDRV_SEQ_TIME_MODE_MASK) +#define sndrv_seq_ev_is_abstime(ev) (sndrv_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_ABS) +#define sndrv_seq_ev_is_reltime(ev) (sndrv_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_REL) + +/* queue sync port */ +#define sndrv_seq_queue_sync_port(q) ((q) + 16) + +#endif /* __KERNEL__ */ + + /* system information */ +struct sndrv_seq_system_info { + int queues; /* maximum queues count */ + int clients; /* maximum clients count */ + int ports; /* maximum ports per client */ + int channels; /* maximum channels per port */ + int cur_clients; /* current clients */ + int cur_queues; /* current queues */ + char reserved[24]; +}; + + + /* system running information */ +struct sndrv_seq_running_info { + unsigned char client; /* client id */ + unsigned char big_endian; /* 1 = big-endian */ + unsigned char cpu_mode; /* 4 = 32bit, 8 = 64bit */ + unsigned char pad; /* reserved */ + unsigned char reserved[12]; +}; + + + /* known client numbers */ +#define SNDRV_SEQ_CLIENT_SYSTEM 0 + /* internal client numbers */ +#define SNDRV_SEQ_CLIENT_DUMMY 14 /* midi through */ +#define SNDRV_SEQ_CLIENT_OSS 15 /* oss sequencer emulator */ + + + /* client types */ +enum sndrv_seq_client_type { + NO_CLIENT = 0, + USER_CLIENT = 1, + KERNEL_CLIENT = 2 +}; + + /* event filter flags */ +#define SNDRV_SEQ_FILTER_BROADCAST (1<<0) /* accept broadcast messages */ +#define SNDRV_SEQ_FILTER_MULTICAST (1<<1) /* accept multicast messages */ +#define SNDRV_SEQ_FILTER_BOUNCE (1<<2) /* accept bounce event in error */ +#define SNDRV_SEQ_FILTER_USE_EVENT (1<<31) /* use event filter */ + +struct sndrv_seq_client_info { + int client; /* client number to inquire */ + int type; /* client type */ + char name[64]; /* client name */ + unsigned int filter; /* filter flags */ + unsigned char multicast_filter[8]; /* multicast filter bitmap */ + unsigned char event_filter[32]; /* event filter bitmap */ + int num_ports; /* RO: number of ports */ + int event_lost; /* number of lost events */ + char reserved[64]; /* for future use */ +}; + + +/* client pool size */ +struct sndrv_seq_client_pool { + int client; /* client number to inquire */ + int output_pool; /* outgoing (write) pool size */ + int input_pool; /* incoming (read) pool size */ + int output_room; /* minimum free pool size for select/blocking mode */ + int output_free; /* unused size */ + int input_free; /* unused size */ + char reserved[64]; +}; + + +/* Remove events by specified criteria */ + +#define SNDRV_SEQ_REMOVE_INPUT (1<<0) /* Flush input queues */ +#define SNDRV_SEQ_REMOVE_OUTPUT (1<<1) /* Flush output queues */ +#define SNDRV_SEQ_REMOVE_DEST (1<<2) /* Restrict by destination q:client:port */ +#define SNDRV_SEQ_REMOVE_DEST_CHANNEL (1<<3) /* Restrict by channel */ +#define SNDRV_SEQ_REMOVE_TIME_BEFORE (1<<4) /* Restrict to before time */ +#define SNDRV_SEQ_REMOVE_TIME_AFTER (1<<5) /* Restrict to time or after */ +#define SNDRV_SEQ_REMOVE_TIME_TICK (1<<6) /* Time is in ticks */ +#define SNDRV_SEQ_REMOVE_EVENT_TYPE (1<<7) /* Restrict to event type */ +#define SNDRV_SEQ_REMOVE_IGNORE_OFF (1<<8) /* Do not flush off events */ +#define SNDRV_SEQ_REMOVE_TAG_MATCH (1<<9) /* Restrict to events with given tag */ + +struct sndrv_seq_remove_events { + unsigned int remove_mode; /* Flags that determine what gets removed */ + + union sndrv_seq_timestamp time; + + unsigned char queue; /* Queue for REMOVE_DEST */ + struct sndrv_seq_addr dest; /* Address for REMOVE_DEST */ + unsigned char channel; /* Channel for REMOVE_DEST */ + + int type; /* For REMOVE_EVENT_TYPE */ + char tag; /* Tag for REMOVE_TAG */ + + int reserved[10]; /* To allow for future binary compatibility */ + +}; + + + /* known port numbers */ +#define SNDRV_SEQ_PORT_SYSTEM_TIMER 0 +#define SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE 1 + + /* port capabilities (32 bits) */ +#define SNDRV_SEQ_PORT_CAP_READ (1<<0) /* readable from this port */ +#define SNDRV_SEQ_PORT_CAP_WRITE (1<<1) /* writable to this port */ + +#define SNDRV_SEQ_PORT_CAP_SYNC_READ (1<<2) +#define SNDRV_SEQ_PORT_CAP_SYNC_WRITE (1<<3) + +#define SNDRV_SEQ_PORT_CAP_DUPLEX (1<<4) + +#define SNDRV_SEQ_PORT_CAP_SUBS_READ (1<<5) /* allow read subscription */ +#define SNDRV_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /* allow write subscription */ +#define SNDRV_SEQ_PORT_CAP_NO_EXPORT (1<<7) /* routing not allowed */ + + /* port type */ +#define SNDRV_SEQ_PORT_TYPE_SPECIFIC (1<<0) /* hardware specific */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC (1<<1) /* generic MIDI device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_GM (1<<2) /* General MIDI compatible device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_GS (1<<3) /* GS compatible device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_XG (1<<4) /* XG compatible device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) /* MT-32 compatible device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_GM2 (1<<6) /* General MIDI 2 compatible device */ + +/* other standards...*/ +#define SNDRV_SEQ_PORT_TYPE_SYNTH (1<<10) /* Synth device (no MIDI compatible - direct wavetable) */ +#define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) /* Sampling device (support sample download) */ +#define SNDRV_SEQ_PORT_TYPE_SAMPLE (1<<12) /* Sampling device (sample can be downloaded at any time) */ +/*...*/ +#define SNDRV_SEQ_PORT_TYPE_HARDWARE (1<<16) /* driver for a hardware device */ +#define SNDRV_SEQ_PORT_TYPE_SOFTWARE (1<<17) /* implemented in software */ +#define SNDRV_SEQ_PORT_TYPE_SYNTHESIZER (1<<18) /* generates sound */ +#define SNDRV_SEQ_PORT_TYPE_PORT (1<<19) /* connects to other device(s) */ +#define SNDRV_SEQ_PORT_TYPE_APPLICATION (1<<20) /* application (sequencer/editor) */ + +/* misc. conditioning flags */ +#define SNDRV_SEQ_PORT_FLG_GIVEN_PORT (1<<0) +#define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1) +#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2) + +struct sndrv_seq_port_info { + struct sndrv_seq_addr addr; /* client/port numbers */ + char name[64]; /* port name */ + + unsigned int capability; /* port capability bits */ + unsigned int type; /* port type bits */ + int midi_channels; /* channels per MIDI port */ + int midi_voices; /* voices per MIDI port */ + int synth_voices; /* voices per SYNTH port */ + + int read_use; /* R/O: subscribers for output (from this port) */ + int write_use; /* R/O: subscribers for input (to this port) */ + + void *kernel; /* reserved for kernel use (must be NULL) */ + unsigned int flags; /* misc. conditioning */ + unsigned char time_queue; /* queue # for timestamping */ + char reserved[59]; /* for future use */ +}; + + +/* queue flags */ +#define SNDRV_SEQ_QUEUE_FLG_SYNC (1<<0) /* sync enabled */ + +/* queue information */ +struct sndrv_seq_queue_info { + int queue; /* queue id */ + + /* + * security settings, only owner of this queue can start/stop timer + * etc. if the queue is locked for other clients + */ + int owner; /* client id for owner of the queue */ + int locked:1; /* timing queue locked for other queues */ + char name[64]; /* name of this queue */ + unsigned int flags; /* flags */ + char reserved[60]; /* for future use */ + +}; + +/* queue info/status */ +struct sndrv_seq_queue_status { + int queue; /* queue id */ + int events; /* read-only - queue size */ + sndrv_seq_tick_time_t tick; /* current tick */ + struct sndrv_seq_real_time time; /* current time */ + int running; /* running state of queue */ + int flags; /* various flags */ + char reserved[64]; /* for the future */ +}; + + +/* queue tempo */ +struct sndrv_seq_queue_tempo { + int queue; /* sequencer queue */ + unsigned int tempo; /* current tempo, us/tick */ + int ppq; /* time resolution, ticks/quarter */ + unsigned int skew_value; /* queue skew */ + unsigned int skew_base; /* queue skew base */ + char reserved[24]; /* for the future */ +}; + + +/* sequencer timer sources */ +#define SNDRV_SEQ_TIMER_ALSA 0 /* ALSA timer */ +#define SNDRV_SEQ_TIMER_MIDI_CLOCK 1 /* Midi Clock (CLOCK event) */ +#define SNDRV_SEQ_TIMER_MIDI_TICK 2 /* Midi Timer Tick (TICK event) */ + +/* queue timer info */ +struct sndrv_seq_queue_timer { + int queue; /* sequencer queue */ + int type; /* source timer type */ + union { + struct { + struct sndrv_timer_id id; /* ALSA's timer ID */ + unsigned int resolution; /* resolution in Hz */ + } alsa; + } u; + char reserved[64]; /* for the future use */ +}; + + +struct sndrv_seq_queue_client { + int queue; /* sequencer queue */ + int client; /* sequencer client */ + int used; /* queue is used with this client + (must be set for accepting events) */ + /* per client watermarks */ + char reserved[64]; /* for future use */ +}; + + +#define SNDRV_SEQ_PORT_SUBS_EXCLUSIVE (1<<0) /* exclusive connection */ +#define SNDRV_SEQ_PORT_SUBS_TIMESTAMP (1<<1) +#define SNDRV_SEQ_PORT_SUBS_TIME_REAL (1<<2) + +struct sndrv_seq_port_subscribe { + struct sndrv_seq_addr sender; /* sender address */ + struct sndrv_seq_addr dest; /* destination address */ + unsigned int voices; /* number of voices to be allocated (0 = don't care) */ + unsigned int flags; /* modes */ + unsigned char queue; /* input time-stamp queue (optional) */ + unsigned char pad[3]; /* reserved */ + char reserved[64]; +}; + +/* type of query subscription */ +#define SNDRV_SEQ_QUERY_SUBS_READ 0 +#define SNDRV_SEQ_QUERY_SUBS_WRITE 1 + +struct sndrv_seq_query_subs { + struct sndrv_seq_addr root; /* client/port id to be searched */ + int type; /* READ or WRITE */ + int index; /* 0..N-1 */ + int num_subs; /* R/O: number of subscriptions on this port */ + struct sndrv_seq_addr addr; /* R/O: result */ + unsigned char queue; /* R/O: result */ + unsigned int flags; /* R/O: result */ + char reserved[64]; /* for future use */ +}; + + +/* + * IOCTL commands + */ + +#define SNDRV_SEQ_IOCTL_PVERSION _IOR ('S', 0x00, int) +#define SNDRV_SEQ_IOCTL_CLIENT_ID _IOR ('S', 0x01, int) +#define SNDRV_SEQ_IOCTL_SYSTEM_INFO _IOWR('S', 0x02, struct sndrv_seq_system_info) +#define SNDRV_SEQ_IOCTL_RUNNING_MODE _IOWR('S', 0x03, struct sndrv_seq_running_info) + +#define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct sndrv_seq_client_info) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct sndrv_seq_client_info) + +#define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_GET_PORT_INFO _IOWR('S', 0x22, struct sndrv_seq_port_info) +#define SNDRV_SEQ_IOCTL_SET_PORT_INFO _IOW ('S', 0x23, struct sndrv_seq_port_info) + +#define SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT _IOW ('S', 0x30, struct sndrv_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT _IOW ('S', 0x31, struct sndrv_seq_port_subscribe) + +#define SNDRV_SEQ_IOCTL_CREATE_QUEUE _IOWR('S', 0x32, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_DELETE_QUEUE _IOW ('S', 0x33, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_INFO _IOWR('S', 0x34, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_INFO _IOWR('S', 0x35, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE _IOWR('S', 0x36, struct sndrv_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS _IOWR('S', 0x40, struct sndrv_seq_queue_status) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO _IOWR('S', 0x41, struct sndrv_seq_queue_tempo) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO _IOW ('S', 0x42, struct sndrv_seq_queue_tempo) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_OWNER _IOWR('S', 0x43, struct sndrv_seq_queue_owner) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_OWNER _IOW ('S', 0x44, struct sndrv_seq_queue_owner) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER _IOWR('S', 0x45, struct sndrv_seq_queue_timer) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER _IOW ('S', 0x46, struct sndrv_seq_queue_timer) +/* XXX +#define SNDRV_SEQ_IOCTL_GET_QUEUE_SYNC _IOWR('S', 0x53, struct sndrv_seq_queue_sync) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_SYNC _IOW ('S', 0x54, struct sndrv_seq_queue_sync) +*/ +#define SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT _IOWR('S', 0x49, struct sndrv_seq_queue_client) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT _IOW ('S', 0x4a, struct sndrv_seq_queue_client) +#define SNDRV_SEQ_IOCTL_GET_CLIENT_POOL _IOWR('S', 0x4b, struct sndrv_seq_client_pool) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_POOL _IOW ('S', 0x4c, struct sndrv_seq_client_pool) +#define SNDRV_SEQ_IOCTL_REMOVE_EVENTS _IOW ('S', 0x4e, struct sndrv_seq_remove_events) +#define SNDRV_SEQ_IOCTL_QUERY_SUBS _IOWR('S', 0x4f, struct sndrv_seq_query_subs) +#define SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION _IOWR('S', 0x50, struct sndrv_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT _IOWR('S', 0x51, struct sndrv_seq_client_info) +#define SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT _IOWR('S', 0x52, struct sndrv_seq_port_info) + +#endif /* __SOUND_ASEQUENCER_H */ diff --git a/include/sound/asound.h b/include/sound/asound.h new file mode 100644 index 0000000..17dfe8f --- /dev/null +++ b/include/sound/asound.h @@ -0,0 +1,957 @@ +/* + * Advanced Linux Sound Architecture - ALSA - Driver + * Copyright (c) 1994-2003 by Jaroslav Kysela , + * Abramo Bagnara + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __SOUND_ASOUND_H +#define __SOUND_ASOUND_H + +#if defined(LINUX) || defined(__LINUX__) || defined(__linux__) + +#include + +#ifdef __KERNEL__ + +#include +#include +#include + +#if __LITTLE_ENDIAN == 1234 +#define SNDRV_LITTLE_ENDIAN +#elif __BIG_ENDIAN == 4321 +#define SNDRV_BIG_ENDIAN +#else +#error "Unsupported endian..." +#endif + +#else /* !__KERNEL__ */ + +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SNDRV_LITTLE_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +#define SNDRV_BIG_ENDIAN +#else +#error "Unsupported endian..." +#endif + +#endif /* __KERNEL **/ + +#endif /* LINUX */ + +#ifndef __KERNEL__ +#include +#include +#include +#endif + +/* + * protocol version + */ + +#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor)) +#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff) +#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff) +#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff) +#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) \ + (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || \ + (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && \ + SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion))) + +/**************************************************************************** + * * + * Digital audio interface * + * * + ****************************************************************************/ + +struct sndrv_aes_iec958 { + unsigned char status[24]; /* AES/IEC958 channel status bits */ + unsigned char subcode[147]; /* AES/IEC958 subcode bits */ + unsigned char pad; /* nothing */ + unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */ +}; + +/**************************************************************************** + * * + * Section for driver hardware dependent interface - /dev/snd/hw? * + * * + ****************************************************************************/ + +#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +enum sndrv_hwdep_iface { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, /* Creative Signal Processor */ + SNDRV_HWDEP_IFACE_EMU10K1, /* FX8010 processor in EMU10K1 chip */ + SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */ + SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */ + SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */ + SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */ + SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */ + SNDRV_HWDEP_IFACE_USX2Y, /* Tascam US122, US224 & US428 usb */ + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, /* EmuX wavetable */ + SNDRV_HWDEP_IFACE_BLUETOOTH, /* Bluetooth audio */ + SNDRV_HWDEP_IFACE_USX2Y_PCM, /* Tascam US122, US224 & US428 rawusb pcm */ + SNDRV_HWDEP_IFACE_PCXHR, /* Digigram PCXHR */ + SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ + + /* Don't forget to change the following: */ + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC +}; + +struct sndrv_hwdep_info { + unsigned int device; /* WR: device number */ + int card; /* R: card number */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* hwdep name */ + int iface; /* hwdep interface */ + unsigned char reserved[64]; /* reserved for future */ +}; + +/* generic DSP loader */ +struct sndrv_hwdep_dsp_status { + unsigned int version; /* R: driver-specific version */ + unsigned char id[32]; /* R: driver-specific ID string */ + unsigned int num_dsps; /* R: number of DSP images to transfer */ + unsigned int dsp_loaded; /* R: bit flags indicating the loaded DSPs */ + unsigned int chip_ready; /* R: 1 = initialization finished */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +struct sndrv_hwdep_dsp_image { + unsigned int index; /* W: DSP index */ + unsigned char name[64]; /* W: ID (e.g. file name) */ + unsigned char *image; /* W: binary image */ + size_t length; /* W: size of image in bytes */ + unsigned long driver_data; /* W: driver-specific data */ +}; + +enum { + SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int), + SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct sndrv_hwdep_info), + SNDRV_HWDEP_IOCTL_DSP_STATUS = _IOR('H', 0x02, struct sndrv_hwdep_dsp_status), + SNDRV_HWDEP_IOCTL_DSP_LOAD = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image) +}; + +/***************************************************************************** + * * + * Digital Audio (PCM) interface - /dev/snd/pcm?? * + * * + *****************************************************************************/ + +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) + +typedef unsigned long sndrv_pcm_uframes_t; +typedef long sndrv_pcm_sframes_t; + +enum sndrv_pcm_class { + SNDRV_PCM_CLASS_GENERIC = 0, /* standard mono or stereo device */ + SNDRV_PCM_CLASS_MULTI, /* multichannel device */ + SNDRV_PCM_CLASS_MODEM, /* software modem class */ + SNDRV_PCM_CLASS_DIGITIZER, /* digitizer class */ + /* Don't forget to change the following: */ + SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, +}; + +enum sndrv_pcm_subclass { + SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, /* mono or stereo subdevices are mixed together */ + SNDRV_PCM_SUBCLASS_MULTI_MIX, /* multichannel subdevices are mixed together */ + /* Don't forget to change the following: */ + SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, +}; + +enum sndrv_pcm_stream { + SNDRV_PCM_STREAM_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +enum sndrv_pcm_access { + SNDRV_PCM_ACCESS_MMAP_INTERLEAVED = 0, /* interleaved mmap */ + SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED, /* noninterleaved mmap */ + SNDRV_PCM_ACCESS_MMAP_COMPLEX, /* complex mmap */ + SNDRV_PCM_ACCESS_RW_INTERLEAVED, /* readi/writei */ + SNDRV_PCM_ACCESS_RW_NONINTERLEAVED, /* readn/writen */ + SNDRV_PCM_ACCESS_LAST = SNDRV_PCM_ACCESS_RW_NONINTERLEAVED, +}; + +enum sndrv_pcm_format { + SNDRV_PCM_FORMAT_S8 = 0, + SNDRV_PCM_FORMAT_U8, + SNDRV_PCM_FORMAT_S16_LE, + SNDRV_PCM_FORMAT_S16_BE, + SNDRV_PCM_FORMAT_U16_LE, + SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24_LE, /* low three bytes */ + SNDRV_PCM_FORMAT_S24_BE, /* low three bytes */ + SNDRV_PCM_FORMAT_U24_LE, /* low three bytes */ + SNDRV_PCM_FORMAT_U24_BE, /* low three bytes */ + SNDRV_PCM_FORMAT_S32_LE, + SNDRV_PCM_FORMAT_S32_BE, + SNDRV_PCM_FORMAT_U32_LE, + SNDRV_PCM_FORMAT_U32_BE, + SNDRV_PCM_FORMAT_FLOAT_LE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT_BE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT64_LE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT64_BE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, /* IEC-958 subframe, Little Endian */ + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, /* IEC-958 subframe, Big Endian */ + SNDRV_PCM_FORMAT_MU_LAW, + SNDRV_PCM_FORMAT_A_LAW, + SNDRV_PCM_FORMAT_IMA_ADPCM, + SNDRV_PCM_FORMAT_MPEG, + SNDRV_PCM_FORMAT_GSM, + SNDRV_PCM_FORMAT_SPECIAL = 31, + SNDRV_PCM_FORMAT_S24_3LE = 32, /* in three bytes */ + SNDRV_PCM_FORMAT_S24_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U24_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U24_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_S20_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_S20_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U20_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U20_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_S18_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_S18_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U18_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U18_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_LAST = SNDRV_PCM_FORMAT_U18_3BE, + +#ifdef SNDRV_LITTLE_ENDIAN + SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_LE, + SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_LE, + SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_LE, + SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_LE, + SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_LE, + SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_LE, + SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_LE, + SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_LE, + SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, +#endif +#ifdef SNDRV_BIG_ENDIAN + SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_BE, + SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_BE, + SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_BE, + SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_BE, + SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_BE, + SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_BE, + SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_BE, + SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, +#endif +}; + +enum sndrv_pcm_subformat { + SNDRV_PCM_SUBFORMAT_STD = 0, + SNDRV_PCM_SUBFORMAT_LAST = SNDRV_PCM_SUBFORMAT_STD, +}; + +#define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ +#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ +#define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ +#define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ +#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ +#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ +#define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ +#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000 /* hardware transfer block of samples */ +#define SNDRV_PCM_INFO_OVERRANGE 0x00020000 /* hardware supports ADC (capture) overrange detection */ +#define SNDRV_PCM_INFO_RESUME 0x00040000 /* hardware supports stream resume after suspend */ +#define SNDRV_PCM_INFO_PAUSE 0x00080000 /* pause ioctl is supported */ +#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ +#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ +#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ +#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ + +enum sndrv_pcm_state { + SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ + SNDRV_PCM_STATE_SETUP, /* stream has a setup */ + SNDRV_PCM_STATE_PREPARED, /* stream is ready to start */ + SNDRV_PCM_STATE_RUNNING, /* stream is running */ + SNDRV_PCM_STATE_XRUN, /* stream reached an xrun */ + SNDRV_PCM_STATE_DRAINING, /* stream is draining */ + SNDRV_PCM_STATE_PAUSED, /* stream is paused */ + SNDRV_PCM_STATE_SUSPENDED, /* hardware is suspended */ + SNDRV_PCM_STATE_DISCONNECTED, /* hardware is disconnected */ + SNDRV_PCM_STATE_LAST = SNDRV_PCM_STATE_DISCONNECTED, +}; + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, +}; + +union sndrv_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct sndrv_pcm_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* RO/WR (control): stream number */ + int card; /* R: card number */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* name of this device */ + unsigned char subname[32]; /* subdevice name */ + int dev_class; /* SNDRV_PCM_CLASS_* */ + int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ + unsigned int subdevices_count; + unsigned int subdevices_avail; + union sndrv_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char reserved[64]; /* reserved for future... */ +}; + +enum sndrv_pcm_hw_param { + SNDRV_PCM_HW_PARAM_ACCESS = 0, /* Access type */ + SNDRV_PCM_HW_PARAM_FIRST_MASK = SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_HW_PARAM_FORMAT, /* Format */ + SNDRV_PCM_HW_PARAM_SUBFORMAT, /* Subformat */ + SNDRV_PCM_HW_PARAM_LAST_MASK = SNDRV_PCM_HW_PARAM_SUBFORMAT, + + SNDRV_PCM_HW_PARAM_SAMPLE_BITS = 8, /* Bits per sample */ + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL = SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + SNDRV_PCM_HW_PARAM_FRAME_BITS, /* Bits per frame */ + SNDRV_PCM_HW_PARAM_CHANNELS, /* Channels */ + SNDRV_PCM_HW_PARAM_RATE, /* Approx rate */ + SNDRV_PCM_HW_PARAM_PERIOD_TIME, /* Approx distance between interrupts + in us */ + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, /* Approx frames between interrupts */ + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, /* Approx bytes between interrupts */ + SNDRV_PCM_HW_PARAM_PERIODS, /* Approx interrupts per buffer */ + SNDRV_PCM_HW_PARAM_BUFFER_TIME, /* Approx duration of buffer in us */ + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, /* Size of buffer in frames */ + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, /* Size of buffer in bytes */ + SNDRV_PCM_HW_PARAM_TICK_TIME, /* Approx tick duration in us */ + SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME +}; + +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ +#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ + +struct sndrv_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +#define SNDRV_MASK_MAX 256 + +struct sndrv_mask { + u_int32_t bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct sndrv_pcm_hw_params { + unsigned int flags; + struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct sndrv_mask mres[5]; /* reserved masks */ + struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct sndrv_interval ires[9]; /* reserved intervals */ + unsigned int rmask; /* W: requested masks */ + unsigned int cmask; /* R: changed masks */ + unsigned int info; /* R: Info flags for returned setup */ + unsigned int msbits; /* R: used most significant bits */ + unsigned int rate_num; /* R: rate numerator */ + unsigned int rate_den; /* R: rate denominator */ + sndrv_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ + unsigned char reserved[64]; /* reserved for future */ +}; + +enum sndrv_pcm_tstamp { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_ENABLE, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, +}; + +struct sndrv_pcm_sw_params { + int tstamp_mode; /* timestamp mode */ + unsigned int period_step; + unsigned int sleep_min; /* min ticks to sleep */ + sndrv_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + sndrv_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */ + sndrv_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ + sndrv_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */ + sndrv_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */ + sndrv_pcm_uframes_t silence_size; /* silence block size */ + sndrv_pcm_uframes_t boundary; /* pointers wrap point */ + unsigned char reserved[60]; /* reserved for future */ + unsigned int period_event; /* for alsa-lib implementation */ +}; + +struct sndrv_pcm_channel_info { + unsigned int channel; + long offset; /* mmap offset */ + unsigned int first; /* offset to first sample in bits */ + unsigned int step; /* samples distance in bits */ +}; + +struct sndrv_pcm_status { + int state; /* stream state */ + struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ + struct timespec tstamp; /* reference timestamp */ + sndrv_pcm_uframes_t appl_ptr; /* appl ptr */ + sndrv_pcm_uframes_t hw_ptr; /* hw ptr */ + sndrv_pcm_sframes_t delay; /* current delay in frames */ + sndrv_pcm_uframes_t avail; /* number of frames available */ + sndrv_pcm_uframes_t avail_max; /* max frames available on hw since last status */ + sndrv_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ + int suspended_state; /* suspended stream state */ + unsigned char reserved[60]; /* must be filled with zero */ +}; + +struct sndrv_pcm_mmap_status { + int state; /* RO: state - SNDRV_PCM_STATE_XXXX */ + int pad1; /* Needed for 64 bit alignment */ + sndrv_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ + struct timespec tstamp; /* Timestamp */ + int suspended_state; /* RO: suspended stream state */ +}; + +struct sndrv_pcm_mmap_control { + sndrv_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ + sndrv_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ +}; + +#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0) /* execute hwsync */ +#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */ +#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */ + +struct sndrv_pcm_sync_ptr { + unsigned int flags; + union { + struct sndrv_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct sndrv_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +struct sndrv_xferi { + sndrv_pcm_sframes_t result; + void *buf; + sndrv_pcm_uframes_t frames; +}; + +struct sndrv_xfern { + sndrv_pcm_sframes_t result; + void **bufs; + sndrv_pcm_uframes_t frames; +}; + + +enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, /* posix_clock_monotonic equivalent */ + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, +}; + +enum { + SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int), + SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct sndrv_pcm_info), + SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int), + SNDRV_PCM_IOCTL_TTSTAMP = _IOW('A', 0x03, int), + SNDRV_PCM_IOCTL_HW_REFINE = _IOWR('A', 0x10, struct sndrv_pcm_hw_params), + SNDRV_PCM_IOCTL_HW_PARAMS = _IOWR('A', 0x11, struct sndrv_pcm_hw_params), + SNDRV_PCM_IOCTL_HW_FREE = _IO('A', 0x12), + SNDRV_PCM_IOCTL_SW_PARAMS = _IOWR('A', 0x13, struct sndrv_pcm_sw_params), + SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct sndrv_pcm_status), + SNDRV_PCM_IOCTL_DELAY = _IOR('A', 0x21, sndrv_pcm_sframes_t), + SNDRV_PCM_IOCTL_HWSYNC = _IO('A', 0x22), + SNDRV_PCM_IOCTL_SYNC_PTR = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr), + SNDRV_PCM_IOCTL_CHANNEL_INFO = _IOR('A', 0x32, struct sndrv_pcm_channel_info), + SNDRV_PCM_IOCTL_PREPARE = _IO('A', 0x40), + SNDRV_PCM_IOCTL_RESET = _IO('A', 0x41), + SNDRV_PCM_IOCTL_START = _IO('A', 0x42), + SNDRV_PCM_IOCTL_DROP = _IO('A', 0x43), + SNDRV_PCM_IOCTL_DRAIN = _IO('A', 0x44), + SNDRV_PCM_IOCTL_PAUSE = _IOW('A', 0x45, int), + SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, sndrv_pcm_uframes_t), + SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47), + SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48), + SNDRV_PCM_IOCTL_FORWARD = _IOW('A', 0x49, sndrv_pcm_uframes_t), + SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct sndrv_xferi), + SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct sndrv_xferi), + SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct sndrv_xfern), + SNDRV_PCM_IOCTL_READN_FRAMES = _IOR('A', 0x53, struct sndrv_xfern), + SNDRV_PCM_IOCTL_LINK = _IOW('A', 0x60, int), + SNDRV_PCM_IOCTL_UNLINK = _IO('A', 0x61), +}; + +/* Trick to make alsa-lib/acinclude.m4 happy */ +#define SNDRV_PCM_IOCTL_REWIND SNDRV_PCM_IOCTL_REWIND + +/***************************************************************************** + * * + * MIDI v1.0 interface * + * * + *****************************************************************************/ + +/* + * Raw MIDI section - /dev/snd/midi?? + */ + +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) + +enum sndrv_rawmidi_stream { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 +#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 +#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 + +struct sndrv_rawmidi_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* WR: stream */ + int card; /* R: card number */ + unsigned int flags; /* SNDRV_RAWMIDI_INFO_XXXX */ + unsigned char id[64]; /* ID (user selectable) */ + unsigned char name[80]; /* name of device */ + unsigned char subname[32]; /* name of active or selected subdevice */ + unsigned int subdevices_count; + unsigned int subdevices_avail; + unsigned char reserved[64]; /* reserved for future use */ +}; + +struct sndrv_rawmidi_params { + int stream; + size_t buffer_size; /* queue size in bytes */ + size_t avail_min; /* minimum avail bytes for wakeup */ + unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +struct sndrv_rawmidi_status { + int stream; + struct timespec tstamp; /* Timestamp */ + size_t avail; /* available bytes */ + size_t xruns; /* count of overruns since last status (in bytes) */ + unsigned char reserved[16]; /* reserved for future use */ +}; + +enum { + SNDRV_RAWMIDI_IOCTL_PVERSION = _IOR('W', 0x00, int), + SNDRV_RAWMIDI_IOCTL_INFO = _IOR('W', 0x01, struct sndrv_rawmidi_info), + SNDRV_RAWMIDI_IOCTL_PARAMS = _IOWR('W', 0x10, struct sndrv_rawmidi_params), + SNDRV_RAWMIDI_IOCTL_STATUS = _IOWR('W', 0x20, struct sndrv_rawmidi_status), + SNDRV_RAWMIDI_IOCTL_DROP = _IOW('W', 0x30, int), + SNDRV_RAWMIDI_IOCTL_DRAIN = _IOW('W', 0x31, int), +}; + +/* + * Timer section - /dev/snd/timer + */ + +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 5) + +enum sndrv_timer_class { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +/* slave timer classes */ +enum sndrv_timer_slave_class { + SNDRV_TIMER_SCLASS_NONE = 0, + SNDRV_TIMER_SCLASS_APPLICATION, + SNDRV_TIMER_SCLASS_SEQUENCER, /* alias */ + SNDRV_TIMER_SCLASS_OSS_SEQUENCER, /* alias */ + SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, +}; + +/* global timers (device member) */ +#define SNDRV_TIMER_GLOBAL_SYSTEM 0 +#define SNDRV_TIMER_GLOBAL_RTC 1 +#define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 + +/* info flags */ +#define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ + +struct sndrv_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct sndrv_timer_ginfo { + struct sndrv_timer_id tid; /* requested timer ID */ + unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ + int card; /* card number */ + unsigned char id[64]; /* timer identification */ + unsigned char name[80]; /* timer name */ + unsigned long reserved0; /* reserved for future use */ + unsigned long resolution; /* average period resolution in ns */ + unsigned long resolution_min; /* minimal period resolution in ns */ + unsigned long resolution_max; /* maximal period resolution in ns */ + unsigned int clients; /* active timer clients */ + unsigned char reserved[32]; +}; + +struct sndrv_timer_gparams { + struct sndrv_timer_id tid; /* requested timer ID */ + unsigned long period_num; /* requested precise period duration (in seconds) - numerator */ + unsigned long period_den; /* requested precise period duration (in seconds) - denominator */ + unsigned char reserved[32]; +}; + +struct sndrv_timer_gstatus { + struct sndrv_timer_id tid; /* requested timer ID */ + unsigned long resolution; /* current period resolution in ns */ + unsigned long resolution_num; /* precise current period resolution (in seconds) - numerator */ + unsigned long resolution_den; /* precise current period resolution (in seconds) - denominator */ + unsigned char reserved[32]; +}; + +struct sndrv_timer_select { + struct sndrv_timer_id id; /* bind to timer ID */ + unsigned char reserved[32]; /* reserved */ +}; + +struct sndrv_timer_info { + unsigned int flags; /* timer flags - SNDRV_TIMER_FLG_* */ + int card; /* card number */ + unsigned char id[64]; /* timer identificator */ + unsigned char name[80]; /* timer name */ + unsigned long reserved0; /* reserved for future use */ + unsigned long resolution; /* average period resolution in ns */ + unsigned char reserved[64]; /* reserved */ +}; + +#define SNDRV_TIMER_PSFLG_AUTO (1<<0) /* auto start, otherwise one-shot */ +#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1) /* exclusive use, precise start/stop/pause/continue */ +#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) /* write early event to the poll queue */ + +struct sndrv_timer_params { + unsigned int flags; /* flags - SNDRV_MIXER_PSFLG_* */ + unsigned int ticks; /* requested resolution in ticks */ + unsigned int queue_size; /* total size of queue (32-1024) */ + unsigned int reserved0; /* reserved, was: failure locations */ + unsigned int filter; /* event filter (bitmask of SNDRV_TIMER_EVENT_*) */ + unsigned char reserved[60]; /* reserved */ +}; + +struct sndrv_timer_status { + struct timespec tstamp; /* Timestamp - last update */ + unsigned int resolution; /* current period resolution in ns */ + unsigned int lost; /* counter of master tick lost */ + unsigned int overrun; /* count of read queue overruns */ + unsigned int queue; /* used queue size */ + unsigned char reserved[64]; /* reserved */ +}; + +enum { + SNDRV_TIMER_IOCTL_PVERSION = _IOR('T', 0x00, int), + SNDRV_TIMER_IOCTL_NEXT_DEVICE = _IOWR('T', 0x01, struct sndrv_timer_id), + SNDRV_TIMER_IOCTL_TREAD = _IOW('T', 0x02, int), + SNDRV_TIMER_IOCTL_GINFO = _IOWR('T', 0x03, struct sndrv_timer_ginfo), + SNDRV_TIMER_IOCTL_GPARAMS = _IOW('T', 0x04, struct sndrv_timer_gparams), + SNDRV_TIMER_IOCTL_GSTATUS = _IOWR('T', 0x05, struct sndrv_timer_gstatus), + SNDRV_TIMER_IOCTL_SELECT = _IOW('T', 0x10, struct sndrv_timer_select), + SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct sndrv_timer_info), + SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct sndrv_timer_params), + SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct sndrv_timer_status), + /* The following four ioctls are changed since 1.0.9 due to confliction */ + SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0), + SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1), + SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2), + SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3), +}; + +struct sndrv_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum sndrv_timer_event { + SNDRV_TIMER_EVENT_RESOLUTION = 0, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_TICK, /* val = ticks */ + SNDRV_TIMER_EVENT_START, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_STOP, /* val = 0 */ + SNDRV_TIMER_EVENT_CONTINUE, /* val = resolution in ns */ + SNDRV_TIMER_EVENT_PAUSE, /* val = 0 */ + SNDRV_TIMER_EVENT_EARLY, /* val = 0, early event */ + SNDRV_TIMER_EVENT_SUSPEND, /* val = 0 */ + SNDRV_TIMER_EVENT_RESUME, /* val = resolution in ns */ + /* master timer events for slave timer instances */ + SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, + SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, + SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, + SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, + SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, + SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, +}; + +struct sndrv_timer_tread { + int event; + struct timespec tstamp; + unsigned int val; +}; + +/**************************************************************************** + * * + * Section for driver control interface - /dev/snd/control? * + * * + ****************************************************************************/ + +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +struct sndrv_ctl_card_info { + int card; /* card number */ + int pad; /* reserved for future (was type) */ + unsigned char id[16]; /* ID of card (user selectable) */ + unsigned char driver[16]; /* Driver name */ + unsigned char name[32]; /* Short name of soundcard */ + unsigned char longname[80]; /* name + info text about soundcard */ + unsigned char reserved_[16]; /* reserved for future (was ID of mixer) */ + unsigned char mixername[80]; /* visual mixer identification */ + unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */ +}; + +enum sndrv_ctl_elem_type { + SNDRV_CTL_ELEM_TYPE_NONE = 0, /* invalid */ + SNDRV_CTL_ELEM_TYPE_BOOLEAN, /* boolean type */ + SNDRV_CTL_ELEM_TYPE_INTEGER, /* integer type */ + SNDRV_CTL_ELEM_TYPE_ENUMERATED, /* enumerated type */ + SNDRV_CTL_ELEM_TYPE_BYTES, /* byte array */ + SNDRV_CTL_ELEM_TYPE_IEC958, /* IEC958 (S/PDIF) setup */ + SNDRV_CTL_ELEM_TYPE_INTEGER64, /* 64-bit integer type */ + SNDRV_CTL_ELEM_TYPE_LAST = SNDRV_CTL_ELEM_TYPE_INTEGER64, +}; + +enum sndrv_ctl_elem_iface { + SNDRV_CTL_ELEM_IFACE_CARD = 0, /* global control */ + SNDRV_CTL_ELEM_IFACE_HWDEP, /* hardware dependent device */ + SNDRV_CTL_ELEM_IFACE_MIXER, /* virtual mixer device */ + SNDRV_CTL_ELEM_IFACE_PCM, /* PCM device */ + SNDRV_CTL_ELEM_IFACE_RAWMIDI, /* RawMidi device */ + SNDRV_CTL_ELEM_IFACE_TIMER, /* timer device */ + SNDRV_CTL_ELEM_IFACE_SEQUENCER, /* sequencer client */ + SNDRV_CTL_ELEM_IFACE_LAST = SNDRV_CTL_ELEM_IFACE_SEQUENCER, +}; + +#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) +#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) +#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */ +#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is supported */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is supported */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */ +#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ +#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ +#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* flag only for kernel */ +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ +/* bits 30 and 31 are obsoleted (for indirect access) */ + +/* for further details see the ACPI and PCI power management specification */ +#define SNDRV_CTL_POWER_D0 0x0000 /* full On */ +#define SNDRV_CTL_POWER_D1 0x0100 /* partial On */ +#define SNDRV_CTL_POWER_D2 0x0200 /* partial On */ +#define SNDRV_CTL_POWER_D3 0x0300 /* Off */ +#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) /* Off, with power */ +#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) /* Off, without power */ + +struct sndrv_ctl_elem_id { + unsigned int numid; /* numeric identifier, zero = invalid */ + int iface; /* interface identifier */ + unsigned int device; /* device/client number */ + unsigned int subdevice; /* subdevice (substream) number */ + unsigned char name[44]; /* ASCII name of item */ + unsigned int index; /* index of item */ +}; + +struct sndrv_ctl_elem_list { + unsigned int offset; /* W: first element ID to get */ + unsigned int space; /* W: count of element IDs to get */ + unsigned int used; /* R: count of element IDs set */ + unsigned int count; /* R: count of all elements */ + struct sndrv_ctl_elem_id *pids; /* R: IDs */ + unsigned char reserved[50]; +}; + +struct sndrv_ctl_elem_info { + struct sndrv_ctl_elem_id id; /* W: element ID */ + int type; /* R: value type - SNDRV_CTL_ELEM_TYPE_* */ + unsigned int access; /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */ + unsigned int count; /* count of values */ + pid_t owner; /* owner's PID of this control */ + union { + struct { + long min; /* R: minimum value */ + long max; /* R: maximum value */ + long step; /* R: step (0 variable) */ + } integer; + struct { + long long min; /* R: minimum value */ + long long max; /* R: maximum value */ + long long step; /* R: step (0 variable) */ + } integer64; + struct { + unsigned int items; /* R: number of items */ + unsigned int item; /* W: item number */ + char name[64]; /* R: value name */ + } enumerated; + unsigned char reserved[128]; + } value; + union { + unsigned short d[4]; /* dimensions */ + unsigned short *d_ptr; /* (obsolete) indirect */ + } dimen; + unsigned char reserved[64-4*sizeof(unsigned short)]; +}; + +struct sndrv_ctl_elem_value { + struct sndrv_ctl_elem_id id; /* W: element ID */ + unsigned int indirect: 1; /* (obsolete) W: use indirect pointer (xxx_ptr member) */ + union { + union { + long value[128]; + long *value_ptr; /* obsolete */ + } integer; + union { + long long value[64]; + long long *value_ptr; /* obsolete */ + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; /* obsolete */ + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; /* obsolete */ + } bytes; + struct sndrv_aes_iec958 iec958; + } value; /* RO */ + struct timespec tstamp; + unsigned char reserved[128-sizeof(struct timespec)]; +}; + +struct sndrv_ctl_tlv { + unsigned int numid; /* control element numeric identification */ + unsigned int length; /* in bytes aligned to 4 */ + unsigned int tlv[0]; /* first TLV */ +}; + +enum { + SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int), + SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct sndrv_ctl_card_info), + SNDRV_CTL_IOCTL_ELEM_LIST = _IOWR('U', 0x10, struct sndrv_ctl_elem_list), + SNDRV_CTL_IOCTL_ELEM_INFO = _IOWR('U', 0x11, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_READ = _IOWR('U', 0x12, struct sndrv_ctl_elem_value), + SNDRV_CTL_IOCTL_ELEM_WRITE = _IOWR('U', 0x13, struct sndrv_ctl_elem_value), + SNDRV_CTL_IOCTL_ELEM_LOCK = _IOW('U', 0x14, struct sndrv_ctl_elem_id), + SNDRV_CTL_IOCTL_ELEM_UNLOCK = _IOW('U', 0x15, struct sndrv_ctl_elem_id), + SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS = _IOWR('U', 0x16, int), + SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct sndrv_ctl_elem_id), + SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct sndrv_ctl_tlv), + SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct sndrv_ctl_tlv), + SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct sndrv_ctl_tlv), + SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int), + SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct sndrv_hwdep_info), + SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int), + SNDRV_CTL_IOCTL_PCM_INFO = _IOWR('U', 0x31, struct sndrv_pcm_info), + SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE = _IOW('U', 0x32, int), + SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE = _IOWR('U', 0x40, int), + SNDRV_CTL_IOCTL_RAWMIDI_INFO = _IOWR('U', 0x41, struct sndrv_rawmidi_info), + SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE = _IOW('U', 0x42, int), + SNDRV_CTL_IOCTL_POWER = _IOWR('U', 0xd0, int), + SNDRV_CTL_IOCTL_POWER_STATE = _IOR('U', 0xd1, int), +}; + +/* + * Read interface. + */ + +enum sndrv_ctl_event_type { + SNDRV_CTL_EVENT_ELEM = 0, + SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, +}; + +#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */ +#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */ +#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */ +#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */ + +struct sndrv_ctl_event { + int type; /* event type - SNDRV_CTL_EVENT_* */ + union { + struct { + unsigned int mask; + struct sndrv_ctl_elem_id id; + } elem; + unsigned char data8[60]; + } data; +}; + +/* + * Control names + */ + +#define SNDRV_CTL_NAME_NONE "" +#define SNDRV_CTL_NAME_PLAYBACK "Playback " +#define SNDRV_CTL_NAME_CAPTURE "Capture " + +#define SNDRV_CTL_NAME_IEC958_NONE "" +#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch" +#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume" +#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default" +#define SNDRV_CTL_NAME_IEC958_MASK "Mask" +#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask" +#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask" +#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" +#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what + +/* + * + */ + +struct sndrv_xferv { + const struct iovec *vector; + unsigned long count; +}; + +enum { + SNDRV_IOCTL_READV = _IOW('K', 0x00, struct sndrv_xferv), + SNDRV_IOCTL_WRITEV = _IOW('K', 0x01, struct sndrv_xferv), +}; + +#endif /* __SOUND_ASOUND_H */ diff --git a/include/sound/asound_fm.h b/include/sound/asound_fm.h new file mode 100644 index 0000000..c2a4b96 --- /dev/null +++ b/include/sound/asound_fm.h @@ -0,0 +1,134 @@ +#ifndef __SOUND_ASOUND_FM_H +#define __SOUND_ASOUND_FM_H + +/* + * Advanced Linux Sound Architecture - ALSA + * + * Interface file between ALSA driver & user space + * Copyright (c) 1994-98 by Jaroslav Kysela , + * 4Front Technologies + * + * Direct FM control + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define SNDRV_DM_FM_MODE_OPL2 0x00 +#define SNDRV_DM_FM_MODE_OPL3 0x01 + +struct snd_dm_fm_info { + unsigned char fm_mode; /* OPL mode, see SNDRV_DM_FM_MODE_XXX */ + unsigned char rhythm; /* percussion mode flag */ +}; + +/* + * Data structure composing an FM "note" or sound event. + */ + +struct snd_dm_fm_voice { + unsigned char op; /* operator cell (0 or 1) */ + unsigned char voice; /* FM voice (0 to 17) */ + + unsigned char am; /* amplitude modulation */ + unsigned char vibrato; /* vibrato effect */ + unsigned char do_sustain; /* sustain phase */ + unsigned char kbd_scale; /* keyboard scaling */ + unsigned char harmonic; /* 4 bits: harmonic and multiplier */ + unsigned char scale_level; /* 2 bits: decrease output freq rises */ + unsigned char volume; /* 6 bits: volume */ + + unsigned char attack; /* 4 bits: attack rate */ + unsigned char decay; /* 4 bits: decay rate */ + unsigned char sustain; /* 4 bits: sustain level */ + unsigned char release; /* 4 bits: release rate */ + + unsigned char feedback; /* 3 bits: feedback for op0 */ + unsigned char connection; /* 0 for serial, 1 for parallel */ + unsigned char left; /* stereo left */ + unsigned char right; /* stereo right */ + unsigned char waveform; /* 3 bits: waveform shape */ +}; + +/* + * This describes an FM note by its voice, octave, frequency number (10bit) + * and key on/off. + */ + +struct snd_dm_fm_note { + unsigned char voice; /* 0-17 voice channel */ + unsigned char octave; /* 3 bits: what octave to play */ + unsigned int fnum; /* 10 bits: frequency number */ + unsigned char key_on; /* set for active, clear for silent */ +}; + +/* + * FM parameters that apply globally to all voices, and thus are not "notes" + */ + +struct snd_dm_fm_params { + unsigned char am_depth; /* amplitude modulation depth (1=hi) */ + unsigned char vib_depth; /* vibrato depth (1=hi) */ + unsigned char kbd_split; /* keyboard split */ + unsigned char rhythm; /* percussion mode select */ + + /* This block is the percussion instrument data */ + unsigned char bass; + unsigned char snare; + unsigned char tomtom; + unsigned char cymbal; + unsigned char hihat; +}; + +/* + * FM mode ioctl settings + */ + +#define SNDRV_DM_FM_IOCTL_INFO _IOR('H', 0x20, struct snd_dm_fm_info) +#define SNDRV_DM_FM_IOCTL_RESET _IO ('H', 0x21) +#define SNDRV_DM_FM_IOCTL_PLAY_NOTE _IOW('H', 0x22, struct snd_dm_fm_note) +#define SNDRV_DM_FM_IOCTL_SET_VOICE _IOW('H', 0x23, struct snd_dm_fm_voice) +#define SNDRV_DM_FM_IOCTL_SET_PARAMS _IOW('H', 0x24, struct snd_dm_fm_params) +#define SNDRV_DM_FM_IOCTL_SET_MODE _IOW('H', 0x25, int) +/* for OPL3 only */ +#define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int) +/* SBI patch management */ +#define SNDRV_DM_FM_IOCTL_CLEAR_PATCHES _IO ('H', 0x40) + +#define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 +#define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 +#define SNDRV_DM_FM_OSS_IOCTL_SET_VOICE 0x22 +#define SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS 0x23 +#define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 +#define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 + +/* + * Patch Record - fixed size for write + */ + +#define FM_KEY_SBI "SBI\032" +#define FM_KEY_2OP "2OP\032" +#define FM_KEY_4OP "4OP\032" + +struct sbi_patch { + unsigned char prog; + unsigned char bank; + char key[4]; + char name[25]; + char extension[7]; + unsigned char data[32]; +}; + +#endif /* __SOUND_ASOUND_FM_H */ diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h new file mode 100644 index 0000000..f962c5a --- /dev/null +++ b/include/sound/asoundef.h @@ -0,0 +1,227 @@ +#ifndef __SOUND_ASOUNDEF_H +#define __SOUND_ASOUNDEF_H + +/* + * Advanced Linux Sound Architecture - ALSA - Driver + * Copyright (c) 1994-2000 by Jaroslav Kysela + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/**************************************************************************** + * * + * Digital audio interface * + * * + ****************************************************************************/ + +/* AES/IEC958 channel status bits */ +#define IEC958_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */ +#define IEC958_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */ +#define IEC958_AES0_PRO_EMPHASIS (7<<2) /* mask - emphasis */ +#define IEC958_AES0_PRO_EMPHASIS_NOTID (0<<2) /* emphasis not indicated */ +#define IEC958_AES0_PRO_EMPHASIS_NONE (1<<2) /* none emphasis */ +#define IEC958_AES0_PRO_EMPHASIS_5015 (3<<2) /* 50/15us emphasis */ +#define IEC958_AES0_PRO_EMPHASIS_CCITT (7<<2) /* CCITT J.17 emphasis */ +#define IEC958_AES0_PRO_FREQ_UNLOCKED (1<<5) /* source sample frequency: 0 = locked, 1 = unlocked */ +#define IEC958_AES0_PRO_FS (3<<6) /* mask - sample frequency */ +#define IEC958_AES0_PRO_FS_NOTID (0<<6) /* fs not indicated */ +#define IEC958_AES0_PRO_FS_44100 (1<<6) /* 44.1kHz */ +#define IEC958_AES0_PRO_FS_48000 (2<<6) /* 48kHz */ +#define IEC958_AES0_PRO_FS_32000 (3<<6) /* 32kHz */ +#define IEC958_AES0_CON_NOT_COPYRIGHT (1<<2) /* 0 = copyright, 1 = not copyright */ +#define IEC958_AES0_CON_EMPHASIS (7<<3) /* mask - emphasis */ +#define IEC958_AES0_CON_EMPHASIS_NONE (0<<3) /* none emphasis */ +#define IEC958_AES0_CON_EMPHASIS_5015 (1<<3) /* 50/15us emphasis */ +#define IEC958_AES0_CON_MODE (3<<6) /* mask - mode */ +#define IEC958_AES1_PRO_MODE (15<<0) /* mask - channel mode */ +#define IEC958_AES1_PRO_MODE_NOTID (0<<0) /* not indicated */ +#define IEC958_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */ +#define IEC958_AES1_PRO_MODE_SINGLE (4<<0) /* single channel */ +#define IEC958_AES1_PRO_MODE_TWO (8<<0) /* two channels */ +#define IEC958_AES1_PRO_MODE_PRIMARY (12<<0) /* primary/secondary */ +#define IEC958_AES1_PRO_MODE_BYTE3 (15<<0) /* vector to byte 3 */ +#define IEC958_AES1_PRO_USERBITS (15<<4) /* mask - user bits */ +#define IEC958_AES1_PRO_USERBITS_NOTID (0<<4) /* not indicated */ +#define IEC958_AES1_PRO_USERBITS_192 (8<<4) /* 192-bit structure */ +#define IEC958_AES1_PRO_USERBITS_UDEF (12<<4) /* user defined application */ +#define IEC958_AES1_CON_CATEGORY 0x7f +#define IEC958_AES1_CON_GENERAL 0x00 +#define IEC958_AES1_CON_EXPERIMENTAL 0x40 +#define IEC958_AES1_CON_SOLIDMEM_MASK 0x0f +#define IEC958_AES1_CON_SOLIDMEM_ID 0x08 +#define IEC958_AES1_CON_BROADCAST1_MASK 0x07 +#define IEC958_AES1_CON_BROADCAST1_ID 0x04 +#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07 +#define IEC958_AES1_CON_DIGDIGCONV_ID 0x02 +#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f +#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x06 +#define IEC958_AES1_CON_ADC_MASK 0x1f +#define IEC958_AES1_CON_ADC_ID 0x16 +#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f +#define IEC958_AES1_CON_BROADCAST2_ID 0x0e +#define IEC958_AES1_CON_LASEROPT_MASK 0x07 +#define IEC958_AES1_CON_LASEROPT_ID 0x01 +#define IEC958_AES1_CON_MUSICAL_MASK 0x07 +#define IEC958_AES1_CON_MUSICAL_ID 0x05 +#define IEC958_AES1_CON_MAGNETIC_MASK 0x07 +#define IEC958_AES1_CON_MAGNETIC_ID 0x03 +#define IEC958_AES1_CON_IEC908_CD (IEC958_AES1_CON_LASEROPT_ID|0x00) +#define IEC958_AES1_CON_NON_IEC908_CD (IEC958_AES1_CON_LASEROPT_ID|0x08) +#define IEC958_AES1_CON_PCM_CODER (IEC958_AES1_CON_DIGDIGCONV_ID|0x00) +#define IEC958_AES1_CON_SAMPLER (IEC958_AES1_CON_DIGDIGCONV_ID|0x20) +#define IEC958_AES1_CON_MIXER (IEC958_AES1_CON_DIGDIGCONV_ID|0x10) +#define IEC958_AES1_CON_RATE_CONVERTER (IEC958_AES1_CON_DIGDIGCONV_ID|0x18) +#define IEC958_AES1_CON_SYNTHESIZER (IEC958_AES1_CON_MUSICAL_ID|0x00) +#define IEC958_AES1_CON_MICROPHONE (IEC958_AES1_CON_MUSICAL_ID|0x08) +#define IEC958_AES1_CON_DAT (IEC958_AES1_CON_MAGNETIC_ID|0x00) +#define IEC958_AES1_CON_VCR (IEC958_AES1_CON_MAGNETIC_ID|0x08) +#define IEC958_AES1_CON_ORIGINAL (1<<7) /* this bits depends on the category code */ +#define IEC958_AES2_PRO_SBITS (7<<0) /* mask - sample bits */ +#define IEC958_AES2_PRO_SBITS_20 (2<<0) /* 20-bit - coordination */ +#define IEC958_AES2_PRO_SBITS_24 (4<<0) /* 24-bit - main audio */ +#define IEC958_AES2_PRO_SBITS_UDEF (6<<0) /* user defined application */ +#define IEC958_AES2_PRO_WORDLEN (7<<3) /* mask - source word length */ +#define IEC958_AES2_PRO_WORDLEN_NOTID (0<<3) /* not indicated */ +#define IEC958_AES2_PRO_WORDLEN_22_18 (2<<3) /* 22-bit or 18-bit */ +#define IEC958_AES2_PRO_WORDLEN_23_19 (4<<3) /* 23-bit or 19-bit */ +#define IEC958_AES2_PRO_WORDLEN_24_20 (5<<3) /* 24-bit or 20-bit */ +#define IEC958_AES2_PRO_WORDLEN_20_16 (6<<3) /* 20-bit or 16-bit */ +#define IEC958_AES2_CON_SOURCE (15<<0) /* mask - source number */ +#define IEC958_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */ +#define IEC958_AES2_CON_CHANNEL (15<<4) /* mask - channel number */ +#define IEC958_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */ +#define IEC958_AES3_CON_FS (15<<0) /* mask - sample frequency */ +#define IEC958_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */ +#define IEC958_AES3_CON_FS_48000 (2<<0) /* 48kHz */ +#define IEC958_AES3_CON_FS_32000 (3<<0) /* 32kHz */ +#define IEC958_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */ +#define IEC958_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */ +#define IEC958_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */ +#define IEC958_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */ + +/***************************************************************************** + * * + * MIDI v1.0 interface * + * * + *****************************************************************************/ + +#define MIDI_CHANNELS 16 +#define MIDI_GM_DRUM_CHANNEL (10-1) + +/* + * MIDI commands + */ + +#define MIDI_CMD_NOTE_OFF 0x80 +#define MIDI_CMD_NOTE_ON 0x90 +#define MIDI_CMD_NOTE_PRESSURE 0xa0 +#define MIDI_CMD_CONTROL 0xb0 +#define MIDI_CMD_PGM_CHANGE 0xc0 +#define MIDI_CMD_CHANNEL_PRESSURE 0xd0 +#define MIDI_CMD_BENDER 0xe0 + +#define MIDI_CMD_COMMON_SYSEX 0xf0 +#define MIDI_CMD_COMMON_MTC_QUARTER 0xf1 +#define MIDI_CMD_COMMON_SONG_POS 0xf2 +#define MIDI_CMD_COMMON_SONG_SELECT 0xf3 +#define MIDI_CMD_COMMON_TUNE_REQUEST 0xf6 +#define MIDI_CMD_COMMON_SYSEX_END 0xf7 +#define MIDI_CMD_COMMON_CLOCK 0xf8 +#define MIDI_CMD_COMMON_START 0xfa +#define MIDI_CMD_COMMON_CONTINUE 0xfb +#define MIDI_CMD_COMMON_STOP 0xfc +#define MIDI_CMD_COMMON_SENSING 0xfe +#define MIDI_CMD_COMMON_RESET 0xff + +/* + * MIDI controllers + */ + +#define MIDI_CTL_MSB_BANK 0x00 +#define MIDI_CTL_MSB_MODWHEEL 0x01 +#define MIDI_CTL_MSB_BREATH 0x02 +#define MIDI_CTL_MSB_FOOT 0x04 +#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 +#define MIDI_CTL_MSB_DATA_ENTRY 0x06 +#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 +#define MIDI_CTL_MSB_BALANCE 0x08 +#define MIDI_CTL_MSB_PAN 0x0a +#define MIDI_CTL_MSB_EXPRESSION 0x0b +#define MIDI_CTL_MSB_EFFECT1 0x0c +#define MIDI_CTL_MSB_EFFECT2 0x0d +#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 +#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 +#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 +#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 +#define MIDI_CTL_LSB_BANK 0x20 +#define MIDI_CTL_LSB_MODWHEEL 0x21 +#define MIDI_CTL_LSB_BREATH 0x22 +#define MIDI_CTL_LSB_FOOT 0x24 +#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 +#define MIDI_CTL_LSB_DATA_ENTRY 0x26 +#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 +#define MIDI_CTL_LSB_BALANCE 0x28 +#define MIDI_CTL_LSB_PAN 0x2a +#define MIDI_CTL_LSB_EXPRESSION 0x2b +#define MIDI_CTL_LSB_EFFECT1 0x2c +#define MIDI_CTL_LSB_EFFECT2 0x2d +#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 +#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 +#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 +#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 +#define MIDI_CTL_SUSTAIN 0x40 +#define MIDI_CTL_PORTAMENTO 0x41 +#define MIDI_CTL_SUSTENUTO 0x42 +#define MIDI_CTL_SOFT_PEDAL 0x43 +#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 +#define MIDI_CTL_HOLD2 0x45 +#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 +#define MIDI_CTL_SC2_TIMBRE 0x47 +#define MIDI_CTL_SC3_RELEASE_TIME 0x48 +#define MIDI_CTL_SC4_ATTACK_TIME 0x49 +#define MIDI_CTL_SC5_BRIGHTNESS 0x4a +#define MIDI_CTL_SC6 0x4b +#define MIDI_CTL_SC7 0x4c +#define MIDI_CTL_SC8 0x4d +#define MIDI_CTL_SC9 0x4e +#define MIDI_CTL_SC10 0x4f +#define MIDI_CTL_GENERAL_PURPOSE5 0x50 +#define MIDI_CTL_GENERAL_PURPOSE6 0x51 +#define MIDI_CTL_GENERAL_PURPOSE7 0x52 +#define MIDI_CTL_GENERAL_PURPOSE8 0x53 +#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 +#define MIDI_CTL_E1_REVERB_DEPTH 0x5b +#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5c +#define MIDI_CTL_E3_CHORUS_DEPTH 0x5d +#define MIDI_CTL_E4_DETUNE_DEPTH 0x5e +#define MIDI_CTL_E5_PHASER_DEPTH 0x5f +#define MIDI_CTL_DATA_INCREMENT 0x60 +#define MIDI_CTL_DATA_DECREMENT 0x61 +#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 +#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 +#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 +#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 +#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 +#define MIDI_CTL_RESET_CONTROLLERS 0x79 +#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7a +#define MIDI_CTL_ALL_NOTES_OFF 0x7b +#define MIDI_CTL_OMNI_OFF 0x7c +#define MIDI_CTL_OMNI_ON 0x7d +#define MIDI_CTL_MONO1 0x7e +#define MIDI_CTL_MONO2 0x7f + +#endif /* __SOUND_ASOUNDEF_H */ diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h new file mode 100644 index 0000000..94018b7 --- /dev/null +++ b/include/sound/emu10k1.h @@ -0,0 +1,349 @@ +#ifndef __SOUND_EMU10K1_H +#define __SOUND_EMU10K1_H + +/* + * Copyright (c) by Jaroslav Kysela , + * Creative Labs, Inc. + * Definitions for EMU10K1 (SB Live!) chips + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +/* + * ---- FX8010 ---- + */ + +#define EMU10K1_CARD_CREATIVE 0x00000000 +#define EMU10K1_CARD_EMUAPS 0x00000001 + +#define EMU10K1_FX8010_PCM_COUNT 8 + +/* instruction set */ +#define iMAC0 0x00 /* R = A + (X * Y >> 31) ; saturation */ +#define iMAC1 0x01 /* R = A + (-X * Y >> 31) ; saturation */ +#define iMAC2 0x02 /* R = A + (X * Y >> 31) ; wraparound */ +#define iMAC3 0x03 /* R = A + (-X * Y >> 31) ; wraparound */ +#define iMACINT0 0x04 /* R = A + X * Y ; saturation */ +#define iMACINT1 0x05 /* R = A + X * Y ; wraparound (31-bit) */ +#define iACC3 0x06 /* R = A + X + Y ; saturation */ +#define iMACMV 0x07 /* R = A, acc += X * Y >> 31 */ +#define iANDXOR 0x08 /* R = (A & X) ^ Y */ +#define iTSTNEG 0x09 /* R = (A >= Y) ? X : ~X */ +#define iLIMITGE 0x0a /* R = (A >= Y) ? X : Y */ +#define iLIMITLT 0x0b /* R = (A < Y) ? X : Y */ +#define iLOG 0x0c /* R = linear_data, A (log_data), X (max_exp), Y (format_word) */ +#define iEXP 0x0d /* R = log_data, A (linear_data), X (max_exp), Y (format_word) */ +#define iINTERP 0x0e /* R = A + (X * (Y - A) >> 31) ; saturation */ +#define iSKIP 0x0f /* R = A (cc_reg), X (count), Y (cc_test) */ + +/* GPRs */ +#define FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x0f */ +#define EXTIN(x) (0x10 + (x)) /* x = 0x00 - 0x0f */ +#define EXTOUT(x) (0x20 + (x)) /* x = 0x00 - 0x0f */ +#define C_00000000 0x40 +#define C_00000001 0x41 +#define C_00000002 0x42 +#define C_00000003 0x43 +#define C_00000004 0x44 +#define C_00000008 0x45 +#define C_00000010 0x46 +#define C_00000020 0x47 +#define C_00000100 0x48 +#define C_00010000 0x49 +#define C_00080000 0x4a +#define C_10000000 0x4b +#define C_20000000 0x4c +#define C_40000000 0x4d +#define C_80000000 0x4e +#define C_7fffffff 0x4f +#define C_ffffffff 0x50 +#define C_fffffffe 0x51 +#define C_c0000000 0x52 +#define C_4f1bbcdc 0x53 +#define C_5a7ef9db 0x54 +#define C_00100000 0x55 /* ?? */ +#define GPR_ACCU 0x56 /* ACCUM, accumulator */ +#define GPR_COND 0x57 /* CCR, condition register */ +#define GPR_NOISE0 0x58 /* noise source */ +#define GPR_NOISE1 0x59 /* noise source */ +#define GPR_IRQ 0x5a /* IRQ register */ +#define GPR_DBAC 0x5b /* TRAM Delay Base Address Counter */ +#define GPR(x) (FXGPREGBASE + (x)) /* free GPRs: x = 0x00 - 0xff */ +#define ITRAM_DATA(x) (TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ +#define ETRAM_DATA(x) (TANKMEMDATAREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ +#define ITRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ +#define ETRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ + +#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f? */ +#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x1f? */ +#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f? */ +#define A_GPR(x) (A_FXGPREGBASE + (x)) + +/* cc_reg constants */ +#define CC_REG_NORMALIZED C_00000001 +#define CC_REG_BORROW C_00000002 +#define CC_REG_MINUS C_00000004 +#define CC_REG_ZERO C_00000008 +#define CC_REG_SATURATE C_00000010 +#define CC_REG_NONZERO C_00000100 + +/* FX buses */ +#define FXBUS_PCM_LEFT 0x00 +#define FXBUS_PCM_RIGHT 0x01 +#define FXBUS_PCM_LEFT_REAR 0x02 +#define FXBUS_PCM_RIGHT_REAR 0x03 +#define FXBUS_MIDI_LEFT 0x04 +#define FXBUS_MIDI_RIGHT 0x05 +#define FXBUS_PCM_CENTER 0x06 +#define FXBUS_PCM_LFE 0x07 +#define FXBUS_PCM_LEFT_FRONT 0x08 +#define FXBUS_PCM_RIGHT_FRONT 0x09 +#define FXBUS_MIDI_REVERB 0x0c +#define FXBUS_MIDI_CHORUS 0x0d +#define FXBUS_PCM_LEFT_SIDE 0x0e +#define FXBUS_PCM_RIGHT_SIDE 0x0f +#define FXBUS_PT_LEFT 0x14 +#define FXBUS_PT_RIGHT 0x15 + +/* Inputs */ +#define EXTIN_AC97_L 0x00 /* AC'97 capture channel - left */ +#define EXTIN_AC97_R 0x01 /* AC'97 capture channel - right */ +#define EXTIN_SPDIF_CD_L 0x02 /* internal S/PDIF CD - onboard - left */ +#define EXTIN_SPDIF_CD_R 0x03 /* internal S/PDIF CD - onboard - right */ +#define EXTIN_ZOOM_L 0x04 /* Zoom Video I2S - left */ +#define EXTIN_ZOOM_R 0x05 /* Zoom Video I2S - right */ +#define EXTIN_TOSLINK_L 0x06 /* LiveDrive - TOSLink Optical - left */ +#define EXTIN_TOSLINK_R 0x07 /* LiveDrive - TOSLink Optical - right */ +#define EXTIN_LINE1_L 0x08 /* LiveDrive - Line/Mic 1 - left */ +#define EXTIN_LINE1_R 0x09 /* LiveDrive - Line/Mic 1 - right */ +#define EXTIN_COAX_SPDIF_L 0x0a /* LiveDrive - Coaxial S/PDIF - left */ +#define EXTIN_COAX_SPDIF_R 0x0b /* LiveDrive - Coaxial S/PDIF - right */ +#define EXTIN_LINE2_L 0x0c /* LiveDrive - Line/Mic 2 - left */ +#define EXTIN_LINE2_R 0x0d /* LiveDrive - Line/Mic 2 - right */ + +/* Outputs */ +#define EXTOUT_AC97_L 0x00 /* AC'97 playback channel - left */ +#define EXTOUT_AC97_R 0x01 /* AC'97 playback channel - right */ +#define EXTOUT_TOSLINK_L 0x02 /* LiveDrive - TOSLink Optical - left */ +#define EXTOUT_TOSLINK_R 0x03 /* LiveDrive - TOSLink Optical - right */ +#define EXTOUT_AC97_CENTER 0x04 /* SB Live 5.1 - center */ +#define EXTOUT_AC97_LFE 0x05 /* SB Live 5.1 - LFE */ +#define EXTOUT_HEADPHONE_L 0x06 /* LiveDrive - Headphone - left */ +#define EXTOUT_HEADPHONE_R 0x07 /* LiveDrive - Headphone - right */ +#define EXTOUT_REAR_L 0x08 /* Rear channel - left */ +#define EXTOUT_REAR_R 0x09 /* Rear channel - right */ +#define EXTOUT_ADC_CAP_L 0x0a /* ADC Capture buffer - left */ +#define EXTOUT_ADC_CAP_R 0x0b /* ADC Capture buffer - right */ +#define EXTOUT_MIC_CAP 0x0c /* MIC Capture buffer */ +#define EXTOUT_AC97_REAR_L 0x0d /* SB Live 5.1 (c) 2003 - Rear Left */ +#define EXTOUT_AC97_REAR_R 0x0e /* SB Live 5.1 (c) 2003 - Rear Right */ +#define EXTOUT_ACENTER 0x11 /* Analog Center */ +#define EXTOUT_ALFE 0x12 /* Analog LFE */ + +/* Audigy Inputs */ +#define A_EXTIN_AC97_L 0x00 /* AC'97 capture channel - left */ +#define A_EXTIN_AC97_R 0x01 /* AC'97 capture channel - right */ +#define A_EXTIN_SPDIF_CD_L 0x02 /* digital CD left */ +#define A_EXTIN_SPDIF_CD_R 0x03 /* digital CD left */ +#define A_EXTIN_OPT_SPDIF_L 0x04 /* audigy drive Optical SPDIF - left */ +#define A_EXTIN_OPT_SPDIF_R 0x05 /* right */ +#define A_EXTIN_LINE2_L 0x08 /* audigy drive line2/mic2 - left */ +#define A_EXTIN_LINE2_R 0x09 /* right */ +#define A_EXTIN_ADC_L 0x0a /* Philips ADC - left */ +#define A_EXTIN_ADC_R 0x0b /* right */ +#define A_EXTIN_AUX2_L 0x0c /* audigy drive aux2 - left */ +#define A_EXTIN_AUX2_R 0x0d /* - right */ + +/* Audigiy Outputs */ +#define A_EXTOUT_FRONT_L 0x00 /* digital front left */ +#define A_EXTOUT_FRONT_R 0x01 /* right */ +#define A_EXTOUT_CENTER 0x02 /* digital front center */ +#define A_EXTOUT_LFE 0x03 /* digital front lfe */ +#define A_EXTOUT_HEADPHONE_L 0x04 /* headphone audigy drive left */ +#define A_EXTOUT_HEADPHONE_R 0x05 /* right */ +#define A_EXTOUT_REAR_L 0x06 /* digital rear left */ +#define A_EXTOUT_REAR_R 0x07 /* right */ +#define A_EXTOUT_AFRONT_L 0x08 /* analog front left */ +#define A_EXTOUT_AFRONT_R 0x09 /* right */ +#define A_EXTOUT_ACENTER 0x0a /* analog center */ +#define A_EXTOUT_ALFE 0x0b /* analog LFE */ +#define A_EXTOUT_ASIDE_L 0x0c /* analog side left - Audigy 2 ZS */ +#define A_EXTOUT_ASIDE_R 0x0d /* right - Audigy 2 ZS */ +#define A_EXTOUT_AREAR_L 0x0e /* analog rear left */ +#define A_EXTOUT_AREAR_R 0x0f /* right */ +#define A_EXTOUT_AC97_L 0x10 /* AC97 left (front) */ +#define A_EXTOUT_AC97_R 0x11 /* right */ +#define A_EXTOUT_ADC_CAP_L 0x16 /* ADC capture buffer left */ +#define A_EXTOUT_ADC_CAP_R 0x17 /* right */ +#define A_EXTOUT_MIC_CAP 0x18 /* Mic capture buffer */ + +/* Audigy constants */ +#define A_C_00000000 0xc0 +#define A_C_00000001 0xc1 +#define A_C_00000002 0xc2 +#define A_C_00000003 0xc3 +#define A_C_00000004 0xc4 +#define A_C_00000008 0xc5 +#define A_C_00000010 0xc6 +#define A_C_00000020 0xc7 +#define A_C_00000100 0xc8 +#define A_C_00010000 0xc9 +#define A_C_00000800 0xca +#define A_C_10000000 0xcb +#define A_C_20000000 0xcc +#define A_C_40000000 0xcd +#define A_C_80000000 0xce +#define A_C_7fffffff 0xcf +#define A_C_ffffffff 0xd0 +#define A_C_fffffffe 0xd1 +#define A_C_c0000000 0xd2 +#define A_C_4f1bbcdc 0xd3 +#define A_C_5a7ef9db 0xd4 +#define A_C_00100000 0xd5 +#define A_GPR_ACCU 0xd6 /* ACCUM, accumulator */ +#define A_GPR_COND 0xd7 /* CCR, condition register */ +#define A_GPR_NOISE0 0xd8 /* noise source */ +#define A_GPR_NOISE1 0xd9 /* noise source */ +#define A_GPR_IRQ 0xda /* IRQ register */ +#define A_GPR_DBAC 0xdb /* TRAM Delay Base Address Counter - internal */ +#define A_GPR_DBACE 0xde /* TRAM Delay Base Address Counter - external */ + +/* definitions for debug register */ +#define EMU10K1_DBG_ZC 0x80000000 /* zero tram counter */ +#define EMU10K1_DBG_SATURATION_OCCURED 0x02000000 /* saturation control */ +#define EMU10K1_DBG_SATURATION_ADDR 0x01ff0000 /* saturation address */ +#define EMU10K1_DBG_SINGLE_STEP 0x00008000 /* single step mode */ +#define EMU10K1_DBG_STEP 0x00004000 /* start single step */ +#define EMU10K1_DBG_CONDITION_CODE 0x00003e00 /* condition code */ +#define EMU10K1_DBG_SINGLE_STEP_ADDR 0x000001ff /* single step address */ + +/* tank memory address line */ +#ifndef __KERNEL__ +#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ +#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ +#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ +#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ +#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ +#endif + +typedef struct { + unsigned int internal_tram_size; /* in samples */ + unsigned int external_tram_size; /* in samples */ + char fxbus_names[16][32]; /* names of FXBUSes */ + char extin_names[16][32]; /* names of external inputs */ + char extout_names[32][32]; /* names of external outputs */ + unsigned int gpr_controls; /* count of GPR controls */ +} emu10k1_fx8010_info_t; + +#define EMU10K1_GPR_TRANSLATION_NONE 0 +#define EMU10K1_GPR_TRANSLATION_TABLE100 1 +#define EMU10K1_GPR_TRANSLATION_BASS 2 +#define EMU10K1_GPR_TRANSLATION_TREBLE 3 +#define EMU10K1_GPR_TRANSLATION_ONOFF 4 + +enum emu10k1_ctl_elem_iface { + EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */ + EMU10K1_CTL_ELEM_IFACE_PCM = 3, /* PCM device */ +}; + +typedef struct { + unsigned int pad; /* don't use */ + int iface; /* interface identifier */ + unsigned int device; /* device/client number */ + unsigned int subdevice; /* subdevice (substream) number */ + unsigned char name[44]; /* ASCII name of item */ + unsigned int index; /* index of item */ +} emu10k1_ctl_elem_id_t; + +typedef struct { + emu10k1_ctl_elem_id_t id; /* full control ID definition */ + unsigned int vcount; /* visible count */ + unsigned int count; /* count of GPR (1..16) */ + unsigned short gpr[32]; /* GPR number(s) */ + unsigned int value[32]; /* initial values */ + unsigned int min; /* minimum range */ + unsigned int max; /* maximum range */ + unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ + unsigned int *tlv; +} emu10k1_fx8010_control_gpr_t; + +typedef struct { + char name[128]; + + unsigned long gpr_valid[0x200/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ + uint32_t *gpr_map; /* initializers */ + + unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */ + emu10k1_fx8010_control_gpr_t *gpr_add_controls; /* GPR controls to add/replace */ + + unsigned int gpr_del_control_count; /* count of GPR controls to remove */ + emu10k1_ctl_elem_id_t *gpr_del_controls; /* IDs of GPR controls to remove */ + + unsigned int gpr_list_control_count; /* count of GPR controls to list */ + unsigned int gpr_list_control_total; /* total count of GPR controls */ + emu10k1_fx8010_control_gpr_t *gpr_list_controls; /* listed GPR controls */ + + unsigned long tram_valid[0x100/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ + uint32_t *tram_data_map; /* data initializers */ + uint32_t *tram_addr_map; /* map initializers */ + + unsigned long code_valid[1024/(sizeof(unsigned long)*8)]; /* bitmask of valid instructions */ + uint32_t *code; /* one instruction - 64 bits */ +} emu10k1_fx8010_code_t; + +typedef struct { + unsigned int address; /* 31.bit == 1 -> external TRAM */ + unsigned int size; /* size in samples (4 bytes) */ + unsigned int *samples; /* pointer to samples (20-bit) */ + /* NULL->clear memory */ +} emu10k1_fx8010_tram_t; + +typedef struct { + unsigned int substream; /* substream number */ + unsigned int res1; /* reserved */ + unsigned int channels; /* 16-bit channels count, zero = remove this substream */ + unsigned int tram_start; /* ring buffer position in TRAM (in samples) */ + unsigned int buffer_size; /* count of buffered samples */ + unsigned short gpr_size; /* GPR containing size of ringbuffer in samples (host) */ + unsigned short gpr_ptr; /* GPR containing current pointer in the ring buffer (host = reset, FX8010) */ + unsigned short gpr_count; /* GPR containing count of samples between two interrupts (host) */ + unsigned short gpr_tmpcount; /* GPR containing current count of samples to interrupt (host = set, FX8010) */ + unsigned short gpr_trigger; /* GPR containing trigger (activate) information (host) */ + unsigned short gpr_running; /* GPR containing info if PCM is running (FX8010) */ + unsigned char pad; /* reserved */ + unsigned char etram[32]; /* external TRAM address & data (one per channel) */ + unsigned int res2; /* reserved */ +} emu10k1_fx8010_pcm_t; + +#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, emu10k1_fx8010_info_t) +#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, emu10k1_fx8010_code_t) +#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, emu10k1_fx8010_code_t) +#define SNDRV_EMU10K1_IOCTL_TRAM_SETUP _IOW ('H', 0x20, int) +#define SNDRV_EMU10K1_IOCTL_TRAM_POKE _IOW ('H', 0x21, emu10k1_fx8010_tram_t) +#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, emu10k1_fx8010_tram_t) +#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, emu10k1_fx8010_pcm_t) +#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, emu10k1_fx8010_pcm_t) +#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int) +#define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80) +#define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81) +#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82) +#define SNDRV_EMU10K1_IOCTL_SINGLE_STEP _IOW ('H', 0x83, int) +#define SNDRV_EMU10K1_IOCTL_DBG_READ _IOR ('H', 0x84, int) + +#endif /* __SOUND_EMU10K1_H */ diff --git a/include/sound/hdsp.h b/include/sound/hdsp.h new file mode 100644 index 0000000..0fc9e98 --- /dev/null +++ b/include/sound/hdsp.h @@ -0,0 +1,112 @@ +#ifndef __SOUND_HDSP_H +#define __SOUND_HDSP_H + +/* + * Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#define HDSP_MATRIX_MIXER_SIZE 2048 + +typedef enum { + Digiface, + Multiface, + H9652, + H9632, + Undefined, +} HDSP_IO_Type; + +typedef struct _snd_hdsp_peak_rms hdsp_peak_rms_t; + +struct _snd_hdsp_peak_rms { + uint32_t input_peaks[26]; + uint32_t playback_peaks[26]; + uint32_t output_peaks[28]; + uint64_t input_rms[26]; + uint64_t playback_rms[26]; + /* These are only used for H96xx cards */ + uint64_t output_rms[26]; +}; + +#define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, hdsp_peak_rms_t) + +typedef struct _snd_hdsp_config_info hdsp_config_info_t; + +struct _snd_hdsp_config_info { + unsigned char pref_sync_ref; + unsigned char wordclock_sync_check; + unsigned char spdif_sync_check; + unsigned char adatsync_sync_check; + unsigned char adat_sync_check[3]; + unsigned char spdif_in; + unsigned char spdif_out; + unsigned char spdif_professional; + unsigned char spdif_emphasis; + unsigned char spdif_nonaudio; + unsigned int spdif_sample_rate; + unsigned int system_sample_rate; + unsigned int autosync_sample_rate; + unsigned char system_clock_mode; + unsigned char clock_source; + unsigned char autosync_ref; + unsigned char line_out; + unsigned char passthru; + unsigned char da_gain; + unsigned char ad_gain; + unsigned char phone_gain; + unsigned char xlr_breakout_cable; + unsigned char analog_extension_board; +}; + +#define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdsp_config_info_t) + +typedef struct _snd_hdsp_firmware hdsp_firmware_t; + +struct _snd_hdsp_firmware { + void *firmware_data; /* 24413 x 4 bytes */ +}; + +#define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, hdsp_firmware_t) + +typedef struct _snd_hdsp_version hdsp_version_t; + +struct _snd_hdsp_version { + HDSP_IO_Type io_type; + unsigned short firmware_rev; +}; + +#define SNDRV_HDSP_IOCTL_GET_VERSION _IOR('H', 0x43, hdsp_version_t) + +typedef struct _snd_hdsp_mixer hdsp_mixer_t; + +struct _snd_hdsp_mixer { + unsigned short matrix[HDSP_MATRIX_MIXER_SIZE]; +}; + +#define SNDRV_HDSP_IOCTL_GET_MIXER _IOR('H', 0x44, hdsp_mixer_t) + +typedef struct _snd_hdsp_9632_aeb hdsp_9632_aeb_t; + +struct _snd_hdsp_9632_aeb { + int aebi; + int aebo; +}; + +#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, hdsp_9632_aeb_t) + +#endif /* __SOUND_HDSP_H */ diff --git a/include/sound/hdspm.h b/include/sound/hdspm.h new file mode 100644 index 0000000..1774ff5 --- /dev/null +++ b/include/sound/hdspm.h @@ -0,0 +1,229 @@ +#ifndef __SOUND_HDSPM_H +#define __SOUND_HDSPM_H +/* + * Copyright (C) 2003 Winfried Ritsch (IEM) + * based on hdsp.h from Thomas Charbonnel (thomas@undata.org) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ +#define HDSPM_MAX_CHANNELS 64 + +enum hdspm_io_type { + MADI, + MADIface, + AIO, + AES32, + RayDAT +}; + +enum hdspm_speed { + ss, + ds, + qs +}; + +/* -------------------- IOCTL Peak/RMS Meters -------------------- */ + +struct hdspm_peak_rms { + uint32_t input_peaks[64]; + uint32_t playback_peaks[64]; + uint32_t output_peaks[64]; + + uint64_t input_rms[64]; + uint64_t playback_rms[64]; + uint64_t output_rms[64]; + + uint8_t speed; /* enum {ss, ds, qs} */ + int status2; +}; + +#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS \ + _IOR('H', 0x42, struct hdspm_peak_rms) + +/* ------------ CONFIG block IOCTL ---------------------- */ + +struct hdspm_config { + unsigned char pref_sync_ref; + unsigned char wordclock_sync_check; + unsigned char madi_sync_check; + unsigned int system_sample_rate; + unsigned int autosync_sample_rate; + unsigned char system_clock_mode; + unsigned char clock_source; + unsigned char autosync_ref; + unsigned char line_out; + unsigned int passthru; + unsigned int analog_out; +}; + +#define SNDRV_HDSPM_IOCTL_GET_CONFIG \ + _IOR('H', 0x41, struct hdspm_config) + +/** + * If there's a TCO (TimeCode Option) board installed, + * there are further options and status data available. + * The hdspm_ltc structure contains the current SMPTE + * timecode and some status information and can be + * obtained via SNDRV_HDSPM_IOCTL_GET_LTC or in the + * hdspm_status struct. + **/ + +enum hdspm_ltc_format { + format_invalid, + fps_24, + fps_25, + fps_2997, + fps_30 +}; + +enum hdspm_ltc_frame { + frame_invalid, + drop_frame, + full_frame +}; + +enum hdspm_ltc_input_format { + ntsc, + pal, + no_video +}; + +struct hdspm_ltc { + unsigned int ltc; + + enum hdspm_ltc_format format; + enum hdspm_ltc_frame frame; + enum hdspm_ltc_input_format input_format; +}; + +#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_mixer_ioctl) + +/** + * The status data reflects the device's current state + * as determined by the card's configuration and + * connection status. + **/ + +enum hdspm_sync { + hdspm_sync_no_lock = 0, + hdspm_sync_lock = 1, + hdspm_sync_sync = 2 +}; + +enum hdspm_madi_input { + hdspm_input_optical = 0, + hdspm_input_coax = 1 +}; + +enum hdspm_madi_channel_format { + hdspm_format_ch_64 = 0, + hdspm_format_ch_56 = 1 +}; + +enum hdspm_madi_frame_format { + hdspm_frame_48 = 0, + hdspm_frame_96 = 1 +}; + +enum hdspm_syncsource { + syncsource_wc = 0, + syncsource_madi = 1, + syncsource_tco = 2, + syncsource_sync = 3, + syncsource_none = 4 +}; + +struct hdspm_status { + uint8_t card_type; /* enum hdspm_io_type */ + enum hdspm_syncsource autosync_source; + + uint64_t card_clock; + uint32_t master_period; + + union { + struct { + uint8_t sync_wc; /* enum hdspm_sync */ + uint8_t sync_madi; /* enum hdspm_sync */ + uint8_t sync_tco; /* enum hdspm_sync */ + uint8_t sync_in; /* enum hdspm_sync */ + uint8_t madi_input; /* enum hdspm_madi_input */ + uint8_t channel_format; /* enum hdspm_madi_channel_format */ + uint8_t frame_format; /* enum hdspm_madi_frame_format */ + } madi; + } card_specific; +}; + +#define SNDRV_HDSPM_IOCTL_GET_STATUS \ + _IOR('H', 0x47, struct hdspm_status) + +/** + * Get information about the card and its add-ons. + **/ + +#define HDSPM_ADDON_TCO 1 + +struct hdspm_version { + uint8_t card_type; /* enum hdspm_io_type */ + char cardname[20]; + unsigned int serial; + unsigned short firmware_rev; + int addons; +}; + +#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x48, struct hdspm_version) + +/* ------------- get Matrix Mixer IOCTL --------------- */ + +/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = + * 32768 Bytes + */ + +/* organisation is 64 channelfader in a continous memory block */ +/* equivalent to hardware definition, maybe for future feature of mmap of + * them + */ +/* each of 64 outputs has 64 infader and 64 outfader: + Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */ + +#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS + +struct hdspm_channelfader { + unsigned int in[HDSPM_MIXER_CHANNELS]; + unsigned int pb[HDSPM_MIXER_CHANNELS]; +}; + +struct hdspm_mixer { + struct hdspm_channelfader ch[HDSPM_MIXER_CHANNELS]; +}; + +struct hdspm_mixer_ioctl { + struct hdspm_mixer *mixer; +}; + +/* use indirect access due to the limit of ioctl bit size */ +#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct hdspm_mixer_ioctl) + +/* typedefs for compatibility to user-space */ +typedef struct hdspm_peak_rms hdspm_peak_rms_t; +typedef struct hdspm_config_info hdspm_config_info_t; +typedef struct hdspm_version hdspm_version_t; +typedef struct hdspm_channelfader snd_hdspm_channelfader_t; +typedef struct hdspm_mixer hdspm_mixer_t; + + +#endif diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h new file mode 100644 index 0000000..78817b4 --- /dev/null +++ b/include/sound/sb16_csp.h @@ -0,0 +1,115 @@ +#ifndef __SOUND_SB16_CSP_H +#define __SOUND_SB16_CSP_H + +/* + * Copyright (c) 1999 by Uros Bizjak + * Takashi Iwai + * + * SB16ASP/AWE32 CSP control + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* CSP modes */ +#define SNDRV_SB_CSP_MODE_NONE 0x00 +#define SNDRV_SB_CSP_MODE_DSP_READ 0x01 /* Record from DSP */ +#define SNDRV_SB_CSP_MODE_DSP_WRITE 0x02 /* Play to DSP */ +#define SNDRV_SB_CSP_MODE_QSOUND 0x04 /* QSound */ + +/* CSP load flags */ +#define SNDRV_SB_CSP_LOAD_FROMUSER 0x01 +#define SNDRV_SB_CSP_LOAD_INITBLOCK 0x02 + +/* CSP sample width */ +#define SNDRV_SB_CSP_SAMPLE_8BIT 0x01 +#define SNDRV_SB_CSP_SAMPLE_16BIT 0x02 + +/* CSP channels */ +#define SNDRV_SB_CSP_MONO 0x01 +#define SNDRV_SB_CSP_STEREO 0x02 + +/* CSP rates */ +#define SNDRV_SB_CSP_RATE_8000 0x01 +#define SNDRV_SB_CSP_RATE_11025 0x02 +#define SNDRV_SB_CSP_RATE_22050 0x04 +#define SNDRV_SB_CSP_RATE_44100 0x08 +#define SNDRV_SB_CSP_RATE_ALL 0x0f + +/* CSP running state */ +#define SNDRV_SB_CSP_ST_IDLE 0x00 +#define SNDRV_SB_CSP_ST_LOADED 0x01 +#define SNDRV_SB_CSP_ST_RUNNING 0x02 +#define SNDRV_SB_CSP_ST_PAUSED 0x04 +#define SNDRV_SB_CSP_ST_AUTO 0x08 +#define SNDRV_SB_CSP_ST_QSOUND 0x10 + +/* maximum QSound value (180 degrees right) */ +#define SNDRV_SB_CSP_QSOUND_MAX_RIGHT 0x20 + +/* maximum microcode RIFF file size */ +#define SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE 0x3000 + +/* microcode header */ +typedef struct snd_sb_csp_mc_header { + char codec_name[16]; /* id name of codec */ + unsigned short func_req; /* requested function */ +} snd_sb_csp_mc_header_t; + +/* microcode to be loaded */ +typedef struct snd_sb_csp_microcode { + snd_sb_csp_mc_header_t info; + unsigned char data[SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE]; +} snd_sb_csp_microcode_t; + +/* start CSP with sample_width in mono/stereo */ +typedef struct snd_sb_csp_start { + int sample_width; /* sample width, look above */ + int channels; /* channels, look above */ +} snd_sb_csp_start_t; + +/* CSP information */ +typedef struct snd_sb_csp_info { + char codec_name[16]; /* id name of codec */ + unsigned short func_nr; /* function number */ + unsigned int acc_format; /* accepted PCM formats */ + unsigned short acc_channels; /* accepted channels */ + unsigned short acc_width; /* accepted sample width */ + unsigned short acc_rates; /* accepted sample rates */ + unsigned short csp_mode; /* CSP mode, see above */ + unsigned short run_channels; /* current channels */ + unsigned short run_width; /* current sample width */ + unsigned short version; /* version id: 0x10 - 0x1f */ + unsigned short state; /* state bits */ +} snd_sb_csp_info_t; + +/* HWDEP controls */ +/* get CSP information */ +#define SNDRV_SB_CSP_IOCTL_INFO _IOR('H', 0x10, snd_sb_csp_info_t) +/* load microcode to CSP */ +#define SNDRV_SB_CSP_IOCTL_LOAD_CODE _IOW('H', 0x11, snd_sb_csp_microcode_t) +/* unload microcode from CSP */ +#define SNDRV_SB_CSP_IOCTL_UNLOAD_CODE _IO('H', 0x12) +/* start CSP */ +#define SNDRV_SB_CSP_IOCTL_START _IOW('H', 0x13, snd_sb_csp_start_t) +/* stop CSP */ +#define SNDRV_SB_CSP_IOCTL_STOP _IO('H', 0x14) +/* pause CSP and DMA transfer */ +#define SNDRV_SB_CSP_IOCTL_PAUSE _IO('H', 0x15) +/* restart CSP and DMA transfer */ +#define SNDRV_SB_CSP_IOCTL_RESTART _IO('H', 0x16) + + +#endif /* __SOUND_SB16_CSP */ diff --git a/include/sound/sscape_ioctl.h b/include/sound/sscape_ioctl.h new file mode 100644 index 0000000..c6653eb --- /dev/null +++ b/include/sound/sscape_ioctl.h @@ -0,0 +1,21 @@ +#ifndef SSCAPE_IOCTL_H +#define SSCAPE_IOCTL_H + + +struct sscape_bootblock +{ + unsigned char code[256]; + unsigned version; +}; + +#define SSCAPE_MICROCODE_SIZE 65536 + +struct sscape_microcode +{ + unsigned char *code; +}; + +#define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock) +#define SND_SSCAPE_LOAD_MCODE _IOW ('P', 101, struct sscape_microcode) + +#endif diff --git a/include/sound/type_compat.h b/include/sound/type_compat.h new file mode 100644 index 0000000..eec86e4 --- /dev/null +++ b/include/sound/type_compat.h @@ -0,0 +1,40 @@ +#ifndef __TYPE_COMPAT_H +#define __TYPE_COMPAT_H + +#ifndef DOC_HIDDEN +#include +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +typedef int8_t __s8; +typedef int16_t __s16; +typedef int32_t __s32; + +#include +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define __cpu_to_le32(x) (x) +#define __cpu_to_be32(x) bswap_32(x) +#define __cpu_to_le16(x) (x) +#define __cpu_to_be16(x) bswap_16(x) +#else +#define __cpu_to_le32(x) bswap_32(x) +#define __cpu_to_be32(x) (x) +#define __cpu_to_le16(x) bswap_16(x) +#define __cpu_to_be16(x) (x) +#endif + +#define __le32_to_cpu __cpu_to_le32 +#define __be32_to_cpu __cpu_to_be32 +#define __le16_to_cpu __cpu_to_le16 +#define __be16_to_cpu __cpu_to_be16 + +#define __le64 __u64 +#define __le32 __u32 +#define __le16 __u16 +#define __be64 __u64 +#define __be32 __u32 +#define __be16 __u16 +#endif /* DOC_HIDDEN */ + +#endif /* __TYPE_COMPAT_H */ diff --git a/include/sys.h b/include/sys.h new file mode 100644 index 0000000..47f587c --- /dev/null +++ b/include/sys.h @@ -0,0 +1,2 @@ +#warning This header is deprecated, use instead. +#include diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..2803f53 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,259 @@ +/** + * \file include/timer.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2001 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_TIMER_H +#define __ALSA_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Timer Timer Interface + * Timer Interface. See \ref timer page for more details. + * \{ + */ + +/** dlsym version for interface entry callback */ +#define SND_TIMER_DLSYM_VERSION _dlsym_timer_001 +/** dlsym version for interface entry callback */ +#define SND_TIMER_QUERY_DLSYM_VERSION _dlsym_timer_query_001 + +/** timer identification structure */ +typedef struct _snd_timer_id snd_timer_id_t; +/** timer global info structure */ +typedef struct _snd_timer_ginfo snd_timer_ginfo_t; +/** timer global params structure */ +typedef struct _snd_timer_gparams snd_timer_gparams_t; +/** timer global status structure */ +typedef struct _snd_timer_gstatus snd_timer_gstatus_t; +/** timer info structure */ +typedef struct _snd_timer_info snd_timer_info_t; +/** timer params structure */ +typedef struct _snd_timer_params snd_timer_params_t; +/** timer status structure */ +typedef struct _snd_timer_status snd_timer_status_t; +/** timer master class */ +typedef enum _snd_timer_class { + SND_TIMER_CLASS_NONE = -1, /**< invalid */ + SND_TIMER_CLASS_SLAVE = 0, /**< slave timer */ + SND_TIMER_CLASS_GLOBAL, /**< global timer */ + SND_TIMER_CLASS_CARD, /**< card timer */ + SND_TIMER_CLASS_PCM, /**< PCM timer */ + SND_TIMER_CLASS_LAST = SND_TIMER_CLASS_PCM /**< last timer */ +} snd_timer_class_t; + +/** timer slave class */ +typedef enum _snd_timer_slave_class { + SND_TIMER_SCLASS_NONE = 0, /**< none */ + SND_TIMER_SCLASS_APPLICATION, /**< for internal use */ + SND_TIMER_SCLASS_SEQUENCER, /**< sequencer timer */ + SND_TIMER_SCLASS_OSS_SEQUENCER, /**< OSS sequencer timer */ + SND_TIMER_SCLASS_LAST = SND_TIMER_SCLASS_OSS_SEQUENCER /**< last slave timer */ +} snd_timer_slave_class_t; + +/** timer read event identification */ +typedef enum _snd_timer_event { + SND_TIMER_EVENT_RESOLUTION = 0, /* val = resolution in ns */ + SND_TIMER_EVENT_TICK, /* val = ticks */ + SND_TIMER_EVENT_START, /* val = resolution in ns */ + SND_TIMER_EVENT_STOP, /* val = 0 */ + SND_TIMER_EVENT_CONTINUE, /* val = resolution in ns */ + SND_TIMER_EVENT_PAUSE, /* val = 0 */ + SND_TIMER_EVENT_EARLY, /* val = 0 */ + SND_TIMER_EVENT_SUSPEND, /* val = 0 */ + SND_TIMER_EVENT_RESUME, /* val = resolution in ns */ + /* master timer events for slave timer instances */ + SND_TIMER_EVENT_MSTART = SND_TIMER_EVENT_START + 10, + SND_TIMER_EVENT_MSTOP = SND_TIMER_EVENT_STOP + 10, + SND_TIMER_EVENT_MCONTINUE = SND_TIMER_EVENT_CONTINUE + 10, + SND_TIMER_EVENT_MPAUSE = SND_TIMER_EVENT_PAUSE + 10, + SND_TIMER_EVENT_MSUSPEND = SND_TIMER_EVENT_SUSPEND + 10, + SND_TIMER_EVENT_MRESUME = SND_TIMER_EVENT_RESUME + 10 +} snd_timer_event_t; + +/** timer read structure */ +typedef struct _snd_timer_read { + unsigned int resolution; /**< tick resolution in nanoseconds */ + unsigned int ticks; /**< count of happened ticks */ +} snd_timer_read_t; + +/** timer tstamp + event read structure */ +typedef struct _snd_timer_tread { + snd_timer_event_t event; /**< Timer event */ + snd_htimestamp_t tstamp; /**< Time stamp of each event */ + unsigned int val; /**< Event value */ +} snd_timer_tread_t; + +/** global timer - system */ +#define SND_TIMER_GLOBAL_SYSTEM 0 +/** global timer - RTC */ +#define SND_TIMER_GLOBAL_RTC 1 +/** global timer - HPET */ +#define SND_TIMER_GLOBAL_HPET 2 +/** global timer - HRTIMER */ +#define SND_TIMER_GLOBAL_HRTIMER 3 + +/** timer open mode flag - non-blocking behaviour */ +#define SND_TIMER_OPEN_NONBLOCK (1<<0) +/** use timestamps and event notification - enhanced read */ +#define SND_TIMER_OPEN_TREAD (1<<1) + +/** timer handle type */ +typedef enum _snd_timer_type { + /** Kernel level HwDep */ + SND_TIMER_TYPE_HW = 0, + /** Shared memory client timer (not yet implemented) */ + SND_TIMER_TYPE_SHM, + /** INET client timer (not yet implemented) */ + SND_TIMER_TYPE_INET +} snd_timer_type_t; + +/** timer query handle */ +typedef struct _snd_timer_query snd_timer_query_t; +/** timer handle */ +typedef struct _snd_timer snd_timer_t; + + +int snd_timer_query_open(snd_timer_query_t **handle, const char *name, int mode); +int snd_timer_query_open_lconf(snd_timer_query_t **handle, const char *name, int mode, snd_config_t *lconf); +int snd_timer_query_close(snd_timer_query_t *handle); +int snd_timer_query_next_device(snd_timer_query_t *handle, snd_timer_id_t *tid); +int snd_timer_query_info(snd_timer_query_t *handle, snd_timer_ginfo_t *info); +int snd_timer_query_params(snd_timer_query_t *handle, snd_timer_gparams_t *params); +int snd_timer_query_status(snd_timer_query_t *handle, snd_timer_gstatus_t *status); + +int snd_timer_open(snd_timer_t **handle, const char *name, int mode); +int snd_timer_open_lconf(snd_timer_t **handle, const char *name, int mode, snd_config_t *lconf); +int snd_timer_close(snd_timer_t *handle); +int snd_async_add_timer_handler(snd_async_handler_t **handler, snd_timer_t *timer, + snd_async_callback_t callback, void *private_data); +snd_timer_t *snd_async_handler_get_timer(snd_async_handler_t *handler); +int snd_timer_poll_descriptors_count(snd_timer_t *handle); +int snd_timer_poll_descriptors(snd_timer_t *handle, struct pollfd *pfds, unsigned int space); +int snd_timer_poll_descriptors_revents(snd_timer_t *timer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_timer_info(snd_timer_t *handle, snd_timer_info_t *timer); +int snd_timer_params(snd_timer_t *handle, snd_timer_params_t *params); +int snd_timer_status(snd_timer_t *handle, snd_timer_status_t *status); +int snd_timer_start(snd_timer_t *handle); +int snd_timer_stop(snd_timer_t *handle); +int snd_timer_continue(snd_timer_t *handle); +ssize_t snd_timer_read(snd_timer_t *handle, void *buffer, size_t size); + +size_t snd_timer_id_sizeof(void); +/** allocate #snd_timer_id_t container on stack */ +#define snd_timer_id_alloca(ptr) __snd_alloca(ptr, snd_timer_id) +int snd_timer_id_malloc(snd_timer_id_t **ptr); +void snd_timer_id_free(snd_timer_id_t *obj); +void snd_timer_id_copy(snd_timer_id_t *dst, const snd_timer_id_t *src); + +void snd_timer_id_set_class(snd_timer_id_t *id, int dev_class); +int snd_timer_id_get_class(snd_timer_id_t *id); +void snd_timer_id_set_sclass(snd_timer_id_t *id, int dev_sclass); +int snd_timer_id_get_sclass(snd_timer_id_t *id); +void snd_timer_id_set_card(snd_timer_id_t *id, int card); +int snd_timer_id_get_card(snd_timer_id_t *id); +void snd_timer_id_set_device(snd_timer_id_t *id, int device); +int snd_timer_id_get_device(snd_timer_id_t *id); +void snd_timer_id_set_subdevice(snd_timer_id_t *id, int subdevice); +int snd_timer_id_get_subdevice(snd_timer_id_t *id); + +size_t snd_timer_ginfo_sizeof(void); +/** allocate #snd_timer_ginfo_t container on stack */ +#define snd_timer_ginfo_alloca(ptr) __snd_alloca(ptr, snd_timer_ginfo) +int snd_timer_ginfo_malloc(snd_timer_ginfo_t **ptr); +void snd_timer_ginfo_free(snd_timer_ginfo_t *obj); +void snd_timer_ginfo_copy(snd_timer_ginfo_t *dst, const snd_timer_ginfo_t *src); + +int snd_timer_ginfo_set_tid(snd_timer_ginfo_t *obj, snd_timer_id_t *tid); +snd_timer_id_t *snd_timer_ginfo_get_tid(snd_timer_ginfo_t *obj); +unsigned int snd_timer_ginfo_get_flags(snd_timer_ginfo_t *obj); +int snd_timer_ginfo_get_card(snd_timer_ginfo_t *obj); +char *snd_timer_ginfo_get_id(snd_timer_ginfo_t *obj); +char *snd_timer_ginfo_get_name(snd_timer_ginfo_t *obj); +unsigned long snd_timer_ginfo_get_resolution(snd_timer_ginfo_t *obj); +unsigned long snd_timer_ginfo_get_resolution_min(snd_timer_ginfo_t *obj); +unsigned long snd_timer_ginfo_get_resolution_max(snd_timer_ginfo_t *obj); +unsigned int snd_timer_ginfo_get_clients(snd_timer_ginfo_t *obj); + +size_t snd_timer_info_sizeof(void); +/** allocate #snd_timer_info_t container on stack */ +#define snd_timer_info_alloca(ptr) __snd_alloca(ptr, snd_timer_info) +int snd_timer_info_malloc(snd_timer_info_t **ptr); +void snd_timer_info_free(snd_timer_info_t *obj); +void snd_timer_info_copy(snd_timer_info_t *dst, const snd_timer_info_t *src); + +int snd_timer_info_is_slave(snd_timer_info_t * info); +int snd_timer_info_get_card(snd_timer_info_t * info); +const char *snd_timer_info_get_id(snd_timer_info_t * info); +const char *snd_timer_info_get_name(snd_timer_info_t * info); +long snd_timer_info_get_resolution(snd_timer_info_t * info); + +size_t snd_timer_params_sizeof(void); +/** allocate #snd_timer_params_t container on stack */ +#define snd_timer_params_alloca(ptr) __snd_alloca(ptr, snd_timer_params) +int snd_timer_params_malloc(snd_timer_params_t **ptr); +void snd_timer_params_free(snd_timer_params_t *obj); +void snd_timer_params_copy(snd_timer_params_t *dst, const snd_timer_params_t *src); + +int snd_timer_params_set_auto_start(snd_timer_params_t * params, int auto_start); +int snd_timer_params_get_auto_start(snd_timer_params_t * params); +int snd_timer_params_set_exclusive(snd_timer_params_t * params, int exclusive); +int snd_timer_params_get_exclusive(snd_timer_params_t * params); +int snd_timer_params_set_early_event(snd_timer_params_t * params, int early_event); +int snd_timer_params_get_early_event(snd_timer_params_t * params); +void snd_timer_params_set_ticks(snd_timer_params_t * params, long ticks); +long snd_timer_params_get_ticks(snd_timer_params_t * params); +void snd_timer_params_set_queue_size(snd_timer_params_t * params, long queue_size); +long snd_timer_params_get_queue_size(snd_timer_params_t * params); +void snd_timer_params_set_filter(snd_timer_params_t * params, unsigned int filter); +unsigned int snd_timer_params_get_filter(snd_timer_params_t * params); + +size_t snd_timer_status_sizeof(void); +/** allocate #snd_timer_status_t container on stack */ +#define snd_timer_status_alloca(ptr) __snd_alloca(ptr, snd_timer_status) +int snd_timer_status_malloc(snd_timer_status_t **ptr); +void snd_timer_status_free(snd_timer_status_t *obj); +void snd_timer_status_copy(snd_timer_status_t *dst, const snd_timer_status_t *src); + +snd_htimestamp_t snd_timer_status_get_timestamp(snd_timer_status_t * status); +long snd_timer_status_get_resolution(snd_timer_status_t * status); +long snd_timer_status_get_lost(snd_timer_status_t * status); +long snd_timer_status_get_overrun(snd_timer_status_t * status); +long snd_timer_status_get_queue(snd_timer_status_t * status); + +/* deprecated functions, for compatibility */ +long snd_timer_info_get_ticks(snd_timer_info_t * info); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /** __ALSA_TIMER_H */ + diff --git a/include/use-case.h b/include/use-case.h new file mode 100644 index 0000000..c37c842 --- /dev/null +++ b/include/use-case.h @@ -0,0 +1,381 @@ +/** + * \file include/use-case.h + * \brief use case interface for the ALSA driver + * \author Liam Girdwood + * \author Stefan Schmidt + * \author Jaroslav Kysela + * \author Justin Xu + * \date 2008-2010 + */ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2008-2010 SlimLogic Ltd + * Copyright (C) 2010 Wolfson Microelectronics PLC + * Copyright (C) 2010 Texas Instruments Inc. + * + * Support for the verb/device/modifier core logic and API, + * command line tool and file parser was kindly sponsored by + * Texas Instruments Inc. + * Support for multiple active modifiers and devices, + * transition sequences, multiple client access and user defined use + * cases was kindly sponsored by Wolfson Microelectronics PLC. + */ + +#ifndef __ALSA_USE_CASE_H +#define __ALSA_USE_CASE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup Use Case Interface + * The ALSA Use Case manager interface. + * See \ref Usecase page for more details. + * \{ + */ + +/** + * ALSA Use Case Interface + * + * The use case manager works by configuring the sound card ALSA kcontrols to + * change the hardware digital and analog audio routing to match the requested + * device use case. The use case manager kcontrol configurations are stored in + * easy to modify text files. + * + * An audio use case can be defined by a verb and device parameter. The verb + * describes the use case action i.e. a phone call, listening to music, recording + * a conversation etc. The device describes the physical audio capture and playback + * hardware i.e. headphones, phone handset, bluetooth headset, etc. + * + * It's intended clients will mostly only need to set the use case verb and + * device for each system use case change (as the verb and device parameters + * cover most audio use cases). + * + * However there are times when a use case has to be modified at runtime. e.g. + * + * o Incoming phone call when the device is playing music + * o Recording sections of a phone call + * o Playing tones during a call. + * + * In order to allow asynchronous runtime use case adaptations, we have a third + * optional modifier parameter that can be used to further configure + * the use case during live audio runtime. + * + * This interface allows clients to :- + * + * o Query the supported use case verbs, devices and modifiers for the machine. + * o Set and Get use case verbs, devices and modifiers for the machine. + * o Get the ALSA PCM playback and capture device PCMs for use case verb, + * use case device and modifier. + * o Get the TQ parameter for each use case verb, use case device and + * modifier. + * o Get the ALSA master playback and capture volume/switch kcontrols + * for each use case. + */ + + +/* + * Use Case Verb. + * + * The use case verb is the main device audio action. e.g. the "HiFi" use + * case verb will configure the audio hardware for HiFi Music playback + * and capture. + */ +#define SND_USE_CASE_VERB_INACTIVE "Inactive" +#define SND_USE_CASE_VERB_HIFI "HiFi" +#define SND_USE_CASE_VERB_HIFI_LOW_POWER "HiFi Low Power" +#define SND_USE_CASE_VERB_VOICE "Voice" +#define SND_USE_CASE_VERB_VOICE_LOW_POWER "Voice Low Power" +#define SND_USE_CASE_VERB_VOICECALL "Voice Call" +#define SND_USE_CASE_VERB_IP_VOICECALL "Voice Call IP" +#define SND_USE_CASE_VERB_ANALOG_RADIO "FM Analog Radio" +#define SND_USE_CASE_VERB_DIGITAL_RADIO "FM Digital Radio" +/* add new verbs to end of list */ + + +/* + * Use Case Device. + * + * Physical system devices the render and capture audio. Devices can be OR'ed + * together to support audio on simultaneous devices. + */ +#define SND_USE_CASE_DEV_NONE "None" +#define SND_USE_CASE_DEV_SPEAKER "Speaker" +#define SND_USE_CASE_DEV_LINE "Line" +#define SND_USE_CASE_DEV_HEADPHONES "Headphones" +#define SND_USE_CASE_DEV_HEADSET "Headset" +#define SND_USE_CASE_DEV_HANDSET "Handset" +#define SND_USE_CASE_DEV_BLUETOOTH "Bluetooth" +#define SND_USE_CASE_DEV_EARPIECE "Earpiece" +#define SND_USE_CASE_DEV_SPDIF "SPDIF" +#define SND_USE_CASE_DEV_HDMI "HDMI" +/* add new devices to end of list */ + + +/* + * Use Case Modifiers. + * + * The use case modifier allows runtime configuration changes to deal with + * asynchronous events. + * + * e.g. to record a voice call :- + * 1. Set verb to SND_USE_CASE_VERB_VOICECALL (for voice call) + * 2. Set modifier SND_USE_CASE_MOD_CAPTURE_VOICE when capture required. + * 3. Call snd_use_case_get("CapturePCM") to get ALSA source PCM name + * with captured voice pcm data. + * + * e.g. to play a ring tone when listenin to MP3 Music :- + * 1. Set verb to SND_USE_CASE_VERB_HIFI (for MP3 playback) + * 2. Set modifier to SND_USE_CASE_MOD_PLAY_TONE when incoming call happens. + * 3. Call snd_use_case_get("PlaybackPCM") to get ALSA PCM sink name for + * ringtone pcm data. + */ +#define SND_USE_CASE_MOD_CAPTURE_VOICE "Capture Voice" +#define SND_USE_CASE_MOD_CAPTURE_MUSIC "Capture Music" +#define SND_USE_CASE_MOD_PLAY_MUSIC "Play Music" +#define SND_USE_CASE_MOD_PLAY_VOICE "Play Voice" +#define SND_USE_CASE_MOD_PLAY_TONE "Play Tone" +#define SND_USE_CASE_MOD_ECHO_REF "Echo Reference" +/* add new modifiers to end of list */ + + +/** + * TQ - Tone Quality + * + * The interface allows clients to determine the audio TQ required for each + * use case verb and modifier. It's intended as an optional hint to the + * audio driver in order to lower power consumption. + * + */ +#define SND_USE_CASE_TQ_MUSIC "Music" +#define SND_USE_CASE_TQ_VOICE "Voice" +#define SND_USE_CASE_TQ_TONES "Tones" + +/** use case container */ +typedef struct snd_use_case_mgr snd_use_case_mgr_t; + +/** + * \brief Create an identifier + * \param fmt Format (sprintf like) + * \param ... Optional arguments for sprintf like format + * \return Allocated string identifier or NULL on error + */ +char *snd_use_case_identifier(const char *fmt, ...); + +/** + * \brief Free a string list + * \param list The string list to free + * \param items Count of strings + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_free_list(const char *list[], int items); + +/** + * \brief Obtain a list of entries + * \param uc_mgr Use case manager (may be NULL - card list) + * \param identifier (may be NULL - card list) + * \param list Returned allocated list + * \return Number of list entries if success, otherwise a negative error code + * + * Defined identifiers: + * NULL - get card list + * (in pair cardname+comment) + * _verbs - get verb list + * (in pair verb+comment) + * _devices[/] - get list of supported devices + * (in pair device+comment) + * _modifiers[/]- get list of supported modifiers + * (in pair modifier+comment) + * TQ[/] - get list of TQ identifiers + * _enadevs - get list of enabled devices + * _enamods - get list of enabled modifiers + * + * _supporteddevs/|[/] - list of supported devices + * _conflictingdevs/|[/] - list of conflicting devices + * Note that at most one of the supported/conflicting devs lists has + * any entries, and when neither is present, all devices are supported. + * + */ +int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char **list[]); + + +/** + * \brief Get current - string + * \param uc_mgr Use case manager + * \param identifier + * \param value Value pointer + * \return Zero if success, otherwise a negative error code + * + * Note: String is dynamically allocated, use free() to + * deallocate this string. + * + * Known identifiers: + * NULL - return current card + * _verb - return current verb + * + * [=][/[|][/]] + * - value identifier + * - Search starts at given modifier or device if any, + * else at a verb + * - Search starts at given verb if any, + * else current verb + * - Searches modifier/device, then verb, then defaults + * - Specify a leading "=" to search only the exact + * device/modifier/verb specified, and not search + * through each object in turn. + * - Examples: + * "PlaybackPCM/Play Music" + * "CapturePCM/SPDIF" + * From ValueDefaults only: + * "=Variable" + * From current active verb: + * "=Variable//" + * From verb "Verb": + * "=Variable//Verb" + * From "Modifier" in current active verb: + * "=Variable/Modifier/" + * From "Modifier" in "Verb": + * "=Variable/Modifier/Verb" + * + * Recommended names for values: + * TQ - Tone Quality + * PlaybackPCM - full PCM playback device name + * CapturePCM - full PCM capture device name + * PlaybackCTL - playback control device name + * PlaybackVolume - playback control volume ID string + * PlaybackSwitch - playback control switch ID string + * CaptureCTL - capture control device name + * CaptureVolume - capture control volume ID string + * CaptureSwitch - capture control switch ID string + * PlaybackMixer - name of playback mixer + * PlaybackMixerID - mixer playback ID + * CaptureMixer - name of capture mixer + * CaptureMixerID - mixer capture ID + */ +int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char **value); + +/** + * \brief Get current - integer + * \param uc_mgr Use case manager + * \param identifier + * \param value result + * \return Zero if success, otherwise a negative error code + * + * Known identifiers: + * _devstatus/ - return status for given device + * _modstatus/ - return status for given modifier + */ +int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + long *value); + +/** + * \brief Set new + * \param uc_mgr Use case manager + * \param identifier + * \param value Value + * \return Zero if success, otherwise a negative error code + * + * Known identifiers: + * _verb - set current verb = value + * _enadev - enable given device = value + * _disdev - disable given device = value + * _swdev/ - new_device = value + * - disable old_device and then enable new_device + * - if old_device is not enabled just return + * - check transmit sequence firstly + * _enamod - enable given modifier = value + * _dismod - disable given modifier = value + * _swmod/ - new_modifier = value + * - disable old_modifier and then enable new_modifier + * - if old_modifier is not enabled just return + * - check transmit sequence firstly + */ +int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char *value); + +/** + * \brief Open and initialise use case core for sound card + * \param uc_mgr Returned use case manager pointer + * \param card_name Sound card name. + * \return zero if success, otherwise a negative error code + */ +int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name); + + +/** + * \brief Reload and re-parse use case configuration files for sound card. + * \param uc_mgr Use case manager + * \return zero if success, otherwise a negative error code + */ +int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr); + +/** + * \brief Close use case manager + * \param uc_mgr Use case manager + * \return zero if success, otherwise a negative error code + */ +int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr); + +/** + * \brief Reset use case manager verb, device, modifier to deafult settings. + * \param uc_mgr Use case manager + * \return zero if success, otherwise a negative error code + */ +int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr); + +/* + * helper functions + */ + +/** + * \brief Obtain a list of cards + * \param list Returned allocated list + * \return Number of list entries if success, otherwise a negative error code + */ +static inline int snd_use_case_card_list(const char **list[]) +{ + return snd_use_case_get_list(NULL, NULL, list); +} + +/** + * \brief Obtain a list of verbs + * \param uc_mgr Use case manager + * \param list Returned list of verbs + * \return Number of list entries if success, otherwise a negative error code + */ +static inline int snd_use_case_verb_list(snd_use_case_mgr_t *uc_mgr, + const char **list[]) +{ + return snd_use_case_get_list(uc_mgr, "_verbs", list); +} + +/** + * \} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_USE_CASE_H */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..6781b98 --- /dev/null +++ b/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/ltconfig b/ltconfig new file mode 100644 index 0000000..e69de29 diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 0000000..d88da2c --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,8413 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6b +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="2.2.6b Debian-2.2.6b-2" +TIMESTAMP="" +package_revision=1.3017 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +# define setmode _setmode +#else +# include +# include +# ifdef __CYGWIN__ +# include +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : ""), + (value ? value : ""))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + + +EOF +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/m4/attributes.m4 b/m4/attributes.m4 new file mode 100644 index 0000000..e86456a --- /dev/null +++ b/m4/attributes.m4 @@ -0,0 +1,311 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2007 Diego Pettenò +dnl Copyright (c) 2006-2007 xine project +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if the flag is supported by compiler +dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ + AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([int a;], + [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl Check if the flag is supported by compiler (cacheable) +dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) +dnl Check for CFLAG and appends them to CFLAGS if supported +AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [CFLAGS="$CFLAGS $1"; $2], [$3]) +]) + +dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) +AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ + for flag in $1; do + CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([int main() { return 1; }], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable commandline, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([$3], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 0000000..a3fee53 --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,7377 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 0000000..34151a3 --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,368 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 new file mode 100644 index 0000000..9000a05 --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 new file mode 100644 index 0000000..f3c5309 --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 0000000..637bb20 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,92 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) diff --git a/missing b/missing new file mode 100755 index 0000000..28055d2 --- /dev/null +++ b/missing @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/modules/Makefile.am b/modules/Makefile.am new file mode 100644 index 0000000..bf9543e --- /dev/null +++ b/modules/Makefile.am @@ -0,0 +1,3 @@ +if BUILD_MIXER +SUBDIRS=mixer +endif diff --git a/modules/Makefile.in b/modules/Makefile.in new file mode 100644 index 0000000..00f4c68 --- /dev/null +++ b/modules/Makefile.in @@ -0,0 +1,570 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = modules +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = mixer +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@BUILD_MIXER_TRUE@SUBDIRS = mixer +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign modules/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/modules/mixer/Makefile.am b/modules/mixer/Makefile.am new file mode 100644 index 0000000..9f5917f --- /dev/null +++ b/modules/mixer/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=simple diff --git a/modules/mixer/Makefile.in b/modules/mixer/Makefile.in new file mode 100644 index 0000000..366bd67 --- /dev/null +++ b/modules/mixer/Makefile.in @@ -0,0 +1,570 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = modules/mixer +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = simple +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/mixer/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign modules/mixer/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/modules/mixer/simple/Makefile.am b/modules/mixer/simple/Makefile.am new file mode 100644 index 0000000..bad0944 --- /dev/null +++ b/modules/mixer/simple/Makefile.am @@ -0,0 +1,35 @@ +alsaplugindir = @ALSA_PLUGIN_DIR@ +pkglibdir = $(alsaplugindir)/smixer + +AM_CFLAGS = -g -O2 -W -Wall + +INCLUDES=-I$(top_srcdir)/include + +pkglib_LTLIBRARIES = smixer-sbase.la \ + smixer-ac97.la \ + smixer-hda.la + +if BUILD_PYTHON +pkglib_LTLIBRARIES += smixer-python.la +endif + +noinst_HEADERS = sbase.h + +smixer_sbase_la_SOURCES = sbase.c +smixer_sbase_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_sbase_la_LIBADD = ../../../src/libasound.la + +smixer_ac97_la_SOURCES = ac97.c sbasedl.c +smixer_ac97_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_ac97_la_LIBADD = ../../../src/libasound.la -ldl + +smixer_hda_la_SOURCES = hda.c sbasedl.c +smixer_hda_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_hda_la_LIBADD = ../../../src/libasound.la -ldl + +if BUILD_PYTHON +smixer_python_la_SOURCES = python.c +smixer_python_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_python_la_CFLAGS = $(PYTHON_INCLUDES) +smixer_python_la_LIBADD = ../../../src/libasound.la $(PYTHON_LIBS) +endif diff --git a/modules/mixer/simple/Makefile.in b/modules/mixer/simple/Makefile.in new file mode 100644 index 0000000..cef0f8b --- /dev/null +++ b/modules/mixer/simple/Makefile.in @@ -0,0 +1,616 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_PYTHON_TRUE@am__append_1 = smixer-python.la +subdir = modules/mixer/simple +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +smixer_ac97_la_DEPENDENCIES = ../../../src/libasound.la +am_smixer_ac97_la_OBJECTS = ac97.lo sbasedl.lo +smixer_ac97_la_OBJECTS = $(am_smixer_ac97_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +smixer_ac97_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(smixer_ac97_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +smixer_hda_la_DEPENDENCIES = ../../../src/libasound.la +am_smixer_hda_la_OBJECTS = hda.lo sbasedl.lo +smixer_hda_la_OBJECTS = $(am_smixer_hda_la_OBJECTS) +smixer_hda_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(smixer_hda_la_LDFLAGS) $(LDFLAGS) -o $@ +am__DEPENDENCIES_1 = +@BUILD_PYTHON_TRUE@smixer_python_la_DEPENDENCIES = \ +@BUILD_PYTHON_TRUE@ ../../../src/libasound.la \ +@BUILD_PYTHON_TRUE@ $(am__DEPENDENCIES_1) +am__smixer_python_la_SOURCES_DIST = python.c +@BUILD_PYTHON_TRUE@am_smixer_python_la_OBJECTS = \ +@BUILD_PYTHON_TRUE@ smixer_python_la-python.lo +smixer_python_la_OBJECTS = $(am_smixer_python_la_OBJECTS) +smixer_python_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(smixer_python_la_CFLAGS) $(CFLAGS) \ + $(smixer_python_la_LDFLAGS) $(LDFLAGS) -o $@ +@BUILD_PYTHON_TRUE@am_smixer_python_la_rpath = -rpath $(pkglibdir) +smixer_sbase_la_DEPENDENCIES = ../../../src/libasound.la +am_smixer_sbase_la_OBJECTS = sbase.lo +smixer_sbase_la_OBJECTS = $(am_smixer_sbase_la_OBJECTS) +smixer_sbase_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(smixer_sbase_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(smixer_ac97_la_SOURCES) $(smixer_hda_la_SOURCES) \ + $(smixer_python_la_SOURCES) $(smixer_sbase_la_SOURCES) +DIST_SOURCES = $(smixer_ac97_la_SOURCES) $(smixer_hda_la_SOURCES) \ + $(am__smixer_python_la_SOURCES_DIST) \ + $(smixer_sbase_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkglibdir = $(alsaplugindir)/smixer +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +alsaplugindir = @ALSA_PLUGIN_DIR@ +AM_CFLAGS = -g -O2 -W -Wall +INCLUDES = -I$(top_srcdir)/include +pkglib_LTLIBRARIES = smixer-sbase.la smixer-ac97.la smixer-hda.la \ + $(am__append_1) +noinst_HEADERS = sbase.h +smixer_sbase_la_SOURCES = sbase.c +smixer_sbase_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_sbase_la_LIBADD = ../../../src/libasound.la +smixer_ac97_la_SOURCES = ac97.c sbasedl.c +smixer_ac97_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_ac97_la_LIBADD = ../../../src/libasound.la -ldl +smixer_hda_la_SOURCES = hda.c sbasedl.c +smixer_hda_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +smixer_hda_la_LIBADD = ../../../src/libasound.la -ldl +@BUILD_PYTHON_TRUE@smixer_python_la_SOURCES = python.c +@BUILD_PYTHON_TRUE@smixer_python_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) +@BUILD_PYTHON_TRUE@smixer_python_la_CFLAGS = $(PYTHON_INCLUDES) +@BUILD_PYTHON_TRUE@smixer_python_la_LIBADD = ../../../src/libasound.la $(PYTHON_LIBS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/mixer/simple/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign modules/mixer/simple/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +smixer-ac97.la: $(smixer_ac97_la_OBJECTS) $(smixer_ac97_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_ac97_la_LINK) -rpath $(pkglibdir) $(smixer_ac97_la_OBJECTS) $(smixer_ac97_la_LIBADD) $(LIBS) +smixer-hda.la: $(smixer_hda_la_OBJECTS) $(smixer_hda_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_hda_la_LINK) -rpath $(pkglibdir) $(smixer_hda_la_OBJECTS) $(smixer_hda_la_LIBADD) $(LIBS) +smixer-python.la: $(smixer_python_la_OBJECTS) $(smixer_python_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_python_la_LINK) $(am_smixer_python_la_rpath) $(smixer_python_la_OBJECTS) $(smixer_python_la_LIBADD) $(LIBS) +smixer-sbase.la: $(smixer_sbase_la_OBJECTS) $(smixer_sbase_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_sbase_la_LINK) -rpath $(pkglibdir) $(smixer_sbase_la_OBJECTS) $(smixer_sbase_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ac97.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hda.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbase.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbasedl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smixer_python_la-python.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +smixer_python_la-python.lo: python.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smixer_python_la_CFLAGS) $(CFLAGS) -MT smixer_python_la-python.lo -MD -MP -MF $(DEPDIR)/smixer_python_la-python.Tpo -c -o smixer_python_la-python.lo `test -f 'python.c' || echo '$(srcdir)/'`python.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/smixer_python_la-python.Tpo $(DEPDIR)/smixer_python_la-python.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='python.c' object='smixer_python_la-python.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smixer_python_la_CFLAGS) $(CFLAGS) -c -o smixer_python_la-python.lo `test -f 'python.c' || echo '$(srcdir)/'`python.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/modules/mixer/simple/ac97.c b/modules/mixer/simple/ac97.c new file mode 100644 index 0000000..ddb6143 --- /dev/null +++ b/modules/mixer/simple/ac97.c @@ -0,0 +1,89 @@ +/* + * Mixer Interface - AC97 simple abstact module + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "asoundlib.h" +#include "mixer_abst.h" +#include "sbase.h" + +static struct sm_elem_ops simple_ac97_ops; + +struct melem_sids sids[] = { + { + .sid = SID_MASTER, + .sname = "Master", + .sindex = 0, + .weight = 1, + .chanmap = { 3, 0 }, + .sops = &simple_ac97_ops, + } +}; + +#define SELECTORS (sizeof(selectors)/sizeof(selectors[0])) + +struct helem_selector selectors[] = { + { + .iface = SND_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .index = 0, + .sid = SID_MASTER, + .purpose = PURPOSE_VOLUME, + .caps = SM_CAP_PVOLUME, + }, + { + .iface = SND_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .index = 0, + .sid = SID_MASTER, + .purpose = PURPOSE_SWITCH, + .caps = SM_CAP_PSWITCH, + } +}; + +int alsa_mixer_simple_event(snd_mixer_class_t *class, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + return priv->ops.event(class, mask, helem, melem); +} + +int alsa_mixer_simple_init(snd_mixer_class_t *class) +{ + struct bclass_base_ops *ops; + int err; + + err = mixer_simple_basic_dlopen(class, &ops); + if (err < 0) + return 0; + err = ops->selreg(class, selectors, SELECTORS); + if (err < 0) + return err; + err = ops->sidreg(class, sids, SELECTORS); + if (err < 0) + return err; + return 0; +} diff --git a/modules/mixer/simple/hda.c b/modules/mixer/simple/hda.c new file mode 100644 index 0000000..13c931a --- /dev/null +++ b/modules/mixer/simple/hda.c @@ -0,0 +1,90 @@ +/* + * Mixer Interface - HDA simple abstact module + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "asoundlib.h" +#include "mixer_abst.h" +#include "sbase.h" + +static struct sm_elem_ops simple_hda_ops; + +struct melem_sids sids[] = { + { + .sid = SID_FRONT, + .sname = "Front", + .sindex = 0, + .weight = 1, + .chanmap = { 3, 0 }, + .sops = &simple_hda_ops, + } +}; + +#define SELECTORS (sizeof(selectors)/sizeof(selectors[0])) + +struct helem_selector selectors[] = { + { + .iface = SND_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Volume", + .index = 0, + .sid = SID_FRONT, + .purpose = PURPOSE_VOLUME, + .caps = SM_CAP_PVOLUME, + }, + { + .iface = SND_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Switch", + .index = 0, + .sid = SID_FRONT, + .purpose = PURPOSE_SWITCH, + .caps = SM_CAP_PSWITCH, + } +}; + +int alsa_mixer_simple_event(snd_mixer_class_t *class, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + return priv->ops.event(class, mask, helem, melem); +} + +int alsa_mixer_simple_init(snd_mixer_class_t *class) +{ + struct bclass_base_ops *ops; + int err; + + err = mixer_simple_basic_dlopen(class, &ops); + if (err < 0) + return 0; + err = ops->selreg(class, selectors, SELECTORS); + if (err < 0) + return err; + err = ops->sidreg(class, sids, SELECTORS); + if (err < 0) + return err; + return 0; +} diff --git a/modules/mixer/simple/python.c b/modules/mixer/simple/python.c new file mode 100644 index 0000000..c822c52 --- /dev/null +++ b/modules/mixer/simple/python.c @@ -0,0 +1,1046 @@ +/* + * Mixer Interface - python binding simple abstact module + * Copyright (c) 2007 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "Python.h" +#include +#include "config.h" +#include "asoundlib.h" +#include "mixer_abst.h" + +struct python_priv { + int py_initialized; + PyObject *py_event_func; + PyObject *py_mdict; + PyObject *py_mixer; +}; + +#define SCRIPT ALSA_PLUGIN_DIR "/smixer/python/main.py" + +struct pymelem { + PyObject_HEAD + sm_selem_t selem; + PyObject *py_mixer; + snd_mixer_elem_t *melem; +}; + +struct pymixer { + PyObject_HEAD + snd_mixer_class_t *class; + snd_mixer_t *mixer; + PyObject *mdict; + int hctl_count; + void **hctl; + int helem_count; + void **helem; + int melem_count; + void **melem; +}; + +static PyInterpreterState *main_interpreter; + +static void *get_C_ptr(PyObject *obj, const char *attr) +{ + PyObject *o; + + o = PyObject_GetAttr(obj, PyString_InternFromString(attr)); + if (!o) { + PyErr_Format(PyExc_TypeError, "missing '%s' attribute", attr); + return NULL; + } + if (!PyInt_Check(o)) { + PyErr_Format(PyExc_TypeError, "'%s' attribute is not integer", attr); + return NULL; + } + return (void *)PyInt_AsLong(o); +} + +static struct pymelem *melem_to_pymelem(snd_mixer_elem_t *elem) +{ + return (struct pymelem *)((char *)snd_mixer_elem_get_private(elem) - offsetof(struct pymelem, selem)); +} + +static int pcall(struct pymelem *pymelem, const char *attr, PyObject *args, PyObject **_res) +{ + PyObject *obj = (PyObject *)pymelem, *res; + int xres = 0; + + if (_res) + *_res = NULL; + obj = PyObject_GetAttr(obj, PyString_InternFromString(attr)); + if (!obj) { + PyErr_Format(PyExc_TypeError, "missing '%s' attribute", attr); + PyErr_Print(); + PyErr_Clear(); + Py_DECREF(args); + return -EIO; + } + res = PyObject_CallObject(obj, args); + Py_XDECREF(args); + if (res == NULL) { + PyErr_Print(); + PyErr_Clear(); + return -EIO; + } + if (_res && PyTuple_Check(res)) { + *_res = res; + res = PyTuple_GetItem(res, 0); + } + if (PyInt_Check(res)) { + xres = PyInt_AsLong(res); + } else if (res == Py_None) { + xres = 0; + } else if (PyBool_Check(res)) { + xres = res == Py_True; + } else { + PyErr_Format(PyExc_TypeError, "wrong result from '%s'!", attr); + PyErr_Print(); + PyErr_Clear(); + Py_DECREF(res); + if (_res) + *_res = NULL; + return -EIO; + } + if (_res && *_res) + return xres; + Py_DECREF(res); + return xres; +} + +static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) +{ + PyObject *obj1; + struct pymelem *pymelem = melem_to_pymelem(elem); + char *s, fcn[32] = "opsIs"; + int res, xdir = 1, xval = 0; + + switch (cmd) { + case SM_OPS_IS_ACTIVE: s = "Active"; xdir = 0; break; + case SM_OPS_IS_MONO: s = "Mono"; break; + case SM_OPS_IS_CHANNEL: s = "Channel"; xval = 1; break; + case SM_OPS_IS_ENUMERATED: s = "Enumerated"; xdir = val == 1; break; + case SM_OPS_IS_ENUMCNT: s = "EnumCnt"; break; + default: + return 1; + } + strcat(fcn, s); + + obj1 = PyTuple_New(xdir + xval); + if (xdir) { + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + if (xval) + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(val)); + } + res = pcall(pymelem, fcn, obj1, NULL); + return res < 0 ? 0 : res; +} + +static int get_x_range_ops(snd_mixer_elem_t *elem, int dir, + long *min, long *max, const char *attr) +{ + PyObject *obj1, *res; + struct pymelem *pymelem = melem_to_pymelem(elem); + int err; + + obj1 = PyTuple_New(1); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + err = pcall(pymelem, attr, obj1, &res); + if (err >= 0) { + err = !PyInt_Check(PyTuple_GetItem(res, 1)) || !PyInt_Check(PyTuple_GetItem(res, 2)); + if (err) { + err = !PyLong_Check(PyTuple_GetItem(res, 1)) || !PyLong_Check(PyTuple_GetItem(res, 2)); + if (err) { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } else { + *min = PyLong_AsLong(PyTuple_GetItem(res, 1)); + *max = PyLong_AsLong(PyTuple_GetItem(res, 2)); + } + } else { + *min = PyInt_AsLong(PyTuple_GetItem(res, 1)); + *max = PyInt_AsLong(PyTuple_GetItem(res, 2)); + } + } + Py_XDECREF(res); + return err; +} + +static int get_range_ops(snd_mixer_elem_t *elem, int dir, + long *min, long *max) +{ + return get_x_range_ops(elem, dir, min, max, "opsGetRange"); +} + +static int set_range_ops(snd_mixer_elem_t *elem, int dir, + long min, long max) +{ + PyObject *obj1; + struct pymelem *pymelem = melem_to_pymelem(elem); + + obj1 = PyTuple_New(3); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(min)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(max)); + return pcall(pymelem, "opsGetRange", obj1, NULL); +} + +static int get_x_ops(snd_mixer_elem_t *elem, int dir, + long channel, long *value, + const char *attr) +{ + PyObject *obj1, *res; + struct pymelem *pymelem = melem_to_pymelem(elem); + int err; + + obj1 = PyTuple_New(2); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel)); + err = pcall(pymelem, attr, obj1, &res); + if (err >= 0) { + err = !PyInt_Check(PyTuple_GetItem(res, 1)); + if (err) { + err = !PyLong_Check(PyTuple_GetItem(res, 1)); + if (err) { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } else { + *value = PyLong_AsLong(PyTuple_GetItem(res, 1)); + } + } else { + *value = PyInt_AsLong(PyTuple_GetItem(res, 1)); + } + } + Py_XDECREF(res); + return err; +} + +static int get_volume_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, long *value) +{ + return get_x_ops(elem, dir, channel, value, "opsGetVolume"); +} + +static int get_switch_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, int *value) +{ + long value1; + int res; + res = get_x_ops(elem, dir, channel, &value1, "opsGetSwitch"); + *value = value1; + return res; +} + +static int ask_vol_dB_ops(snd_mixer_elem_t *elem, + int dir, + long value, + long *dbValue) +{ + return get_x_ops(elem, dir, value, dbValue, "opsGetVolDB"); +} + +static int ask_dB_vol_ops(snd_mixer_elem_t *elem, + int dir, + long value, + long *dbValue, + int xdir) +{ + PyObject *obj1, *res; + struct pymelem *pymelem = melem_to_pymelem(elem); + int err; + + obj1 = PyTuple_New(3); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(value)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(xdir)); + err = pcall(pymelem, "opsGetDBVol", obj1, &res); + if (err >= 0) { + err = !PyInt_Check(PyTuple_GetItem(res, 1)); + if (err) { + err = !PyLong_Check(PyTuple_GetItem(res, 1)); + if (err) { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } else { + *dbValue = PyLong_AsLong(PyTuple_GetItem(res, 1)); + } + } else { + *dbValue = PyInt_AsLong(PyTuple_GetItem(res, 1)); + } + } + Py_XDECREF(res); + return err; +} + +static int get_dB_ops(snd_mixer_elem_t *elem, + int dir, + snd_mixer_selem_channel_id_t channel, + long *value) +{ + return get_x_ops(elem, dir, channel, value, "opsGetDB"); +} + +static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir, + long *min, long *max) +{ + return get_x_range_ops(elem, dir, min, max, "opsGetDBRange"); +} + +static int set_volume_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, long value) +{ + PyObject *obj1; + struct pymelem *pymelem = melem_to_pymelem(elem); + + obj1 = PyTuple_New(3); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(value)); + return pcall(pymelem, "opsSetVolume", obj1, NULL); +} + +static int set_switch_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, int value) +{ + PyObject *obj1; + struct pymelem *pymelem = melem_to_pymelem(elem); + + obj1 = PyTuple_New(3); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(value)); + return pcall(pymelem, "opsSetSwitch", obj1, NULL); +} + +static int set_dB_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, + long db_gain, int xdir) +{ + PyObject *obj1; + struct pymelem *pymelem = melem_to_pymelem(elem); + + obj1 = PyTuple_New(4); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(dir)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(channel)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(db_gain)); + PyTuple_SET_ITEM(obj1, 3, PyInt_FromLong(xdir)); + return pcall(pymelem, "opsSetDB", obj1, NULL); +} + +static int enum_item_name_ops(snd_mixer_elem_t *elem, + unsigned int item, + size_t maxlen, char *buf) +{ + PyObject *obj1, *res; + struct pymelem *pymelem = melem_to_pymelem(elem); + int err; + unsigned int len; + char *s; + + obj1 = PyTuple_New(1); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(item)); + err = pcall(pymelem, "opsGetEnumItemName", obj1, &res); + if (err >= 0) { + err = !PyString_Check(PyTuple_GetItem(res, 1)); + if (err) { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } else { + s = PyString_AsString(PyTuple_GetItem(res, 1)); + len = strlen(s); + if (maxlen - 1 > len) + len = maxlen - 1; + memcpy(buf, s, len); + buf[len] = '\0'; + } + } + Py_XDECREF(res); + return err; +} + +static int get_enum_item_ops(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int *itemp) +{ + PyObject *obj1, *res; + struct pymelem *pymelem = melem_to_pymelem(elem); + int err; + + obj1 = PyTuple_New(1); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(channel)); + err = pcall(pymelem, "opsGetEnumItem", obj1, &res); + if (err >= 0) { + err = !PyInt_Check(PyTuple_GetItem(res, 1)); + if (err) { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } else { + *itemp = PyInt_AsLong(PyTuple_GetItem(res, 1)); + } + } + Py_XDECREF(res); + return err; +} + +static int set_enum_item_ops(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int item) +{ + PyObject *obj1; + struct pymelem *pymelem = melem_to_pymelem(elem); + + obj1 = PyTuple_New(2); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong(channel)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong(item)); + return pcall(pymelem, "opsSetEnumItem", obj1, NULL); +} + +static struct sm_elem_ops simple_python_ops = { + .is = is_ops, + .get_range = get_range_ops, + .get_dB_range = get_dB_range_ops, + .set_range = set_range_ops, + .ask_vol_dB = ask_vol_dB_ops, + .ask_dB_vol = ask_dB_vol_ops, + .get_volume = get_volume_ops, + .get_dB = get_dB_ops, + .set_volume = set_volume_ops, + .set_dB = set_dB_ops, + .get_switch = get_switch_ops, + .set_switch = set_switch_ops, + .enum_item_name = enum_item_name_ops, + .get_enum_item = get_enum_item_ops, + .set_enum_item = set_enum_item_ops +}; + +static void selem_free(snd_mixer_elem_t *elem) +{ + sm_selem_t *simple = snd_mixer_elem_get_private(elem); + + if (simple->id) { + snd_mixer_selem_id_free(simple->id); + simple->id = NULL; + } +} + +static PyObject * +pymelem_cap(struct pymelem *pymelem ATTRIBUTE_UNUSED, void *priv) +{ + return PyInt_FromLong((long)priv); +} + +static PyObject * +pymelem_get_caps(struct pymelem *pymelem, void *priv ATTRIBUTE_UNUSED) +{ + return PyInt_FromLong(pymelem->selem.caps); +} + +static PyObject * +pymelem_get_name(struct pymelem *pymelem, void *priv ATTRIBUTE_UNUSED) +{ + return PyString_FromString(snd_mixer_selem_id_get_name(pymelem->selem.id)); +} + +static PyObject * +pymelem_get_index(struct pymelem *pymelem, void *priv ATTRIBUTE_UNUSED) +{ + return PyInt_FromLong(snd_mixer_selem_id_get_index(pymelem->selem.id)); +} + +static int +pymelem_set_caps(struct pymelem *pymelem, PyObject *val, void *priv ATTRIBUTE_UNUSED) +{ + if (!PyInt_Check(val)) { + PyErr_SetString(PyExc_TypeError, "The last attribute value must be an integer"); + return -1; + } + pymelem->selem.caps = PyInt_AsLong(val); + return 0; +} + +static PyObject * +pymelem_ignore(struct pymelem *pymelem ATTRIBUTE_UNUSED, PyObject *args ATTRIBUTE_UNUSED) +{ + Py_RETURN_NONE; +} + +static PyObject * +pymelem_ignore1(struct pymelem *pymelem ATTRIBUTE_UNUSED, PyObject *args ATTRIBUTE_UNUSED) +{ + Py_RETURN_TRUE; +} + +static PyObject * +pymelem_error(struct pymelem *pymelem ATTRIBUTE_UNUSED, PyObject *args ATTRIBUTE_UNUSED) +{ + return PyInt_FromLong(-EIO); +} + +static PyObject * +pymelem_attach(struct pymelem *pymelem, PyObject *args) +{ + PyObject *obj; + snd_hctl_elem_t *helem; + int err; + + if (!PyArg_ParseTuple(args, "O", &obj)) + return NULL; + helem = (snd_hctl_elem_t *)get_C_ptr(obj, "get_C_helem"); + if (helem == NULL) + return NULL; + err = snd_mixer_elem_attach(pymelem->melem, helem); + if (err < 0) { + PyErr_Format(PyExc_RuntimeError, "Cannot attach hcontrol element to mixer element: %s", snd_strerror(err)); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +pymelem_detach(struct pymelem *pymelem, PyObject *args) +{ + PyObject *obj; + snd_hctl_elem_t *helem; + int err; + + if (!PyArg_ParseTuple(args, "O", &obj)) + return NULL; + helem = (snd_hctl_elem_t *)get_C_ptr(obj, "get_C_helem"); + if (helem == NULL) + return NULL; + err = snd_mixer_elem_detach(pymelem->melem, helem); + if (err < 0) { + PyErr_Format(PyExc_RuntimeError, "Cannot detach hcontrol element to mixer element: %s", snd_strerror(err)); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +pymelem_event_info(struct pymelem *pymelem, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + return PyInt_FromLong(snd_mixer_elem_info(pymelem->melem)); +} + +static PyObject * +pymelem_event_value(struct pymelem *pymelem, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + return PyInt_FromLong(snd_mixer_elem_value(pymelem->melem)); +} + +static int +pymelem_init(struct pymelem *pymelem, PyObject *args, PyObject *kwds ATTRIBUTE_UNUSED) +{ + char *name; + long index, weight; + snd_mixer_selem_id_t *id; + int err; + + if (!PyArg_ParseTuple(args, "Osii", &pymelem->py_mixer, &name, &index, &weight)) + return -1; + memset(&pymelem->selem, 0, sizeof(pymelem->selem)); + if (snd_mixer_selem_id_malloc(&id)) + return -1; + snd_mixer_selem_id_set_name(id, name); + snd_mixer_selem_id_set_index(id, index); + pymelem->selem.id = id; + pymelem->selem.ops = &simple_python_ops; + err = snd_mixer_elem_new(&pymelem->melem, SND_MIXER_ELEM_SIMPLE, + weight, &pymelem->selem, selem_free); + if (err < 0) { + snd_mixer_selem_id_free(id); + return -1; + } + return 0; +} + +static void +pymelem_dealloc(struct pymelem *self) +{ + selem_free(self->melem); + self->ob_type->tp_free(self); +} + +static PyGetSetDef pymelem_getseters[] = { + {"CAP_GVOLUME", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_GVOLUME}, + {"CAP_GSWITCH", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_GSWITCH}, + {"CAP_PVOLUME", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PVOLUME}, + {"CAP_PVOLUME_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PVOLUME_JOIN}, + {"CAP_PSWITCH", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PSWITCH}, + {"CAP_PSWITCH_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PSWITCH_JOIN}, + {"CAP_CVOLUME", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CVOLUME}, + {"CAP_CVOLUME_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CVOLUME_JOIN}, + {"CAP_CSWITCH", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CSWITCH}, + {"CAP_CSWITCH_JOIN", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CSWITCH_JOIN}, + {"CAP_CSWITCH_EXCL", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CSWITCH_EXCL}, + {"CAP_PENUM", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_PENUM}, + {"CAP_CENUM", (getter)pymelem_cap, NULL, NULL, (void *)SM_CAP_CENUM}, + + {"caps", (getter)pymelem_get_caps, (setter)pymelem_set_caps, NULL, NULL}, + + {"name", (getter)pymelem_get_name, NULL, NULL, NULL}, + {"index", (getter)pymelem_get_index, NULL, NULL, NULL}, + + {NULL,NULL,NULL,NULL,NULL} +}; + +static PyMethodDef pymelem_methods[] = { + {"attach", (PyCFunction)pymelem_attach, METH_VARARGS, NULL}, + {"detach", (PyCFunction)pymelem_detach, METH_VARARGS, NULL}, + + /* "default" functions - no functionality */ + {"opsIsActive", (PyCFunction)pymelem_ignore1, METH_VARARGS, NULL}, + {"opsIsMono", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL}, + {"opsIsChannel", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL}, + {"opsIsEnumerated", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL}, + {"opsIsEnumCnt", (PyCFunction)pymelem_ignore, METH_VARARGS, NULL}, + + {"opsGetDB", (PyCFunction)pymelem_error, METH_VARARGS, NULL}, + + {"eventInfo", (PyCFunction)pymelem_event_info, METH_VARARGS, NULL}, + {"eventValue", (PyCFunction)pymelem_event_value, METH_VARARGS, NULL}, + + {NULL,NULL,0,NULL} +}; + +static PyTypeObject pymelem_type = { + PyObject_HEAD_INIT(0) + tp_name: "smixer_python.InternalMElement", + tp_basicsize: sizeof(struct pymelem), + tp_dealloc: (destructor)pymelem_dealloc, + tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + tp_doc: NULL /* mixerinit__doc__ */, + tp_getset: pymelem_getseters, + tp_init: (initproc)pymelem_init, + tp_alloc: PyType_GenericAlloc, + tp_new: PyType_GenericNew, + tp_free: PyObject_Del, + tp_methods: pymelem_methods, +}; + +static PyObject * +pymixer_attach_hctl(struct pymixer *pymixer, PyObject *args) +{ + PyObject *obj; + snd_hctl_t *hctl; + void **hctls; + int err; + + if (!PyArg_ParseTuple(args, "O", &obj)) + return NULL; + hctl = (snd_hctl_t *)get_C_ptr(obj, "get_C_hctl"); + if (hctl == NULL) + return NULL; + err = snd_mixer_attach_hctl(pymixer->mixer, hctl); + if (err < 0) { + PyErr_Format(PyExc_RuntimeError, "Cannot attach hctl: %s", snd_strerror(err)); + return NULL; + } + hctls = realloc(pymixer->hctl, sizeof(void *) * (pymixer->hctl_count+1) * 2); + if (hctls == NULL) { + PyErr_SetString(PyExc_RuntimeError, "No enough memory"); + return NULL; + } + pymixer->hctl = hctls; + pymixer->hctl[pymixer->hctl_count*2] = (void *)hctl; + pymixer->hctl[pymixer->hctl_count*2+1] = (void *)obj; + pymixer->hctl_count++; + Py_INCREF(obj); + Py_RETURN_NONE; +} + +static PyObject * +pymixer_register(struct pymixer *pymixer, PyObject *args) +{ + int err; + + if (!PyArg_ParseTuple(args, "")) + return NULL; + err = snd_mixer_class_register(pymixer->class, pymixer->mixer); + if (err < 0) { + PyErr_Format(PyExc_RuntimeError, "Cannot register mixer: %s", snd_strerror(err)); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +pymixer_melement_new(struct pymixer *pymixer, PyObject *args) +{ + PyObject *obj, *obj1, *obj2; + char *class, *name; + long index, weight; + + if (!PyArg_ParseTuple(args, "ssii", &class, &name, &index, &weight)) + return NULL; + obj = PyDict_GetItemString(pymixer->mdict, class); + if (obj) { + obj1 = PyTuple_New(4); + if (PyTuple_SET_ITEM(obj1, 0, (PyObject *)pymixer)) + Py_INCREF((PyObject *)pymixer); + PyTuple_SET_ITEM(obj1, 1, PyString_FromString(name)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong(index)); + PyTuple_SET_ITEM(obj1, 3, PyInt_FromLong(weight)); + obj2 = PyObject_CallObject(obj, obj1); + Py_XDECREF(obj1); + if (obj2) { + struct pymelem *pymelem = (struct pymelem *)obj2; + void **melems = realloc(pymixer->melem, sizeof(void *) * (pymixer->melem_count + 1) * 2); + if (melems == NULL) { + Py_DECREF(obj2); + return NULL; + } + melems[pymixer->melem_count*2] = pymelem->melem; + melems[pymixer->melem_count*2+1] = obj2; + Py_INCREF(obj2); + pymixer->melem = melems; + pymixer->melem_count++; + } + } else { + PyErr_Format(PyExc_RuntimeError, "Cannot find class '%s'", class); + return NULL; + } + return obj2; +} + +static PyObject * +pymixer_melement_add(struct pymixer *pymixer, PyObject *args) +{ + PyObject *obj; + struct pymelem *pymelem; + int err; + + if (!PyArg_ParseTuple(args, "O", &obj)) + return NULL; + pymelem = (struct pymelem *)obj; + err = snd_mixer_elem_add(pymelem->melem, pymixer->class); + if (err < 0) { + PyErr_Format(PyExc_RuntimeError, "Cannot add mixer element: %s", snd_strerror(err)); + return NULL; + } + Py_RETURN_NONE; +} + +static int +pymixer_init(struct pymixer *pymixer, PyObject *args, PyObject *kwds ATTRIBUTE_UNUSED) +{ + long class, mixer; + + if (!PyArg_ParseTuple(args, "iiO", &class, &mixer, &pymixer->mdict)) + return -1; + pymixer->class = (snd_mixer_class_t *)class; + pymixer->mixer = (snd_mixer_t *)mixer; + pymixer->hctl_count = 0; + pymixer->hctl = NULL; + pymixer->helem_count = 0; + pymixer->helem = NULL; + pymixer->melem_count = 0; + pymixer->melem = NULL; + return 0; +} + +static void +pymixer_free(struct pymixer *self) +{ + int idx; + + for (idx = 0; idx < self->hctl_count; idx++) { + snd_mixer_detach_hctl(self->mixer, self->hctl[idx*2]); + Py_DECREF((PyObject *)self->hctl[idx*2+1]); + } + if (self->hctl) + free(self->hctl); + self->hctl_count = 0; + self->hctl = NULL; + for (idx = 0; idx < self->helem_count; idx++) + Py_DECREF((PyObject *)self->helem[idx*2+1]); + if (self->helem) + free(self->helem); + self->helem_count = 0; + self->helem = NULL; + for (idx = 0; idx < self->melem_count; idx++) + Py_DECREF((PyObject *)self->melem[idx*2+1]); + if (self->melem) + free(self->melem); + self->melem_count = 0; + self->melem = NULL; +} + +static void +pymixer_dealloc(struct pymixer *self) +{ + pymixer_free(self); + self->ob_type->tp_free(self); +} + +static PyGetSetDef pymixer_getseters[] = { + {NULL,NULL,NULL,NULL,NULL} +}; + +static PyMethodDef pymixer_methods[] = { + {"attachHCtl", (PyCFunction)pymixer_attach_hctl, METH_VARARGS, NULL}, + {"register", (PyCFunction)pymixer_register, METH_VARARGS, NULL}, + {"newMElement", (PyCFunction)pymixer_melement_new, METH_VARARGS, NULL}, + {"addMElement", (PyCFunction)pymixer_melement_add, METH_VARARGS, NULL}, + {NULL,NULL,0,NULL} +}; + +static PyTypeObject pymixer_type = { + PyObject_HEAD_INIT(0) + tp_name: "smixer_python.InternalMixer", + tp_basicsize: sizeof(struct pymixer), + tp_dealloc: (destructor)pymixer_dealloc, + tp_flags: Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + tp_doc: NULL /* mixerinit__doc__ */, + tp_getset: pymixer_getseters, + tp_init: (initproc)pymixer_init, + tp_alloc: PyType_GenericAlloc, + tp_new: PyType_GenericNew, + tp_free: PyObject_Del, + tp_methods: pymixer_methods, +}; + +static PyMethodDef python_methods[] = { + {NULL, NULL, 0, NULL} +}; + +static PyObject *new_helem(struct python_priv *priv, snd_hctl_elem_t *helem) +{ + PyObject *obj, *py_hctl = NULL, *obj1, *obj2; + snd_hctl_t *hctl = snd_hctl_elem_get_hctl(helem); + struct pymixer *pymixer = (struct pymixer *)priv->py_mixer; + int idx; + + for (idx = 0; idx < pymixer->hctl_count; idx++) { + if (pymixer->hctl[idx] == hctl) { + py_hctl = pymixer->hctl[idx*2+1]; + break; + } + } + if (py_hctl == NULL) + return NULL; + obj = PyDict_GetItemString(priv->py_mdict, "HElement"); + if (obj) { + obj1 = PyTuple_New(3); + if (PyTuple_SET_ITEM(obj1, 0, py_hctl)) + Py_INCREF(py_hctl); + PyTuple_SET_ITEM(obj1, 1, PyFloat_FromDouble(1)); + PyTuple_SET_ITEM(obj1, 2, PyInt_FromLong((long)helem)); + obj2 = PyObject_CallObject(obj, obj1); + if (obj2 == NULL) { + PyErr_Print(); + PyErr_Clear(); + } + Py_XDECREF(obj1); + } else { + SNDERR("Unable to create InternalMixer object"); + return NULL; + } + if (obj2) { + struct pymixer *pymixer = (struct pymixer *)priv->py_mixer; + void **helems = realloc(pymixer->helem, sizeof(void *) * (pymixer->helem_count + 1) * 2); + if (helems == NULL) { + Py_DECREF(obj2); + return NULL; + } + helems[pymixer->helem_count*2] = helem; + helems[pymixer->helem_count*2+1] = obj2; + Py_INCREF(obj2); + pymixer->helem = helems; + pymixer->helem_count++; + } + return obj2; +} + +static PyObject *find_helem(struct python_priv *priv, snd_hctl_elem_t *helem) +{ + struct pymixer *pymixer = (struct pymixer *)priv->py_mixer; + int idx; + + for (idx = 0; idx < pymixer->helem_count; idx++) { + if (pymixer->helem[idx*2] == helem) + return (PyObject *)pymixer->helem[idx*2+1]; + } + return NULL; +} + +static PyObject *find_melem(struct python_priv *priv, snd_mixer_elem_t *melem) +{ + struct pymixer *pymixer = (struct pymixer *)priv->py_mixer; + int idx; + + for (idx = 0; idx < pymixer->melem_count; idx++) { + if (pymixer->melem[idx*2] == melem) + return (PyObject *)pymixer->melem[idx*2+1]; + } + return NULL; +} + +int alsa_mixer_simple_event(snd_mixer_class_t *class, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) +{ + struct python_priv *priv = snd_mixer_sbasic_get_private(class); + PyThreadState *tstate, *origstate; + PyObject *t, *o, *r; + int res = -ENOMEM; + + tstate = PyThreadState_New(main_interpreter); + origstate = PyThreadState_Swap(tstate); + + t = PyTuple_New(3); + if (t) { + PyTuple_SET_ITEM(t, 0, (PyObject *)PyInt_FromLong(mask)); + o = find_helem(priv, helem); + if (mask & SND_CTL_EVENT_MASK_ADD) { + if (o == NULL) + o = new_helem(priv, helem); + } + if (o == NULL) + return 0; + if (PyTuple_SET_ITEM(t, 1, o)) + Py_INCREF(o); + o = melem ? find_melem(priv, melem) : Py_None; + if (PyTuple_SET_ITEM(t, 2, o)) + Py_INCREF(o); + r = PyObject_CallObject(priv->py_event_func, t); + Py_DECREF(t); + if (r) { + if (PyInt_Check(r)) { + res = PyInt_AsLong(r); + } else if (r == Py_None) { + res = 0; + } + Py_DECREF(r); + } else { + PyErr_Print(); + PyErr_Clear(); + res = -EIO; + } + } + + return res; +} + +static void alsa_mixer_simple_free(snd_mixer_class_t *class) +{ + struct python_priv *priv = snd_mixer_sbasic_get_private(class); + + if (priv->py_mixer) { + pymixer_free((struct pymixer *)priv->py_mixer); + Py_DECREF(priv->py_mixer); + } + if (priv->py_initialized) { + Py_XDECREF(priv->py_event_func); + Py_Finalize(); + } + free(priv); +} + +int alsa_mixer_simple_finit(snd_mixer_class_t *class, + snd_mixer_t *mixer, + const char *device) +{ + struct python_priv *priv; + FILE *fp; + const char *file; + PyObject *obj, *obj1, *obj2, *py_mod, *mdict; + + priv = calloc(1, sizeof(*priv)); + if (priv == NULL) + return -ENOMEM; + + snd_mixer_sbasic_set_private(class, priv); + snd_mixer_sbasic_set_private_free(class, alsa_mixer_simple_free); + + file = getenv("ALSA_MIXER_SIMPLE_MPYTHON"); + if (file == NULL) + file = SCRIPT; + + fp = fopen(file, "r"); + if (fp == NULL) { + SNDERR("Unable to find python module '%s'", file); + return -ENODEV; + } + + Py_Initialize(); + if (PyType_Ready(&pymelem_type) < 0) + return -EIO; + if (PyType_Ready(&pymixer_type) < 0) + return -EIO; + Py_InitModule("smixer_python", python_methods); + priv->py_initialized = 1; + main_interpreter = PyThreadState_Get()->interp; + obj = PyImport_GetModuleDict(); + py_mod = PyDict_GetItemString(obj, "__main__"); + if (py_mod) { + mdict = priv->py_mdict = PyModule_GetDict(py_mod); + obj = PyString_FromString(file); + if (obj) + PyDict_SetItemString(mdict, "__file__", obj); + Py_XDECREF(obj); + obj = PyString_FromString(device); + if (obj) + PyDict_SetItemString(mdict, "device", obj); + Py_XDECREF(obj); + Py_INCREF(&pymixer_type); + PyModule_AddObject(py_mod, "InternalMElement", (PyObject *)&pymelem_type); + PyModule_AddObject(py_mod, "InternalMixer", (PyObject *)&pymixer_type); + obj = PyDict_GetItemString(mdict, "InternalMixer"); + if (obj) { + obj1 = PyTuple_New(3); + PyTuple_SET_ITEM(obj1, 0, PyInt_FromLong((long)class)); + PyTuple_SET_ITEM(obj1, 1, PyInt_FromLong((long)mixer)); + if (PyTuple_SET_ITEM(obj1, 2, mdict)) + Py_INCREF(mdict); + obj2 = PyObject_CallObject(obj, obj1); + Py_XDECREF(obj1); + PyDict_SetItemString(mdict, "mixer", obj2); + priv->py_mixer = obj2; + } else { + SNDERR("Unable to create InternalMixer object"); + return -EIO; + } + + + obj = PyRun_FileEx(fp, file, Py_file_input, mdict, mdict, 1); + if (obj == NULL) + PyErr_Print(); + Py_XDECREF(obj); + priv->py_event_func = PyDict_GetItemString(mdict, "event"); + if (priv->py_event_func == NULL) { + SNDERR("Unable to find python function 'event'"); + return -EIO; + } + } + return 0; +} diff --git a/modules/mixer/simple/sbase.c b/modules/mixer/simple/sbase.c new file mode 100644 index 0000000..97feee8 --- /dev/null +++ b/modules/mixer/simple/sbase.c @@ -0,0 +1,587 @@ +/* + * Mixer Interface - simple abstact module - base library + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "asoundlib.h" +#include "mixer_abst.h" +#include "sbase.h" + +/* + * Prototypes + */ + +static int selem_read(snd_mixer_elem_t *elem); + +/* + * Helpers + */ + +static unsigned int chanmap_to_channels(unsigned int chanmap) +{ + unsigned int i, res; + + for (i = 0, res = 0; i < MAX_CHANNEL; i++) + if (chanmap & (1 << i)) + res++; + return res; +} + +#if 0 +static long to_user(struct selem_base *s, int dir, struct helem_base *c, long value) +{ + int64_t n; + if (c->max == c->min) + return s->dir[dir].min; + n = (int64_t) (value - c->min) * (s->dir[dir].max - s->dir[dir].min); + return s->dir[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min); +} + +static long from_user(struct selem_base *s, int dir, struct helem_base *c, long value) +{ + int64_t n; + if (s->dir[dir].max == s->dir[dir].min) + return c->min; + n = (int64_t) (value - s->dir[dir].min) * (c->max - c->min); + return c->min + (n + (s->dir[dir].max - s->dir[dir].min) / 2) / (s->dir[dir].max - s->dir[dir].min); +} +#endif + +static void update_ranges(struct selem_base *s) +{ + static unsigned int mask[2] = { SM_CAP_PVOLUME, SM_CAP_CVOLUME }; + static unsigned int gmask[2] = { SM_CAP_GVOLUME, SM_CAP_GVOLUME }; + unsigned int dir, ok_flag; + struct list_head *pos; + struct helem_base *helem; + + for (dir = 0; dir < 2; dir++) { + s->dir[dir].min = 0; + s->dir[dir].max = 0; + ok_flag = 0; + list_for_each(pos, &s->helems) { + helem = list_entry(pos, struct helem_base, list); + printf("min = %li, max = %li\n", helem->min, helem->max); + if (helem->caps & mask[dir]) { + s->dir[dir].min = helem->min; + s->dir[dir].max = helem->max; + ok_flag = 1; + break; + } + } + if (ok_flag) + continue; + list_for_each(pos, &s->helems) { + helem = list_entry(pos, struct helem_base, list); + if (helem->caps & gmask[dir]) { + s->dir[dir].min = helem->min; + s->dir[dir].max = helem->max; + break; + } + } + } +} + +/* + * Simple Mixer Operations + */ + +static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) +{ + struct selem_base *s = snd_mixer_elem_get_private(elem); + + switch (cmd) { + + case SM_OPS_IS_ACTIVE: { + struct list_head *pos; + struct helem_base *helem; + list_for_each(pos, &s->helems) { + helem = list_entry(pos, struct helem_base, list); + if (helem->inactive) + return 0; + } + return 1; + } + + case SM_OPS_IS_MONO: + return chanmap_to_channels(s->dir[dir].chanmap) == 1; + + case SM_OPS_IS_CHANNEL: + if (val > MAX_CHANNEL) + return 0; + return !!((1 << val) & s->dir[dir].chanmap); + + case SM_OPS_IS_ENUMERATED: { + struct helem_base *helem; + helem = list_entry(s->helems.next, struct helem_base, list); + return !!(helem->purpose == PURPOSE_ENUMLIST); + } + + case SM_OPS_IS_ENUMCNT: { + struct helem_base *helem; + helem = list_entry(s->helems.next, struct helem_base, list); + return helem->max; + } + + } + + return 1; +} + +static int get_range_ops(snd_mixer_elem_t *elem, int dir, + long *min, long *max) +{ + struct selem_base *s = snd_mixer_elem_get_private(elem); + + *min = s->dir[dir].min; + *max = s->dir[dir].max; + + return 0; +} + +static int get_dB_range_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + int dir ATTRIBUTE_UNUSED, + long *min ATTRIBUTE_UNUSED, + long *max ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int set_range_ops(snd_mixer_elem_t *elem, int dir, + long min, long max) +{ + struct selem_base *s = snd_mixer_elem_get_private(elem); + int err; + + s->dir[dir].forced_range = 1; + s->dir[dir].min = min; + s->dir[dir].max = max; + + if ((err = selem_read(elem)) < 0) + return err; + return 0; +} + +static int get_volume_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, long *value) +{ + struct selem_base *s = snd_mixer_elem_get_private(elem); + + *value = s->dir[dir].vol[channel]; + return 0; +} + +static int get_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + int dir ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + long *value ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int get_switch_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + int dir ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + int *value) +{ + /* struct selem_base *s = snd_mixer_elem_get_private(elem); */ + *value = 0; + return 0; +} + +static int set_volume_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + int dir ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + long value ATTRIBUTE_UNUSED) +{ + /* struct selem_base *s = snd_mixer_elem_get_private(elem); */ + return 0; +} + +static int set_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + int dir ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + long value ATTRIBUTE_UNUSED, + int xdir ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int set_switch_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + int dir ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + int value ATTRIBUTE_UNUSED) +{ + /* struct selem_base *s = snd_mixer_elem_get_private(elem); */ + /* int changed; */ + return 0; +} + +static int enum_item_name_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + unsigned int item ATTRIBUTE_UNUSED, + size_t maxlen ATTRIBUTE_UNUSED, + char *buf ATTRIBUTE_UNUSED) +{ + /* struct selem_base *s = snd_mixer_elem_get_private(elem);*/ + return 0; +} + +static int get_enum_item_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + unsigned int *itemp ATTRIBUTE_UNUSED) +{ + /* struct selem_base *s = snd_mixer_elem_get_private(elem); */ + return 0; +} + +static int set_enum_item_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, + snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED, + unsigned int item ATTRIBUTE_UNUSED) +{ + /* struct selem_base *s = snd_mixer_elem_get_private(elem); */ + return 0; +} + +static struct sm_elem_ops simple_ac97_ops = { + .is = is_ops, + .get_range = get_range_ops, + .get_dB_range = get_dB_range_ops, + .set_range = set_range_ops, + .get_volume = get_volume_ops, + .get_dB = get_dB_ops, + .set_volume = set_volume_ops, + .set_dB = set_dB_ops, + .get_switch = get_switch_ops, + .set_switch = set_switch_ops, + .enum_item_name = enum_item_name_ops, + .get_enum_item = get_enum_item_ops, + .set_enum_item = set_enum_item_ops +}; + +/* + * event handling + */ + +static int selem_read(snd_mixer_elem_t *elem) +{ + printf("elem read: %p\n", elem); + return 0; +} + +static int simple_event_remove(snd_hctl_elem_t *helem, + snd_mixer_elem_t *melem ATTRIBUTE_UNUSED) +{ + printf("event remove: %p\n", helem); + return 0; +} + +static void selem_free(snd_mixer_elem_t *elem) +{ + struct selem_base *simple = snd_mixer_elem_get_private(elem); + struct helem_base *hsimple; + struct list_head *pos, *npos; + + if (simple->selem.id) + snd_mixer_selem_id_free(simple->selem.id); + list_for_each_safe(pos, npos, &simple->helems) { + hsimple = list_entry(pos, struct helem_base, list); + free(hsimple); + } + free(simple); +} + +static int simple_event_add1(snd_mixer_class_t *class, + snd_hctl_elem_t *helem, + struct helem_selector *sel) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + snd_mixer_elem_t *melem; + snd_mixer_selem_id_t *id; + snd_ctl_elem_info_t *info; + struct selem_base *simple; + struct helem_base *hsimple; + snd_ctl_elem_type_t ctype; + unsigned long values; + long min, max; + int err, new = 0; + struct list_head *pos; + struct bclass_sid *bsid; + struct melem_sids *sid; + unsigned int ui; + + list_for_each(pos, &priv->sids) { + bsid = list_entry(pos, struct bclass_sid, list); + for (ui = 0; ui < bsid->count; ui++) { + if (bsid->sids[ui].sid == sel->sid) { + sid = &bsid->sids[ui]; + goto __sid_ok; + } + } + } + return 0; + + __sid_ok: + snd_ctl_elem_info_alloca(&info); + err = snd_hctl_elem_info(helem, info); + if (err < 0) + return err; + ctype = snd_ctl_elem_info_get_type(info); + values = snd_ctl_elem_info_get_count(info); + switch (ctype) { + case SND_CTL_ELEM_TYPE_ENUMERATED: + min = 0; + max = snd_ctl_elem_info_get_items(info); + break; + case SND_CTL_ELEM_TYPE_INTEGER: + min = snd_ctl_elem_info_get_min(info); + max = snd_ctl_elem_info_get_max(info); + break; + default: + min = max = 0; + break; + } + + printf("event add: %p, %p (%s)\n", helem, sel, snd_hctl_elem_get_name(helem)); + if (snd_mixer_selem_id_malloc(&id)) + return -ENOMEM; + hsimple = calloc(1, sizeof(*hsimple)); + if (hsimple == NULL) { + snd_mixer_selem_id_free(id); + return -ENOMEM; + } + switch (sel->purpose) { + case PURPOSE_SWITCH: + if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) { + __invalid_type: + snd_mixer_selem_id_free(id); + return -EINVAL; + } + break; + case PURPOSE_VOLUME: + if (ctype != SND_CTL_ELEM_TYPE_INTEGER) + goto __invalid_type; + break; + } + hsimple->purpose = sel->purpose; + hsimple->caps = sel->caps; + hsimple->min = min; + hsimple->max = max; + snd_mixer_selem_id_set_name(id, sid->sname); + snd_mixer_selem_id_set_index(id, sid->sindex); + melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id); + if (!melem) { + simple = calloc(1, sizeof(*simple)); + if (!simple) { + snd_mixer_selem_id_free(id); + free(hsimple); + return -ENOMEM; + } + simple->selem.id = id; + simple->selem.ops = &simple_ac97_ops; + INIT_LIST_HEAD(&simple->helems); + simple->sid = sel->sid; + err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE, + sid->weight, + simple, selem_free); + if (err < 0) { + snd_mixer_selem_id_free(id); + free(hsimple); + free(simple); + return err; + } + new = 1; + } else { + simple = snd_mixer_elem_get_private(melem); + snd_mixer_selem_id_free(id); + } + list_add_tail(&hsimple->list, &simple->helems); + hsimple->inactive = snd_ctl_elem_info_is_inactive(info); + err = snd_mixer_elem_attach(melem, helem); + if (err < 0) + goto __error; + simple->dir[0].chanmap |= sid->chanmap[0]; + simple->dir[1].chanmap |= sid->chanmap[1]; + simple->selem.caps |= hsimple->caps; + update_ranges(simple); +#if 0 + err = simple_update(melem); + if (err < 0) { + if (new) + goto __error; + return err; + } +#endif + if (new) + err = snd_mixer_elem_add(melem, class); + else + err = snd_mixer_elem_info(melem); + if (err < 0) + return err; + err = selem_read(melem); + if (err < 0) + return err; + if (err) + err = snd_mixer_elem_value(melem); + return err; + __error: + if (new) + snd_mixer_elem_free(melem); + return -EINVAL; +} + +static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + struct bclass_selector *sel; + struct helem_selector *hsel; + struct list_head *pos; + snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); + const char *name = snd_hctl_elem_get_name(helem); + unsigned int index = snd_hctl_elem_get_index(helem); + unsigned int ui; + int err; + + list_for_each(pos, &priv->selectors) { + sel = list_entry(pos, struct bclass_selector, list); + for (ui = 0; ui < sel->count; ui++) { + hsel = &sel->selectors[ui]; + if (hsel->iface == iface && !strcmp(hsel->name, name) && hsel->index == index) { + err = simple_event_add1(class, helem, hsel); + if (err < 0) + return err; /* early exit? */ + } + } + } + return 0; +} + +int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) +{ + int err; + if (mask == SND_CTL_EVENT_MASK_REMOVE) + return simple_event_remove(helem, melem); + if (mask & SND_CTL_EVENT_MASK_ADD) { + err = simple_event_add(class, helem); + if (err < 0) + return err; + } + if (mask & SND_CTL_EVENT_MASK_INFO) { + err = simple_event_remove(helem, melem); + if (err < 0) + return err; + err = simple_event_add(class, helem); + if (err < 0) + return err; + return 0; + } + if (mask & SND_CTL_EVENT_MASK_VALUE) { + err = selem_read(melem); + if (err < 0) + return err; + if (err) { + err = snd_mixer_elem_value(melem); + if (err < 0) + return err; + } + } + return 0; +} + +static void sbasic_cpriv_free(snd_mixer_class_t *class) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + struct bclass_selector *sel; + struct bclass_sid *sid; + struct list_head *pos, *pos1; + + list_for_each_safe(pos, pos1, &priv->selectors) { + sel = list_entry(pos, struct bclass_selector, list); + free(sel); + } + list_for_each_safe(pos, pos1, &priv->sids) { + sid = list_entry(pos, struct bclass_sid, list); + free(sid); + } + free(priv); +} + +void alsa_mixer_sbasic_initpriv(snd_mixer_class_t *class, + struct bclass_private *priv) +{ + INIT_LIST_HEAD(&priv->selectors); + INIT_LIST_HEAD(&priv->sids); + snd_mixer_sbasic_set_private(class, priv); + snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free); +} + +int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class, + struct helem_selector *selectors, + unsigned int count) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + struct bclass_selector *sel = calloc(1, sizeof(*sel)); + + if (sel == NULL) + return -ENOMEM; + if (priv == NULL) { + priv = calloc(1, sizeof(*priv)); + if (priv == NULL) { + free(sel); + return -ENOMEM; + } + } + sel->selectors = selectors; + sel->count = count; + list_add_tail(&sel->list, &priv->selectors); + return 0; +} + +int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class, + struct melem_sids *sids, + unsigned int count) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + struct bclass_sid *sid = calloc(1, sizeof(*sid)); + + if (sid == NULL) + return -ENOMEM; + if (priv == NULL) { + priv = calloc(1, sizeof(*priv)); + if (priv == NULL) { + free(sid); + return -ENOMEM; + } + INIT_LIST_HEAD(&priv->selectors); + INIT_LIST_HEAD(&priv->sids); + snd_mixer_sbasic_set_private(class, priv); + snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free); + } + sid->sids = sids; + sid->count = count; + list_add(&sid->list, &priv->sids); + return 0; +} diff --git a/modules/mixer/simple/sbase.h b/modules/mixer/simple/sbase.h new file mode 100644 index 0000000..ee5fe03 --- /dev/null +++ b/modules/mixer/simple/sbase.h @@ -0,0 +1,111 @@ +/* + * Mixer Interface - simple abstact module - base library + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __SMIXER_BASE_H + +#include "list.h" + +#define MAX_CHANNEL 6 + +#define SID_MASTER 0 +#define SID_HEADPHONE 1 +#define SID_FRONT 2 +#define SID_PCM 3 +#define SID_CD 4 + +struct melem_sids { + unsigned short sid; + const char *sname; + unsigned short sindex; + unsigned short weight; + unsigned int chanmap[2]; + struct sm_elem_ops *sops; +}; + +#define PURPOSE_VOLUME 0 +#define PURPOSE_SWITCH 1 +#define PURPOSE_ENUMLIST 2 + +struct helem_selector { + snd_ctl_elem_iface_t iface; + const char *name; + unsigned short index; + unsigned short sid; + unsigned short purpose; + unsigned short caps; +}; + +struct helem_base { + struct list_head list; + snd_hctl_elem_t *helem; + unsigned short purpose; + unsigned int caps; + unsigned int inactive: 1; + long min, max; + unsigned int count; +}; + +struct selem_base { + sm_selem_t selem; + struct list_head helems; + unsigned short sid; + struct { + unsigned int chanmap; + unsigned int forced_range: 1; + long min, max; + long vol[MAX_CHANNEL]; + } dir[2]; +}; + +struct bclass_selector { + struct list_head list; + struct helem_selector *selectors; + unsigned int count; +}; + +struct bclass_sid { + struct list_head list; + struct melem_sids *sids; + unsigned int count; +}; + +typedef struct bclass_base_ops { + int (*event)(snd_mixer_class_t *class, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem); + int (*selreg)(snd_mixer_class_t *class, + struct helem_selector *selectors, + unsigned int count); + int (*sidreg)(snd_mixer_class_t *class, + struct melem_sids *sids, + unsigned int count); +} bclass_base_ops_t; + +struct bclass_private { + struct list_head selectors; + struct list_head sids; + void *dl_sbase; + bclass_base_ops_t ops; +}; + +int mixer_simple_basic_dlopen(snd_mixer_class_t *class, + bclass_base_ops_t **ops); + +#endif /* __SMIXER_BASE_H */ diff --git a/modules/mixer/simple/sbasedl.c b/modules/mixer/simple/sbasedl.c new file mode 100644 index 0000000..0137586 --- /dev/null +++ b/modules/mixer/simple/sbasedl.c @@ -0,0 +1,106 @@ +/* + * Mixer Interface - simple abstact module - base library (dlopen function) + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "asoundlib.h" +#include "mixer_abst.h" +#include "sbase.h" + +#define SO_PATH ALSA_PLUGIN_DIR "/smixer" + +int mixer_simple_basic_dlopen(snd_mixer_class_t *class, + bclass_base_ops_t **ops) +{ + struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + const char *lib = "smixer-sbase.so"; + void (*initpriv)(snd_mixer_class_t *class, struct bclass_private *priv); + char *xlib, *path; + void *h; + int initflag = 0; + + if (priv == NULL) { + priv = calloc(1, sizeof(*priv)); + if (priv == NULL) + return -ENOMEM; + initflag = 1; + } + path = getenv("ALSA_MIXER_SIMPLE_MODULES"); + if (!path) + path = SO_PATH; + xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); + if (xlib == NULL) { + if (initflag) + free(priv); + return -ENOMEM; + } + strcpy(xlib, path); + strcat(xlib, "/"); + strcat(xlib, lib); + h = snd_dlopen(xlib, RTLD_NOW); + if (h == NULL) { + SNDERR("Unable to open library '%s'", xlib); + goto __error; + } + initpriv = dlsym(h, "alsa_mixer_sbasic_initpriv"); + if (initpriv == NULL) { + SNDERR("Symbol 'alsa_mixer_sbasic_initpriv' was not found in '%s'", xlib); + goto __error; + } + priv->ops.event = dlsym(h, "alsa_mixer_sbasic_event"); + if (priv->ops.event == NULL) { + SNDERR("Symbol 'alsa_mixer_sbasic_event' was not found in '%s'", xlib); + goto __error; + } + priv->ops.selreg = dlsym(h, "alsa_mixer_sbasic_selreg"); + if (priv->ops.selreg == NULL) { + SNDERR("Symbol 'alsa_mixer_sbasic_selreg' was not found in '%s'", xlib); + goto __error; + } + priv->ops.sidreg = dlsym(h, "alsa_mixer_sbasic_sidreg"); + if (priv->ops.sidreg == NULL) { + SNDERR("Symbol 'alsa_mixer_sbasic_sidreg' was not found in '%s'", xlib); + goto __error; + } + free(xlib); + if (initflag) + initpriv(class, priv); + priv->dl_sbase = h; + if (ops) + *ops = &priv->ops; + return 1; + + __error: + if (initflag) + free(priv); + if (h == NULL) + snd_dlclose(h); + free(xlib); + return -ENXIO; +} diff --git a/packaging/alsa-lib.spec b/packaging/alsa-lib.spec new file mode 100644 index 0000000..290e1b0 --- /dev/null +++ b/packaging/alsa-lib.spec @@ -0,0 +1,102 @@ +#sbs-git:slp/pkgs/a/alsa-lib alsa-lib 1.0.21a cb38cd61f9258cb9c7ea768f9782b372de5976df +Name: alsa-lib +Summary: The Advanced Linux Sound Architecture (ALSA) library +Version: 1.0.24.1 +Release: 6 +Group: System/Libraries +License: LGPLv2+ +URL: http://www.alsa-project.org/ +Source0: ftp://ftp.alsa-project.org/pub/lib/%{name}-%{version}.tar.gz +Obsoletes: alsa-lib-1.0.25 +Conflicts: alsa-lib-1.0.25 + + +%description +The Advanced Linux Sound Architecture (ALSA) provides audio and MIDI +functionality to the Linux operating system. + +This package includes the ALSA runtime libraries to simplify application +programming and provide higher level functionality as well as support for +the older OSS API, providing binary compatibility for most OSS programs. + + +%package -n libasound +Summary: ALSA Library package for multimedia framework middleware package +Group: Development/Libraries +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +Obsoletes: libasound-1.0.25 +Conflicts: libasound-1.0.25 + +%description -n libasound +ALSA Library package for multimedia framework middleware package + + +%package -n libasound-devel +Summary: ALSA Library package for multimedia framework middleware package +Group: Development/Libraries +Requires: libasound +Obsoletes: libasound-1.0.25-devel +Conflicts: libasound-1.0.25-devel + +%description -n libasound-devel +ALSA Library package for multimedia framework middleware package + + +%prep +%setup -q + + +%build +export CFLAGS+=" -fPIC" +export LDFLAGS+=" -Wl,--warn-unresolved-symbols -Wl,--hash-style=both -Wl,--as-needed" +chmod +x autogen.sh + +%autogen --disable-static +%configure --disable-static \ +%ifarch %{arm} + --with-alsa-devdir=/dev/snd \ +%endif + --disable-alisp \ + --disable-seq \ + --disable-rawmidi \ + --disable-python \ + --with-gnu-ld \ +%ifarch %{arm} + --with-pcm-plugins=rate,linear,plug,dmix,dsnoop,asym,mmap,ioplug +%endif + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +cp COPYING %{buildroot}/usr/share/license/%{name} +cp COPYING %{buildroot}/usr/share/license/libasound +%make_install + +rm -f %{buildroot}/%{_bindir}/aserver + +%post -n libasound -p /sbin/ldconfig + +%postun -n libasound -p /sbin/ldconfig + +%files +%manifest alsa-lib.manifest +%defattr(-,root,root,-) +%{_datadir}/license/%{name} + +%files -n libasound +%manifest alsa-lib.manifest +%defattr(-,root,root,-) +%{_libdir}/lib*.so.* +%{_libdir}/alsa-lib/smixer/*.so +%{_datadir}/alsa/* +%{_datadir}/license/libasound + +%files -n libasound-devel +%defattr(-,root,root,-) +%{_includedir}/* +%{_libdir}/lib*.so +%{_libdir}/pkgconfig/* +%{_datadir}/aclocal diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..08f482a --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,93 @@ +EXTRA_DIST=Versions +COMPATNUM=@LIBTOOL_VERSION_INFO@ + +if VERSIONED_SYMBOLS +VSYMS = -Wl,--version-script=Versions +else +VSYMS = +endif + +if SYMBOLIC_FUNCTIONS +SYMFUNCS = -Wl,-Bsymbolic-functions +else +SYMFUNCS = +endif + +lib_LTLIBRARIES = libasound.la +libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c names.c + +SUBDIRS=control +libasound_la_LIBADD = control/libcontrol.la +if BUILD_MIXER +SUBDIRS += mixer +libasound_la_LIBADD += mixer/libmixer.la +endif +if BUILD_PCM +SUBDIRS += pcm timer +libasound_la_LIBADD += pcm/libpcm.la timer/libtimer.la +endif +if BUILD_RAWMIDI +SUBDIRS += rawmidi +libasound_la_LIBADD += rawmidi/librawmidi.la +endif +if BUILD_HWDEP +SUBDIRS += hwdep +libasound_la_LIBADD += hwdep/libhwdep.la +endif +if BUILD_SEQ +SUBDIRS += seq +libasound_la_LIBADD += seq/libseq.la +endif +if BUILD_UCM +SUBDIRS += ucm +libasound_la_LIBADD += ucm/libucm.la +endif +if BUILD_ALISP +SUBDIRS += alisp +libasound_la_LIBADD += alisp/libalisp.la +endif +SUBDIRS += compat conf +libasound_la_LIBADD += compat/libcompat.la @ALSA_DEPLIBS@ + +libasound_la_LDFLAGS = -version-info $(COMPATNUM) $(VSYMS) $(SYMFUNCS) $(LDFLAGS_NOUNDEFINED) + +control/libcontrol.la: + $(MAKE) -C control libcontrol.la + +mixer/libmixer.la: + $(MAKE) -C mixer libmixer.la + +ordinary_mixer/libordinarymixer.la: + $(MAKE) -C ordinary_mixer libordinarymixer.la + +pcm/libpcm.la: + $(MAKE) -C pcm libpcm.la + +ordinary_pcm/libordinarypcm.la: + $(MAKE) -C ordinary_pcm libordinarypcm.la + +rawmidi/librawmidi.la: + $(MAKE) -C rawmidi librawmidi.la + +timer/libtimer.la: + $(MAKE) -C timer libtimer.la + +hwdep/libhwdep.la: + $(MAKE) -C hwdep libhwdep.la + +seq/libseq.la: + $(MAKE) -C seq libseq.la + +ucm/libucm.la: + $(MAKE) -C ucm libucm.la + +instr/libinstr.la: + $(MAKE) -C instr libinstr.la + +compat/libcompat.la: + $(MAKE) -C compat libcompat.la + +alisp/libalisp.la: + $(MAKE) -C alisp libalisp.la + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..a6b5fd4 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,787 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_MIXER_TRUE@am__append_1 = mixer +@BUILD_MIXER_TRUE@am__append_2 = mixer/libmixer.la +@BUILD_PCM_TRUE@am__append_3 = pcm timer +@BUILD_PCM_TRUE@am__append_4 = pcm/libpcm.la timer/libtimer.la +@BUILD_RAWMIDI_TRUE@am__append_5 = rawmidi +@BUILD_RAWMIDI_TRUE@am__append_6 = rawmidi/librawmidi.la +@BUILD_HWDEP_TRUE@am__append_7 = hwdep +@BUILD_HWDEP_TRUE@am__append_8 = hwdep/libhwdep.la +@BUILD_SEQ_TRUE@am__append_9 = seq +@BUILD_SEQ_TRUE@am__append_10 = seq/libseq.la +@BUILD_UCM_TRUE@am__append_11 = ucm +@BUILD_UCM_TRUE@am__append_12 = ucm/libucm.la +@BUILD_ALISP_TRUE@am__append_13 = alisp +@BUILD_ALISP_TRUE@am__append_14 = alisp/libalisp.la +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/Versions.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = Versions +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libasound_la_DEPENDENCIES = control/libcontrol.la $(am__append_2) \ + $(am__append_4) $(am__append_6) $(am__append_8) \ + $(am__append_10) $(am__append_12) $(am__append_14) \ + compat/libcompat.la +am_libasound_la_OBJECTS = conf.lo confmisc.lo input.lo output.lo \ + async.lo error.lo dlmisc.lo socket.lo shmarea.lo userfile.lo \ + names.lo +libasound_la_OBJECTS = $(am_libasound_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libasound_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libasound_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libasound_la_SOURCES) +DIST_SOURCES = $(libasound_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = control mixer pcm timer rawmidi hwdep seq ucm alisp \ + compat conf +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = Versions +COMPATNUM = @LIBTOOL_VERSION_INFO@ +@VERSIONED_SYMBOLS_FALSE@VSYMS = +@VERSIONED_SYMBOLS_TRUE@VSYMS = -Wl,--version-script=Versions +@SYMBOLIC_FUNCTIONS_FALSE@SYMFUNCS = +@SYMBOLIC_FUNCTIONS_TRUE@SYMFUNCS = -Wl,-Bsymbolic-functions +lib_LTLIBRARIES = libasound.la +libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c names.c +SUBDIRS = control $(am__append_1) $(am__append_3) $(am__append_5) \ + $(am__append_7) $(am__append_9) $(am__append_11) \ + $(am__append_13) compat conf +libasound_la_LIBADD = control/libcontrol.la $(am__append_2) \ + $(am__append_4) $(am__append_6) $(am__append_8) \ + $(am__append_10) $(am__append_12) $(am__append_14) \ + compat/libcompat.la @ALSA_DEPLIBS@ +libasound_la_LDFLAGS = -version-info $(COMPATNUM) $(VSYMS) $(SYMFUNCS) $(LDFLAGS_NOUNDEFINED) +INCLUDES = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +Versions: $(top_builddir)/config.status $(srcdir)/Versions.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libasound.la: $(libasound_la_OBJECTS) $(libasound_la_DEPENDENCIES) + $(AM_V_CCLD)$(libasound_la_LINK) -rpath $(libdir) $(libasound_la_OBJECTS) $(libasound_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/async.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/confmisc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dlmisc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/names.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shmarea.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userfile.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags ctags-recursive \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-libLTLIBRARIES + + +control/libcontrol.la: + $(MAKE) -C control libcontrol.la + +mixer/libmixer.la: + $(MAKE) -C mixer libmixer.la + +ordinary_mixer/libordinarymixer.la: + $(MAKE) -C ordinary_mixer libordinarymixer.la + +pcm/libpcm.la: + $(MAKE) -C pcm libpcm.la + +ordinary_pcm/libordinarypcm.la: + $(MAKE) -C ordinary_pcm libordinarypcm.la + +rawmidi/librawmidi.la: + $(MAKE) -C rawmidi librawmidi.la + +timer/libtimer.la: + $(MAKE) -C timer libtimer.la + +hwdep/libhwdep.la: + $(MAKE) -C hwdep libhwdep.la + +seq/libseq.la: + $(MAKE) -C seq libseq.la + +ucm/libucm.la: + $(MAKE) -C ucm libucm.la + +instr/libinstr.la: + $(MAKE) -C instr libinstr.la + +compat/libcompat.la: + $(MAKE) -C compat libcompat.la + +alisp/libalisp.la: + $(MAKE) -C alisp libalisp.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/Versions.in b/src/Versions.in new file mode 100644 index 0000000..8d2dd11 --- /dev/null +++ b/src/Versions.in @@ -0,0 +1,131 @@ +ALSA_0.9 { + global: + @SYMBOL_PREFIX@snd_*; + + @SYMBOL_PREFIX@_snd_*_open; + @SYMBOL_PREFIX@_snd_*_dlsym_*; + @SYMBOL_PREFIX@_snd_*_poll_descriptor; + @SYMBOL_PREFIX@_snd_pcm_hook_*; + + @SYMBOL_PREFIX@__snd_pcm_hw_params_*; + @SYMBOL_PREFIX@__snd_pcm_sw_params_*; + @SYMBOL_PREFIX@__snd_*_dlsym_*; + + local: + *; +}; + +ALSA_0.9.0rc4 { + global: + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_access; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_access_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_access_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_format; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_format_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_format_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_subformat; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_subformat_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_subformat_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_channels; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_channels_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_channels_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_channels_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_channels_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_channels_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_rate; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_rate_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_rate_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_rate_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_rate_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_rate_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_period_time; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_period_time_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_period_time_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_period_time_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_period_time_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_period_time_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_period_size; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_period_size_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_period_size_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_period_size_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_period_size_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_period_size_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_periods; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_periods_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_periods_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_periods_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_periods_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_periods_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_buffer_time; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_buffer_time_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_buffer_time_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_buffer_time_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_buffer_time_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_buffer_time_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_buffer_size; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_buffer_size_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_buffer_size_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_buffer_size_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_buffer_size_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_buffer_size_last; + + @SYMBOL_PREFIX@snd_pcm_hw_params_get_tick_time; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_tick_time_min; + @SYMBOL_PREFIX@snd_pcm_hw_params_get_tick_time_max; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_tick_time_near; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_tick_time_first; + @SYMBOL_PREFIX@snd_pcm_hw_params_set_tick_time_last; + +} ALSA_0.9; + +ALSA_0.9.0rc8 { + global: + + @SYMBOL_PREFIX@snd_pcm_forward; + @SYMBOL_PREFIX@snd_pcm_status_get_trigger_htstamp; + @SYMBOL_PREFIX@snd_pcm_status_get_htstamp; + +} ALSA_0.9.0rc4; + +ALSA_0.9.0 { + global: + + @SYMBOL_PREFIX@snd_pcm_type_name; + @SYMBOL_PREFIX@snd_timer_query_info; + @SYMBOL_PREFIX@snd_timer_query_params; + @SYMBOL_PREFIX@snd_timer_query_status; + @SYMBOL_PREFIX@snd_timer_params_set_exclusive; + @SYMBOL_PREFIX@snd_timer_params_get_exclusive; + @SYMBOL_PREFIX@snd_timer_params_set_filter; + @SYMBOL_PREFIX@snd_timer_params_get_filter; +} ALSA_0.9.0rc8; + +ALSA_0.9.3 { + global: + + @SYMBOL_PREFIX@snd_ctl_elem_info_get_dimensions; + @SYMBOL_PREFIX@snd_ctl_elem_info_get_dimension; +} ALSA_0.9.0; + +ALSA_0.9.5 { + global: + + @SYMBOL_PREFIX@alsa_lisp; +} ALSA_0.9.3; + +ALSA_0.9.7 { + global: + + @SYMBOL_PREFIX@alsa_lisp_*; +} ALSA_0.9.5; + diff --git a/src/alisp/Makefile.am b/src/alisp/Makefile.am new file mode 100644 index 0000000..e6d4ac5 --- /dev/null +++ b/src/alisp/Makefile.am @@ -0,0 +1,11 @@ +EXTRA_LTLIBRARIES = libalisp.la + +EXTRA_DIST = alisp_snd.c + +libalisp_la_SOURCES = alisp.c + +noinst_HEADERS = alisp_local.h + +all: libalisp.la + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/alisp/Makefile.in b/src/alisp/Makefile.in new file mode 100644 index 0000000..2000b1f --- /dev/null +++ b/src/alisp/Makefile.in @@ -0,0 +1,492 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/alisp +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libalisp_la_LIBADD = +am_libalisp_la_OBJECTS = alisp.lo +libalisp_la_OBJECTS = $(am_libalisp_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libalisp_la_SOURCES) +DIST_SOURCES = $(libalisp_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libalisp.la +EXTRA_DIST = alisp_snd.c +libalisp_la_SOURCES = alisp.c +noinst_HEADERS = alisp_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/alisp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/alisp/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libalisp.la: $(libalisp_la_OBJECTS) $(libalisp_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libalisp_la_OBJECTS) $(libalisp_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alisp.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +all: libalisp.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c new file mode 100644 index 0000000..7575f55 --- /dev/null +++ b/src/alisp/alisp.c @@ -0,0 +1,3495 @@ +/* + * ALSA lisp implementation + * Copyright (c) 2003 by Jaroslav Kysela + * + * Based on work of Sandro Sigala (slisp-1.2) + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define alisp_seq_iterator alisp_object + +#include "local.h" +#include "alisp.h" +#include "alisp_local.h" + +struct alisp_object alsa_lisp_nil; +struct alisp_object alsa_lisp_t; + +/* parser prototypes */ +static struct alisp_object * parse_object(struct alisp_instance *instance, int havetoken); +static void princ_cons(snd_output_t *out, struct alisp_object * p); +static void princ_object(snd_output_t *out, struct alisp_object * p); +static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_object * p); + +/* functions */ +static struct alisp_object *F_eval(struct alisp_instance *instance, struct alisp_object *); +static struct alisp_object *F_progn(struct alisp_instance *instance, struct alisp_object *); +static struct alisp_object *F_funcall(struct alisp_instance *instance, struct alisp_object *); + +/* others */ +static int alisp_include_file(struct alisp_instance *instance, const char *filename); + +/* + * object handling + */ + +static int get_string_hash(const char *s) +{ + int val = 0; + if (s == NULL) + return val; + while (*s) + val += *s++; + return val & ALISP_OBJ_PAIR_HASH_MASK; +} + +static void nomem(void) +{ + SNDERR("alisp: no enough memory"); +} + +static void lisp_verbose(struct alisp_instance *instance, const char *fmt, ...) +{ + va_list ap; + + if (!instance->verbose) + return; + va_start(ap, fmt); + snd_output_printf(instance->vout, "alisp: "); + snd_output_vprintf(instance->vout, fmt, ap); + snd_output_putc(instance->vout, '\n'); + va_end(ap); +} + +static void lisp_error(struct alisp_instance *instance, const char *fmt, ...) +{ + va_list ap; + + if (!instance->warning) + return; + va_start(ap, fmt); + snd_output_printf(instance->eout, "alisp error: "); + snd_output_vprintf(instance->eout, fmt, ap); + snd_output_putc(instance->eout, '\n'); + va_end(ap); +} + +static void lisp_warn(struct alisp_instance *instance, const char *fmt, ...) +{ + va_list ap; + + if (!instance->warning) + return; + va_start(ap, fmt); + snd_output_printf(instance->wout, "alisp warning: "); + snd_output_vprintf(instance->wout, fmt, ap); + snd_output_putc(instance->wout, '\n'); + va_end(ap); +} + +static void lisp_debug(struct alisp_instance *instance, const char *fmt, ...) +{ + va_list ap; + + if (!instance->debug) + return; + va_start(ap, fmt); + snd_output_printf(instance->dout, "alisp debug: "); + snd_output_vprintf(instance->dout, fmt, ap); + snd_output_putc(instance->dout, '\n'); + va_end(ap); +} + +static struct alisp_object * new_object(struct alisp_instance *instance, int type) +{ + struct alisp_object * p; + + if (list_empty(&instance->free_objs_list)) { + p = (struct alisp_object *)malloc(sizeof(struct alisp_object)); + if (p == NULL) { + nomem(); + return NULL; + } + lisp_debug(instance, "allocating cons %p", p); + } else { + p = (struct alisp_object *)instance->free_objs_list.next; + list_del(&p->list); + instance->free_objs--; + lisp_debug(instance, "recycling cons %p", p); + } + + instance->used_objs++; + + alisp_set_type(p, type); + alisp_set_refs(p, 1); + if (type == ALISP_OBJ_CONS) { + p->value.c.car = &alsa_lisp_nil; + p->value.c.cdr = &alsa_lisp_nil; + list_add(&p->list, &instance->used_objs_list[0][ALISP_OBJ_CONS]); + } + + if (instance->used_objs + instance->free_objs > instance->max_objs) + instance->max_objs = instance->used_objs + instance->free_objs; + + return p; +} + +static void free_object(struct alisp_object * p) +{ + switch (alisp_get_type(p)) { + case ALISP_OBJ_STRING: + case ALISP_OBJ_IDENTIFIER: + free(p->value.s); + alisp_set_type(p, ALISP_OBJ_INTEGER); + break; + default: + break; + } +} + +static void delete_object(struct alisp_instance *instance, struct alisp_object * p) +{ + if (p == NULL || p == &alsa_lisp_nil || p == &alsa_lisp_t) + return; + if (alisp_compare_type(p, ALISP_OBJ_NIL) || + alisp_compare_type(p, ALISP_OBJ_T)) + return; + assert(alisp_get_refs(p) > 0); + lisp_debug(instance, "delete cons %p (type = %i, refs = %i) (s = '%s')", p, alisp_get_type(p), alisp_get_refs(p), + alisp_compare_type(p, ALISP_OBJ_STRING) || + alisp_compare_type(p, ALISP_OBJ_IDENTIFIER) ? p->value.s : "???"); + if (alisp_dec_refs(p)) + return; + list_del(&p->list); + instance->used_objs--; + free_object(p); + if (instance->free_objs >= ALISP_FREE_OBJ_POOL) { + lisp_debug(instance, "freed cons %p", p); + free(p); + return; + } + lisp_debug(instance, "moved cons %p to free list", p); + list_add(&p->list, &instance->free_objs_list); + instance->free_objs++; +} + +static void delete_tree(struct alisp_instance *instance, struct alisp_object * p) +{ + if (p == NULL) + return; + if (alisp_compare_type(p, ALISP_OBJ_CONS)) { + delete_tree(instance, p->value.c.car); + delete_tree(instance, p->value.c.cdr); + } + delete_object(instance, p); +} + +static struct alisp_object * incref_object(struct alisp_instance *instance ATTRIBUTE_UNUSED, struct alisp_object * p) +{ + if (p == NULL || p == &alsa_lisp_nil || p == &alsa_lisp_t) + return p; + if (alisp_get_refs(p) == ALISP_MAX_REFS) { + assert(0); + fprintf(stderr, "OOPS: alsa lisp: incref fatal error\n"); + exit(EXIT_FAILURE); + } + alisp_inc_refs(p); + return p; +} + +static struct alisp_object * incref_tree(struct alisp_instance *instance, struct alisp_object * p) +{ + if (p == NULL) + return NULL; + if (alisp_compare_type(p, ALISP_OBJ_CONS)) { + incref_tree(instance, p->value.c.car); + incref_tree(instance, p->value.c.cdr); + } + return incref_object(instance, p); +} + +/* Function not used yet. Leave it commented out until we actually use it to + * avoid compiler complaints */ +#if 0 +static struct alisp_object * incref_tree_explicit(struct alisp_instance *instance, struct alisp_object * p, struct alisp_object * e) +{ + if (p == NULL) + return NULL; + if (alisp_compare_type(p, ALISP_OBJ_CONS)) { + if (e == p) { + incref_tree(instance, p->value.c.car); + incref_tree(instance, p->value.c.cdr); + } else { + incref_tree_explicit(instance, p->value.c.car, e); + incref_tree_explicit(instance, p->value.c.cdr, e); + } + } + if (e == p) + return incref_object(instance, p); + return p; +} +#endif + +static void free_objects(struct alisp_instance *instance) +{ + struct list_head *pos, *pos1; + struct alisp_object * p; + struct alisp_object_pair * pair; + int i, j; + + for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) { + list_for_each_safe(pos, pos1, &instance->setobjs_list[i]) { + pair = list_entry(pos, struct alisp_object_pair, list); + lisp_debug(instance, "freeing pair: '%s' -> %p", pair->name, pair->value); + delete_tree(instance, pair->value); + free((void *)pair->name); + free(pair); + } + } + for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) + for (j = 0; j <= ALISP_OBJ_LAST_SEARCH; j++) { + list_for_each_safe(pos, pos1, &instance->used_objs_list[i][j]) { + p = list_entry(pos, struct alisp_object, list); + lisp_warn(instance, "object %p is still referenced %i times!", p, alisp_get_refs(p)); +#if 0 + snd_output_printf(instance->wout, ">>>> "); + princ_object(instance->wout, p); + snd_output_printf(instance->wout, " <<<<\n"); +#endif + if (alisp_get_refs(p) > 0) + alisp_set_refs(p, 1); + delete_object(instance, p); + } + } + list_for_each_safe(pos, pos1, &instance->free_objs_list) { + p = list_entry(pos, struct alisp_object, list); + list_del(&p->list); + free(p); + lisp_debug(instance, "freed (all) cons %p", p); + } +} + +static struct alisp_object * search_object_identifier(struct alisp_instance *instance, const char *s) +{ + struct list_head * pos; + struct alisp_object * p; + + list_for_each(pos, &instance->used_objs_list[get_string_hash(s)][ALISP_OBJ_IDENTIFIER]) { + p = list_entry(pos, struct alisp_object, list); + if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) + continue; + if (!strcmp(p->value.s, s)) + return incref_object(instance, p); + } + + return NULL; +} + +static struct alisp_object * search_object_string(struct alisp_instance *instance, const char *s) +{ + struct list_head * pos; + struct alisp_object * p; + + list_for_each(pos, &instance->used_objs_list[get_string_hash(s)][ALISP_OBJ_STRING]) { + p = list_entry(pos, struct alisp_object, list); + if (!strcmp(p->value.s, s)) { + if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) + continue; + return incref_object(instance, p); + } + } + + return NULL; +} + +static struct alisp_object * search_object_integer(struct alisp_instance *instance, long in) +{ + struct list_head * pos; + struct alisp_object * p; + + list_for_each(pos, &instance->used_objs_list[in & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_INTEGER]) { + p = list_entry(pos, struct alisp_object, list); + if (p->value.i == in) { + if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) + continue; + return incref_object(instance, p); + } + } + + return NULL; +} + +static struct alisp_object * search_object_float(struct alisp_instance *instance, double in) +{ + struct list_head * pos; + struct alisp_object * p; + + list_for_each(pos, &instance->used_objs_list[(long)in & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_FLOAT]) { + p = list_entry(pos, struct alisp_object, list); + if (p->value.i == in) { + if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) + continue; + return incref_object(instance, p); + } + } + + return NULL; +} + +static struct alisp_object * search_object_pointer(struct alisp_instance *instance, const void *ptr) +{ + struct list_head * pos; + struct alisp_object * p; + + list_for_each(pos, &instance->used_objs_list[(long)ptr & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_POINTER]) { + p = list_entry(pos, struct alisp_object, list); + if (p->value.ptr == ptr) { + if (alisp_get_refs(p) > ALISP_MAX_REFS_LIMIT) + continue; + return incref_object(instance, p); + } + } + + return NULL; +} + +static struct alisp_object * new_integer(struct alisp_instance *instance, long value) +{ + struct alisp_object * obj; + + obj = search_object_integer(instance, value); + if (obj != NULL) + return obj; + obj = new_object(instance, ALISP_OBJ_INTEGER); + if (obj) { + list_add(&obj->list, &instance->used_objs_list[value & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_INTEGER]); + obj->value.i = value; + } + return obj; +} + +static struct alisp_object * new_float(struct alisp_instance *instance, double value) +{ + struct alisp_object * obj; + + obj = search_object_float(instance, value); + if (obj != NULL) + return obj; + obj = new_object(instance, ALISP_OBJ_FLOAT); + if (obj) { + list_add(&obj->list, &instance->used_objs_list[(long)value & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_FLOAT]); + obj->value.f = value; + } + return obj; +} + +static struct alisp_object * new_string(struct alisp_instance *instance, const char *str) +{ + struct alisp_object * obj; + + obj = search_object_string(instance, str); + if (obj != NULL) + return obj; + obj = new_object(instance, ALISP_OBJ_STRING); + if (obj) + list_add(&obj->list, &instance->used_objs_list[get_string_hash(str)][ALISP_OBJ_STRING]); + if (obj && (obj->value.s = strdup(str)) == NULL) { + delete_object(instance, obj); + nomem(); + return NULL; + } + return obj; +} + +static struct alisp_object * new_identifier(struct alisp_instance *instance, const char *id) +{ + struct alisp_object * obj; + + obj = search_object_identifier(instance, id); + if (obj != NULL) + return obj; + obj = new_object(instance, ALISP_OBJ_IDENTIFIER); + if (obj) + list_add(&obj->list, &instance->used_objs_list[get_string_hash(id)][ALISP_OBJ_IDENTIFIER]); + if (obj && (obj->value.s = strdup(id)) == NULL) { + delete_object(instance, obj); + nomem(); + return NULL; + } + return obj; +} + +static struct alisp_object * new_pointer(struct alisp_instance *instance, const void *ptr) +{ + struct alisp_object * obj; + + obj = search_object_pointer(instance, ptr); + if (obj != NULL) + return obj; + obj = new_object(instance, ALISP_OBJ_POINTER); + if (obj) { + list_add(&obj->list, &instance->used_objs_list[(long)ptr & ALISP_OBJ_PAIR_HASH_MASK][ALISP_OBJ_POINTER]); + obj->value.ptr = ptr; + } + return obj; +} + +static struct alisp_object * new_cons_pointer(struct alisp_instance * instance, const char *ptr_id, void *ptr) +{ + struct alisp_object * lexpr; + + if (ptr == NULL) + return &alsa_lisp_nil; + lexpr = new_object(instance, ALISP_OBJ_CONS); + if (lexpr == NULL) + return NULL; + lexpr->value.c.car = new_string(instance, ptr_id); + if (lexpr->value.c.car == NULL) + goto __end; + lexpr->value.c.cdr = new_pointer(instance, ptr); + if (lexpr->value.c.cdr == NULL) { + delete_object(instance, lexpr->value.c.car); + __end: + delete_object(instance, lexpr); + return NULL; + } + return lexpr; +} + +void alsa_lisp_init_objects(void) __attribute__ ((constructor)); + +void alsa_lisp_init_objects(void) +{ + memset(&alsa_lisp_nil, 0, sizeof(alsa_lisp_nil)); + alisp_set_type(&alsa_lisp_nil, ALISP_OBJ_NIL); + INIT_LIST_HEAD(&alsa_lisp_nil.list); + memset(&alsa_lisp_t, 0, sizeof(alsa_lisp_t)); + alisp_set_type(&alsa_lisp_t, ALISP_OBJ_T); + INIT_LIST_HEAD(&alsa_lisp_t.list); +} + +/* + * lexer + */ + +static int xgetc(struct alisp_instance *instance) +{ + instance->charno++; + if (instance->lex_bufp > instance->lex_buf) + return *--(instance->lex_bufp); + return snd_input_getc(instance->in); +} + +static inline void xungetc(struct alisp_instance *instance, int c) +{ + *(instance->lex_bufp)++ = c; + instance->charno--; +} + +static int init_lex(struct alisp_instance *instance) +{ + instance->charno = instance->lineno = 1; + instance->token_buffer_max = 10; + if ((instance->token_buffer = (char *)malloc(instance->token_buffer_max)) == NULL) { + nomem(); + return -ENOMEM; + } + instance->lex_bufp = instance->lex_buf; + return 0; +} + +static void done_lex(struct alisp_instance *instance) +{ + free(instance->token_buffer); +} + +static char * extend_buf(struct alisp_instance *instance, char *p) +{ + int off = p - instance->token_buffer; + + instance->token_buffer_max += 10; + instance->token_buffer = (char *)realloc(instance->token_buffer, instance->token_buffer_max); + if (instance->token_buffer == NULL) { + nomem(); + return NULL; + } + + return instance->token_buffer + off; +} + +static int gettoken(struct alisp_instance *instance) +{ + char *p; + int c; + + for (;;) { + c = xgetc(instance); + switch (c) { + case '\n': + ++instance->lineno; + break; + + case ' ': case '\f': case '\t': case '\v': case '\r': + break; + + case ';': + /* Comment: ";".*"\n" */ + while ((c = xgetc(instance)) != '\n' && c != EOF) + ; + if (c != EOF) + ++instance->lineno; + break; + + case '?': + /* Character: "?". */ + c = xgetc(instance); + sprintf(instance->token_buffer, "%d", c); + return instance->thistoken = ALISP_INTEGER; + + case '-': + /* Minus sign: "-". */ + c = xgetc(instance); + if (!isdigit(c)) { + xungetc(instance, c); + c = '-'; + goto got_id; + } + xungetc(instance, c); + c = '-'; + /* FALLTRHU */ + + case '0': + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + /* Integer: [0-9]+ */ + p = instance->token_buffer; + instance->thistoken = ALISP_INTEGER; + do { + __ok: + if (p - instance->token_buffer >= instance->token_buffer_max - 1) { + p = extend_buf(instance, p); + if (p == NULL) + return instance->thistoken = EOF; + } + *p++ = c; + c = xgetc(instance); + if (c == '.' && instance->thistoken == ALISP_INTEGER) { + c = xgetc(instance); + xungetc(instance, c); + if (isdigit(c)) { + instance->thistoken = ALISP_FLOAT; + c = '.'; + goto __ok; + } else { + c = '.'; + } + } else if (c == 'e' && instance->thistoken == ALISP_FLOAT) { + c = xgetc(instance); + if (isdigit(c)) { + instance->thistoken = ALISP_FLOATE; + goto __ok; + } + } + } while (isdigit(c)); + xungetc(instance, c); + *p = '\0'; + return instance->thistoken; + + got_id: + case '!': case '_': case '+': case '*': case '/': case '%': + case '<': case '>': case '=': case '&': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': + /* Identifier: [!-/+*%<>=&a-zA-Z_][-/+*%<>=&a-zA-Z_0-9]* */ + p = instance->token_buffer; + do { + if (p - instance->token_buffer >= instance->token_buffer_max - 1) { + p = extend_buf(instance, p); + if (p == NULL) + return instance->thistoken = EOF; + } + *p++ = c; + c = xgetc(instance); + } while (isalnum(c) || strchr("!_-+*/%<>=&", c) != NULL); + xungetc(instance, c); + *p = '\0'; + return instance->thistoken = ALISP_IDENTIFIER; + + case '"': + /* String: "\""([^"]|"\\".)*"\"" */ + p = instance->token_buffer; + while ((c = xgetc(instance)) != '"' && c != EOF) { + if (p - instance->token_buffer >= instance->token_buffer_max - 1) { + p = extend_buf(instance, p); + if (p == NULL) + return instance->thistoken = EOF; + } + if (c == '\\') { + c = xgetc(instance); + switch (c) { + case '\n': ++instance->lineno; break; + case 'a': *p++ = '\a'; break; + case 'b': *p++ = '\b'; break; + case 'f': *p++ = '\f'; break; + case 'n': *p++ = '\n'; break; + case 'r': *p++ = '\r'; break; + case 't': *p++ = '\t'; break; + case 'v': *p++ = '\v'; break; + default: *p++ = c; + } + } else { + if (c == '\n') + ++instance->lineno; + *p++ = c; + } + } + *p = '\0'; + return instance->thistoken = ALISP_STRING; + + default: + return instance->thistoken = c; + } + } +} + +/* + * parser + */ + +static struct alisp_object * parse_form(struct alisp_instance *instance) +{ + int thistoken; + struct alisp_object * p, * first = NULL, * prev = NULL; + + while ((thistoken = gettoken(instance)) != ')' && thistoken != EOF) { + /* + * Parse a dotted pair notation. + */ + if (thistoken == '.') { + gettoken(instance); + if (prev == NULL) { + lisp_error(instance, "unexpected '.'"); + __err: + delete_tree(instance, first); + return NULL; + } + prev->value.c.cdr = parse_object(instance, 1); + if (prev->value.c.cdr == NULL) + goto __err; + if ((thistoken = gettoken(instance)) != ')') { + lisp_error(instance, "expected ')'"); + goto __err; + } + break; + } + + p = new_object(instance, ALISP_OBJ_CONS); + if (p == NULL) + goto __err; + + if (first == NULL) + first = p; + if (prev != NULL) + prev->value.c.cdr = p; + + p->value.c.car = parse_object(instance, 1); + if (p->value.c.car == NULL) + goto __err; + + prev = p; + } + + if (first == NULL) + return &alsa_lisp_nil; + else + return first; +} + +static struct alisp_object * quote_object(struct alisp_instance *instance, struct alisp_object * obj) +{ + struct alisp_object * p; + + if (obj == NULL) + goto __end1; + + p = new_object(instance, ALISP_OBJ_CONS); + if (p == NULL) + goto __end1; + + p->value.c.car = new_identifier(instance, "quote"); + if (p->value.c.car == NULL) + goto __end; + p->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); + if (p->value.c.cdr == NULL) { + delete_object(instance, p->value.c.car); + __end: + delete_object(instance, p); + __end1: + delete_tree(instance, obj); + return NULL; + } + + p->value.c.cdr->value.c.car = obj; + return p; +} + +static inline struct alisp_object * parse_quote(struct alisp_instance *instance) +{ + return quote_object(instance, parse_object(instance, 0)); +} + +static struct alisp_object * parse_object(struct alisp_instance *instance, int havetoken) +{ + int thistoken; + struct alisp_object * p = NULL; + + if (!havetoken) + thistoken = gettoken(instance); + else + thistoken = instance->thistoken; + + switch (thistoken) { + case EOF: + break; + case '(': + p = parse_form(instance); + break; + case '\'': + p = parse_quote(instance); + break; + case ALISP_IDENTIFIER: + if (!strcmp(instance->token_buffer, "t")) + p = &alsa_lisp_t; + else if (!strcmp(instance->token_buffer, "nil")) + p = &alsa_lisp_nil; + else { + p = new_identifier(instance, instance->token_buffer); + } + break; + case ALISP_INTEGER: { + p = new_integer(instance, atol(instance->token_buffer)); + break; + } + case ALISP_FLOAT: + case ALISP_FLOATE: { + p = new_float(instance, atof(instance->token_buffer)); + break; + } + case ALISP_STRING: + p = new_string(instance, instance->token_buffer); + break; + default: + lisp_warn(instance, "%d:%d: unexpected character `%c'", instance->lineno, instance->charno, thistoken); + break; + } + + return p; +} + +/* + * object manipulation + */ + +static struct alisp_object_pair * set_object_direct(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * value) +{ + struct alisp_object_pair *p; + const char *id; + + id = name->value.s; + p = (struct alisp_object_pair *)malloc(sizeof(struct alisp_object_pair)); + if (p == NULL) { + nomem(); + return NULL; + } + p->name = strdup(id); + if (p->name == NULL) { + delete_tree(instance, value); + free(p); + return NULL; + } + list_add(&p->list, &instance->setobjs_list[get_string_hash(id)]); + p->value = value; + return p; +} + +static int check_set_object(struct alisp_instance * instance, struct alisp_object * name) +{ + if (name == &alsa_lisp_nil) { + lisp_warn(instance, "setting the value of a nil object"); + return 0; + } + if (name == &alsa_lisp_t) { + lisp_warn(instance, "setting the value of a t object"); + return 0; + } + if (!alisp_compare_type(name, ALISP_OBJ_IDENTIFIER) && + !alisp_compare_type(name, ALISP_OBJ_STRING)) { + lisp_warn(instance, "setting the value of an object with non-indentifier"); + return 0; + } + return 1; +} + +static struct alisp_object_pair * set_object(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * value) +{ + struct list_head *pos; + struct alisp_object_pair *p; + const char *id; + + if (name == NULL || value == NULL) + return NULL; + + id = name->value.s; + + list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { + p = list_entry(pos, struct alisp_object_pair, list); + if (!strcmp(p->name, id)) { + delete_tree(instance, p->value); + p->value = value; + return p; + } + } + + p = (struct alisp_object_pair *)malloc(sizeof(struct alisp_object_pair)); + if (p == NULL) { + nomem(); + return NULL; + } + p->name = strdup(id); + if (p->name == NULL) { + delete_tree(instance, value); + free(p); + return NULL; + } + list_add(&p->list, &instance->setobjs_list[get_string_hash(id)]); + p->value = value; + return p; +} + +static struct alisp_object * unset_object(struct alisp_instance *instance, struct alisp_object * name) +{ + struct list_head *pos; + struct alisp_object *res; + struct alisp_object_pair *p; + const char *id; + + if (!alisp_compare_type(name, ALISP_OBJ_IDENTIFIER) && + !alisp_compare_type(name, ALISP_OBJ_STRING)) { + lisp_warn(instance, "unset object with a non-indentifier"); + return &alsa_lisp_nil; + } + id = name->value.s; + + list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { + p = list_entry(pos, struct alisp_object_pair, list); + if (!strcmp(p->name, id)) { + list_del(&p->list); + res = p->value; + free((void *)p->name); + free(p); + return res; + } + } + + return &alsa_lisp_nil; +} + +static struct alisp_object * get_object1(struct alisp_instance *instance, const char *id) +{ + struct alisp_object_pair *p; + struct list_head *pos; + + list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { + p = list_entry(pos, struct alisp_object_pair, list); + if (!strcmp(p->name, id)) + return p->value; + } + + return &alsa_lisp_nil; +} + +static struct alisp_object * get_object(struct alisp_instance *instance, struct alisp_object * name) +{ + if (!alisp_compare_type(name, ALISP_OBJ_IDENTIFIER) && + !alisp_compare_type(name, ALISP_OBJ_STRING)) { + delete_tree(instance, name); + return &alsa_lisp_nil; + } + return get_object1(instance, name->value.s); +} + +static struct alisp_object * replace_object(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * onew) +{ + struct alisp_object_pair *p; + struct alisp_object *r; + struct list_head *pos; + const char *id; + + if (!alisp_compare_type(name, ALISP_OBJ_IDENTIFIER) && + !alisp_compare_type(name, ALISP_OBJ_STRING)) { + delete_tree(instance, name); + return &alsa_lisp_nil; + } + id = name->value.s; + list_for_each(pos, &instance->setobjs_list[get_string_hash(id)]) { + p = list_entry(pos, struct alisp_object_pair, list); + if (!strcmp(p->name, id)) { + r = p->value; + p->value = onew; + return r; + } + } + + return NULL; +} + +static void dump_objects(struct alisp_instance *instance, const char *fname) +{ + struct alisp_object_pair *p; + snd_output_t *out; + struct list_head *pos; + int i, err; + + if (!strcmp(fname, "-")) + err = snd_output_stdio_attach(&out, stdout, 0); + else + err = snd_output_stdio_open(&out, fname, "w+"); + if (err < 0) { + SNDERR("alisp: cannot open file '%s' for writting (%s)", fname, snd_strerror(errno)); + return; + } + + for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) { + list_for_each(pos, &instance->setobjs_list[i]) { + p = list_entry(pos, struct alisp_object_pair, list); + if (alisp_compare_type(p->value, ALISP_OBJ_CONS) && + alisp_compare_type(p->value->value.c.car, ALISP_OBJ_IDENTIFIER) && + !strcmp(p->value->value.c.car->value.s, "lambda")) { + snd_output_printf(out, "(defun %s ", p->name); + princ_cons(out, p->value->value.c.cdr); + snd_output_printf(out, ")\n"); + continue; + } + snd_output_printf(out, "(setq %s '", p->name); + princ_object(out, p->value); + snd_output_printf(out, ")\n"); + } + } + snd_output_close(out); +} + +static const char *obj_type_str(struct alisp_object * p) +{ + switch (alisp_get_type(p)) { + case ALISP_OBJ_NIL: return "nil"; + case ALISP_OBJ_T: return "t"; + case ALISP_OBJ_INTEGER: return "integer"; + case ALISP_OBJ_FLOAT: return "float"; + case ALISP_OBJ_IDENTIFIER: return "identifier"; + case ALISP_OBJ_STRING: return "string"; + case ALISP_OBJ_POINTER: return "pointer"; + case ALISP_OBJ_CONS: return "cons"; + default: assert(0); + } +} + +static void print_obj_lists(struct alisp_instance *instance, snd_output_t *out) +{ + struct list_head *pos; + struct alisp_object * p; + int i, j; + + snd_output_printf(out, "** used objects\n"); + for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) + for (j = 0; j <= ALISP_OBJ_LAST_SEARCH; j++) + list_for_each(pos, &instance->used_objs_list[i][j]) { + p = list_entry(pos, struct alisp_object, list); + snd_output_printf(out, "** %p (%s) (", p, obj_type_str(p)); + if (!alisp_compare_type(p, ALISP_OBJ_CONS)) + princ_object(out, p); + else + snd_output_printf(out, "cons"); + snd_output_printf(out, ") refs=%i\n", alisp_get_refs(p)); + } + snd_output_printf(out, "** free objects\n"); + list_for_each(pos, &instance->free_objs_list) { + p = list_entry(pos, struct alisp_object, list); + snd_output_printf(out, "** %p\n", p); + } +} + +static void dump_obj_lists(struct alisp_instance *instance, const char *fname) +{ + snd_output_t *out; + int err; + + if (!strcmp(fname, "-")) + err = snd_output_stdio_attach(&out, stdout, 0); + else + err = snd_output_stdio_open(&out, fname, "w+"); + if (err < 0) { + SNDERR("alisp: cannot open file '%s' for writting (%s)", fname, snd_strerror(errno)); + return; + } + + print_obj_lists(instance, out); + + snd_output_close(out); +} + +/* + * functions + */ + +static int count_list(struct alisp_object * p) +{ + int i = 0; + + while (p != &alsa_lisp_nil && alisp_compare_type(p, ALISP_OBJ_CONS)) { + p = p->value.c.cdr; + ++i; + } + + return i; +} + +static inline struct alisp_object * car(struct alisp_object * p) +{ + if (alisp_compare_type(p, ALISP_OBJ_CONS)) + return p->value.c.car; + + return &alsa_lisp_nil; +} + +static inline struct alisp_object * cdr(struct alisp_object * p) +{ + if (alisp_compare_type(p, ALISP_OBJ_CONS)) + return p->value.c.cdr; + + return &alsa_lisp_nil; +} + +/* + * Syntax: (car expr) + */ +static struct alisp_object * F_car(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object *p1 = car(args), *p2; + delete_tree(instance, cdr(args)); + delete_object(instance, args); + p1 = eval(instance, p1); + delete_tree(instance, cdr(p1)); + p2 = car(p1); + delete_object(instance, p1); + return p2; +} + +/* + * Syntax: (cdr expr) + */ +static struct alisp_object * F_cdr(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object *p1 = car(args), *p2; + delete_tree(instance, cdr(args)); + delete_object(instance, args); + p1 = eval(instance, p1); + delete_tree(instance, car(p1)); + p2 = cdr(p1); + delete_object(instance, p1); + return p2; +} + +/* + * Syntax: (+ expr...) + */ +static struct alisp_object * F_add(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * n; + long v = 0; + double f = 0; + int type = ALISP_OBJ_INTEGER; + + p1 = eval(instance, car(p)); + for (;;) { + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + if (type == ALISP_OBJ_FLOAT) + f += p1->value.i; + else + v += p1->value.i; + } else if (alisp_compare_type(p1, ALISP_OBJ_FLOAT)) { + f += p1->value.f + v; + v = 0; + type = ALISP_OBJ_FLOAT; + } else { + lisp_warn(instance, "sum with a non integer or float operand"); + } + delete_tree(instance, p1); + p = cdr(n = p); + delete_object(instance, n); + if (p == &alsa_lisp_nil) + break; + p1 = eval(instance, car(p)); + } + if (type == ALISP_OBJ_INTEGER) { + return new_integer(instance, v); + } else { + return new_float(instance, f); + } +} + +/* + * Syntax: (concat expr...) + */ +static struct alisp_object * F_concat(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * n; + char *str = NULL, *str1; + + p1 = eval(instance, car(p)); + for (;;) { + if (alisp_compare_type(p1, ALISP_OBJ_STRING)) { + str1 = realloc(str, (str ? strlen(str) : 0) + strlen(p1->value.s) + 1); + if (str1 == NULL) { + nomem(); + free(str); + return NULL; + } + if (str == NULL) + strcpy(str1, p1->value.s); + else + strcat(str1, p1->value.s); + str = str1; + } else { + lisp_warn(instance, "concat with a non string or identifier operand"); + } + delete_tree(instance, p1); + p = cdr(n = p); + delete_object(instance, n); + if (p == &alsa_lisp_nil) + break; + p1 = eval(instance, car(p)); + } + if (str) { + p = new_string(instance, str); + free(str); + } else { + p = &alsa_lisp_nil; + } + return p; +} + +/* + * Syntax: (- expr...) + */ +static struct alisp_object * F_sub(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * n; + long v = 0; + double f = 0; + int type = ALISP_OBJ_INTEGER; + + do { + p1 = eval(instance, car(p)); + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + if (p == args && cdr(p) != &alsa_lisp_nil) { + v = p1->value.i; + } else { + if (type == ALISP_OBJ_FLOAT) + f -= p1->value.i; + else + v -= p1->value.i; + } + } else if (alisp_compare_type(p1, ALISP_OBJ_FLOAT)) { + if (type == ALISP_OBJ_INTEGER) { + f = v; + type = ALISP_OBJ_FLOAT; + } + if (p == args && cdr(p) != &alsa_lisp_nil) + f = p1->value.f; + else { + f -= p1->value.f; + } + } else + lisp_warn(instance, "difference with a non integer or float operand"); + delete_tree(instance, p1); + n = cdr(p); + delete_object(instance, p); + p = n; + } while (p != &alsa_lisp_nil); + + if (type == ALISP_OBJ_INTEGER) { + return new_integer(instance, v); + } else { + return new_float(instance, f); + } +} + +/* + * Syntax: (* expr...) + */ +static struct alisp_object * F_mul(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * n; + long v = 1; + double f = 1; + int type = ALISP_OBJ_INTEGER; + + do { + p1 = eval(instance, car(p)); + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + if (type == ALISP_OBJ_FLOAT) + f *= p1->value.i; + else + v *= p1->value.i; + } else if (alisp_compare_type(p1, ALISP_OBJ_FLOAT)) { + f *= p1->value.f * v; v = 1; + type = ALISP_OBJ_FLOAT; + } else { + lisp_warn(instance, "product with a non integer or float operand"); + } + delete_tree(instance, p1); + n = cdr(p); + delete_object(instance, p); + p = n; + } while (p != &alsa_lisp_nil); + + if (type == ALISP_OBJ_INTEGER) { + return new_integer(instance, v); + } else { + return new_float(instance, f); + } +} + +/* + * Syntax: (/ expr...) + */ +static struct alisp_object * F_div(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * n; + long v = 0; + double f = 0; + int type = ALISP_OBJ_INTEGER; + + do { + p1 = eval(instance, car(p)); + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + if (p == args && cdr(p) != &alsa_lisp_nil) { + v = p1->value.i; + } else { + if (p1->value.i == 0) { + lisp_warn(instance, "division by zero"); + v = 0; + f = 0; + break; + } else { + if (type == ALISP_OBJ_FLOAT) + f /= p1->value.i; + else + v /= p1->value.i; + } + } + } else if (alisp_compare_type(p1, ALISP_OBJ_FLOAT)) { + if (type == ALISP_OBJ_INTEGER) { + f = v; + type = ALISP_OBJ_FLOAT; + } + if (p == args && cdr(p) != &alsa_lisp_nil) { + f = p1->value.f; + } else { + if (p1->value.f == 0) { + lisp_warn(instance, "division by zero"); + f = 0; + break; + } else { + f /= p1->value.i; + } + } + } else + lisp_warn(instance, "quotient with a non integer or float operand"); + delete_tree(instance, p1); + n = cdr(p); + delete_object(instance, p); + p = n; + } while (p != &alsa_lisp_nil); + + if (type == ALISP_OBJ_INTEGER) { + return new_integer(instance, v); + } else { + return new_float(instance, f); + } +} + +/* + * Syntax: (% expr1 expr2) + */ +static struct alisp_object * F_mod(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * p3; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER) && + alisp_compare_type(p2, ALISP_OBJ_INTEGER)) { + if (p2->value.i == 0) { + lisp_warn(instance, "module by zero"); + p3 = new_integer(instance, 0); + } else { + p3 = new_integer(instance, p1->value.i % p2->value.i); + } + } else if ((alisp_compare_type(p1, ALISP_OBJ_INTEGER) || + alisp_compare_type(p1, ALISP_OBJ_FLOAT)) && + (alisp_compare_type(p2, ALISP_OBJ_INTEGER) || + alisp_compare_type(p2, ALISP_OBJ_FLOAT))) { + double f1, f2; + f1 = alisp_compare_type(p1, ALISP_OBJ_INTEGER) ? p1->value.i : p1->value.f; + f2 = alisp_compare_type(p2, ALISP_OBJ_INTEGER) ? p2->value.i : p2->value.f; + f1 = fmod(f1, f2); + if (f1 == EDOM) { + lisp_warn(instance, "module by zero"); + p3 = new_float(instance, 0); + } else { + p3 = new_float(instance, f1); + } + } else { + lisp_warn(instance, "module with a non integer or float operand"); + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return p3; +} + +/* + * Syntax: (< expr1 expr2) + */ +static struct alisp_object * F_lt(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER) && + alisp_compare_type(p2, ALISP_OBJ_INTEGER)) { + if (p1->value.i < p2->value.i) { + __true: + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + } else if ((alisp_compare_type(p1, ALISP_OBJ_INTEGER) || + alisp_compare_type(p1, ALISP_OBJ_FLOAT)) && + (alisp_compare_type(p2, ALISP_OBJ_INTEGER) || + alisp_compare_type(p2, ALISP_OBJ_FLOAT))) { + double f1, f2; + f1 = alisp_compare_type(p1, ALISP_OBJ_INTEGER) ? p1->value.i : p1->value.f; + f2 = alisp_compare_type(p2, ALISP_OBJ_INTEGER) ? p2->value.i : p2->value.f; + if (f1 < f2) + goto __true; + } else { + lisp_warn(instance, "comparison with a non integer or float operand"); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (> expr1 expr2) + */ +static struct alisp_object * F_gt(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER) && + alisp_compare_type(p2, ALISP_OBJ_INTEGER)) { + if (p1->value.i > p2->value.i) { + __true: + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + } else if ((alisp_compare_type(p1, ALISP_OBJ_INTEGER) || + alisp_compare_type(p1, ALISP_OBJ_FLOAT)) && + (alisp_compare_type(p2, ALISP_OBJ_INTEGER) || + alisp_compare_type(p2, ALISP_OBJ_FLOAT))) { + double f1, f2; + f1 = alisp_compare_type(p1, ALISP_OBJ_INTEGER) ? p1->value.i : p1->value.f; + f2 = alisp_compare_type(p2, ALISP_OBJ_INTEGER) ? p2->value.i : p2->value.f; + if (f1 > f2) + goto __true; + } else { + lisp_warn(instance, "comparison with a non integer or float operand"); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (<= expr1 expr2) + */ +static struct alisp_object * F_le(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER) && + alisp_compare_type(p2, ALISP_OBJ_INTEGER)) { + if (p1->value.i <= p2->value.i) { + __true: + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + } else if ((alisp_compare_type(p1, ALISP_OBJ_INTEGER) || + alisp_compare_type(p1, ALISP_OBJ_FLOAT)) && + (alisp_compare_type(p2, ALISP_OBJ_INTEGER) || + alisp_compare_type(p2, ALISP_OBJ_FLOAT))) { + double f1, f2; + f1 = alisp_compare_type(p1, ALISP_OBJ_INTEGER) ? p1->value.i : p1->value.f; + f2 = alisp_compare_type(p2, ALISP_OBJ_INTEGER) ? p2->value.i : p2->value.f; + if (f1 <= f2) + goto __true; + } else { + lisp_warn(instance, "comparison with a non integer or float operand"); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (>= expr1 expr2) + */ +static struct alisp_object * F_ge(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER) && + alisp_compare_type(p2, ALISP_OBJ_INTEGER)) { + if (p1->value.i >= p2->value.i) { + __true: + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + } else if ((alisp_compare_type(p1, ALISP_OBJ_INTEGER) || + alisp_compare_type(p1, ALISP_OBJ_FLOAT)) && + (alisp_compare_type(p2, ALISP_OBJ_INTEGER) || + alisp_compare_type(p2, ALISP_OBJ_FLOAT))) { + double f1, f2; + f1 = alisp_compare_type(p1, ALISP_OBJ_INTEGER) ? p1->value.i : p1->value.f; + f2 = alisp_compare_type(p2, ALISP_OBJ_INTEGER) ? p2->value.i : p2->value.f; + if (f1 >= f2) + goto __true; + } else { + lisp_warn(instance, "comparison with a non integer or float operand"); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (= expr1 expr2) + */ +static struct alisp_object * F_numeq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (alisp_compare_type(p1, ALISP_OBJ_INTEGER) && + alisp_compare_type(p2, ALISP_OBJ_INTEGER)) { + if (p1->value.i == p2->value.i) { + __true: + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + } else if ((alisp_compare_type(p1, ALISP_OBJ_INTEGER) || + alisp_compare_type(p1, ALISP_OBJ_FLOAT)) && + (alisp_compare_type(p2, ALISP_OBJ_INTEGER) || + alisp_compare_type(p2, ALISP_OBJ_FLOAT))) { + double f1, f2; + f1 = alisp_compare_type(p1, ALISP_OBJ_INTEGER) ? p1->value.i : p1->value.f; + f2 = alisp_compare_type(p2, ALISP_OBJ_INTEGER) ? p2->value.i : p2->value.f; + if (f1 == f2) + goto __true; + } else { + lisp_warn(instance, "comparison with a non integer or float operand"); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (!= expr1 expr2) + */ +static struct alisp_object * F_numneq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p; + + p = F_numeq(instance, args); + if (p == &alsa_lisp_nil) + return &alsa_lisp_t; + return &alsa_lisp_nil; +} + +/* + * Syntax: (exfun name) + * Test, if a function exists + */ +static struct alisp_object * F_exfun(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + p2 = get_object(instance, p1); + if (p2 == &alsa_lisp_nil) { + delete_tree(instance, p1); + return &alsa_lisp_nil; + } + p2 = car(p2); + if (alisp_compare_type(p2, ALISP_OBJ_IDENTIFIER) && + !strcmp(p2->value.s, "lambda")) { + delete_tree(instance, p1); + return &alsa_lisp_t; + } + delete_tree(instance, p1); + return &alsa_lisp_nil; +} + +static void princ_string(snd_output_t *out, char *s) +{ + char *p; + + snd_output_putc(out, '"'); + for (p = s; *p != '\0'; ++p) + switch (*p) { + case '\a': snd_output_putc(out, '\\'); snd_output_putc(out, 'a'); break; + case '\b': snd_output_putc(out, '\\'); snd_output_putc(out, 'b'); break; + case '\f': snd_output_putc(out, '\\'); snd_output_putc(out, 'f'); break; + case '\n': snd_output_putc(out, '\\'); snd_output_putc(out, 'n'); break; + case '\r': snd_output_putc(out, '\\'); snd_output_putc(out, 'r'); break; + case '\t': snd_output_putc(out, '\\'); snd_output_putc(out, 't'); break; + case '\v': snd_output_putc(out, '\\'); snd_output_putc(out, 'v'); break; + case '"': snd_output_putc(out, '\\'); snd_output_putc(out, '"'); break; + default: snd_output_putc(out, *p); + } + snd_output_putc(out, '"'); +} + +static void princ_cons(snd_output_t *out, struct alisp_object * p) +{ + do { + princ_object(out, p->value.c.car); + p = p->value.c.cdr; + if (p != &alsa_lisp_nil) { + snd_output_putc(out, ' '); + if (!alisp_compare_type(p, ALISP_OBJ_CONS)) { + snd_output_printf(out, ". "); + princ_object(out, p); + } + } + } while (p != &alsa_lisp_nil && alisp_compare_type(p, ALISP_OBJ_CONS)); +} + +static void princ_object(snd_output_t *out, struct alisp_object * p) +{ + switch (alisp_get_type(p)) { + case ALISP_OBJ_NIL: + snd_output_printf(out, "nil"); + break; + case ALISP_OBJ_T: + snd_output_putc(out, 't'); + break; + case ALISP_OBJ_IDENTIFIER: + snd_output_printf(out, "%s", p->value.s); + break; + case ALISP_OBJ_STRING: + princ_string(out, p->value.s); + break; + case ALISP_OBJ_INTEGER: + snd_output_printf(out, "%ld", p->value.i); + break; + case ALISP_OBJ_FLOAT: + snd_output_printf(out, "%f", p->value.f); + break; + case ALISP_OBJ_POINTER: + snd_output_printf(out, "<%p>", p->value.ptr); + break; + case ALISP_OBJ_CONS: + snd_output_putc(out, '('); + princ_cons(out, p); + snd_output_putc(out, ')'); + } +} + +/* + * Syntax: (princ expr...) + */ +static struct alisp_object * F_princ(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1 = NULL, * n; + + do { + if (p1) + delete_tree(instance, p1); + p1 = eval(instance, car(p)); + if (alisp_compare_type(p1, ALISP_OBJ_STRING)) + snd_output_printf(instance->out, "%s", p1->value.s); + else + princ_object(instance->out, p1); + n = cdr(p); + delete_object(instance, p); + p = n; + } while (p != &alsa_lisp_nil); + + return p1; +} + +/* + * Syntax: (atom expr) + */ +static struct alisp_object * F_atom(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p; + + p = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (p == NULL) + return NULL; + + switch (alisp_get_type(p)) { + case ALISP_OBJ_T: + case ALISP_OBJ_NIL: + case ALISP_OBJ_INTEGER: + case ALISP_OBJ_FLOAT: + case ALISP_OBJ_STRING: + case ALISP_OBJ_IDENTIFIER: + case ALISP_OBJ_POINTER: + delete_tree(instance, p); + return &alsa_lisp_t; + default: + break; + } + + delete_tree(instance, p); + return &alsa_lisp_nil; +} + +/* + * Syntax: (cons expr1 expr2) + */ +static struct alisp_object * F_cons(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p; + + p = new_object(instance, ALISP_OBJ_CONS); + if (p) { + p->value.c.car = eval(instance, car(args)); + p->value.c.cdr = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + } else { + delete_tree(instance, args); + } + + return p; +} + +/* + * Syntax: (list expr1...) + */ +static struct alisp_object * F_list(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * first = NULL, * prev = NULL, * p1; + + if (p == &alsa_lisp_nil) + return &alsa_lisp_nil; + + do { + p1 = new_object(instance, ALISP_OBJ_CONS); + if (p1 == NULL) { + delete_tree(instance, p); + delete_tree(instance, first); + return NULL; + } + p1->value.c.car = eval(instance, car(p)); + if (p1->value.c.car == NULL) { + delete_tree(instance, first); + delete_tree(instance, cdr(p)); + delete_object(instance, p); + return NULL; + } + if (first == NULL) + first = p1; + if (prev != NULL) + prev->value.c.cdr = p1; + prev = p1; + p = cdr(p1 = p); + delete_object(instance, p1); + } while (p != &alsa_lisp_nil); + + return first; +} + +static inline int eq(struct alisp_object * p1, struct alisp_object * p2) +{ + return p1 == p2; +} + +static int equal(struct alisp_object * p1, struct alisp_object * p2) +{ + int type1, type2; + + if (eq(p1, p2)) + return 1; + + type1 = alisp_get_type(p1); + type2 = alisp_get_type(p2); + + if (type1 == ALISP_OBJ_CONS || type2 == ALISP_OBJ_CONS) + return 0; + + if (type1 == type2) { + switch (type1) { + case ALISP_OBJ_STRING: + return !strcmp(p1->value.s, p2->value.s); + case ALISP_OBJ_INTEGER: + return p1->value.i == p2->value.i; + case ALISP_OBJ_FLOAT: + return p1->value.i == p2->value.i; + } + } + + return 0; +} + +/* + * Syntax: (eq expr1 expr2) + */ +static struct alisp_object * F_eq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (eq(p1, p2)) { + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (equal expr1 expr2) + */ +static struct alisp_object * F_equal(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (equal(p1, p2)) { + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_t; + } + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (quote expr) + */ +static struct alisp_object * F_quote(struct alisp_instance *instance ATTRIBUTE_UNUSED, struct alisp_object * args) +{ + struct alisp_object *p = car(args); + + delete_tree(instance, cdr(args)); + delete_object(instance, args); + return p; +} + +/* + * Syntax: (and expr...) + */ +static struct alisp_object * F_and(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1 = NULL, * n; + + do { + if (p1) + delete_tree(instance, p1); + p1 = eval(instance, car(p)); + if (p1 == &alsa_lisp_nil) { + delete_tree(instance, p1); + delete_tree(instance, cdr(p)); + delete_object(instance, p); + return &alsa_lisp_nil; + } + p = cdr(n = p); + delete_object(instance, n); + } while (p != &alsa_lisp_nil); + + return p1; +} + +/* + * Syntax: (or expr...) + */ +static struct alisp_object * F_or(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1 = NULL, * n; + + do { + if (p1) + delete_tree(instance, p1); + p1 = eval(instance, car(p)); + if (p1 != &alsa_lisp_nil) { + delete_tree(instance, cdr(p)); + delete_object(instance, p); + return p1; + } + p = cdr(n = p); + delete_object(instance, n); + } while (p != &alsa_lisp_nil); + + return &alsa_lisp_nil; +} + +/* + * Syntax: (not expr) + * Syntax: (null expr) + */ +static struct alisp_object * F_not(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = eval(instance, car(args)); + + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (p != &alsa_lisp_nil) { + delete_tree(instance, p); + return &alsa_lisp_nil; + } + + delete_tree(instance, p); + return &alsa_lisp_t; +} + +/* + * Syntax: (cond (expr1 [expr2])...) + */ +static struct alisp_object * F_cond(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * p2, * p3; + + do { + p1 = car(p); + if ((p2 = eval(instance, car(p1))) != &alsa_lisp_nil) { + p3 = cdr(p1); + delete_object(instance, p1); + delete_tree(instance, cdr(p)); + delete_object(instance, p); + if (p3 != &alsa_lisp_nil) { + delete_tree(instance, p2); + return F_progn(instance, p3); + } else { + delete_tree(instance, p3); + return p2; + } + } else { + delete_tree(instance, p2); + delete_tree(instance, cdr(p1)); + delete_object(instance, p1); + } + p = cdr(p2 = p); + delete_object(instance, p2); + } while (p != &alsa_lisp_nil); + + return &alsa_lisp_nil; +} + +/* + * Syntax: (if expr then-expr else-expr...) + */ +static struct alisp_object * F_if(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * p3; + + p1 = car(args); + p2 = car(cdr(args)); + p3 = cdr(cdr(args)); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + p1 = eval(instance, p1); + if (p1 != &alsa_lisp_nil) { + delete_tree(instance, p1); + delete_tree(instance, p3); + return eval(instance, p2); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return F_progn(instance, p3); +} + +/* + * Syntax: (when expr then-expr...) + */ +static struct alisp_object * F_when(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = car(args); + p2 = cdr(args); + delete_object(instance, args); + if ((p1 = eval(instance, p1)) != &alsa_lisp_nil) { + delete_tree(instance, p1); + return F_progn(instance, p2); + } else { + delete_tree(instance, p1); + delete_tree(instance, p2); + } + + return &alsa_lisp_nil; +} + +/* + * Syntax: (unless expr else-expr...) + */ +static struct alisp_object * F_unless(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2; + + p1 = car(args); + p2 = cdr(args); + delete_object(instance, args); + if ((p1 = eval(instance, p1)) == &alsa_lisp_nil) { + return F_progn(instance, p2); + } else { + delete_tree(instance, p1); + delete_tree(instance, p2); + } + + return &alsa_lisp_nil; +} + +/* + * Syntax: (while expr exprs...) + */ +static struct alisp_object * F_while(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * p3; + + p1 = car(args); + p2 = cdr(args); + + delete_object(instance, args); + while (1) { + incref_tree(instance, p1); + if ((p3 = eval(instance, p1)) == &alsa_lisp_nil) + break; + delete_tree(instance, p3); + incref_tree(instance, p2); + delete_tree(instance, F_progn(instance, p2)); + } + + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; +} + +/* + * Syntax: (progn expr...) + */ +static struct alisp_object * F_progn(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1 = NULL, * n; + + do { + if (p1) + delete_tree(instance, p1); + p1 = eval(instance, car(p)); + n = cdr(p); + delete_object(instance, p); + p = n; + } while (p != &alsa_lisp_nil); + + return p1; +} + +/* + * Syntax: (prog1 expr...) + */ +static struct alisp_object * F_prog1(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * first = NULL, * p1; + + do { + p1 = eval(instance, car(p)); + if (first == NULL) + first = p1; + else + delete_tree(instance, p1); + p1 = cdr(p); + delete_object(instance, p); + p = p1; + } while (p != &alsa_lisp_nil); + + if (first == NULL) + first = &alsa_lisp_nil; + + return first; +} + +/* + * Syntax: (prog2 expr...) + */ +static struct alisp_object * F_prog2(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * second = NULL, * p1; + int i = 0; + + do { + ++i; + p1 = eval(instance, car(p)); + if (i == 2) + second = p1; + else + delete_tree(instance, p1); + p1 = cdr(p); + delete_object(instance, p); + p = p1; + } while (p != &alsa_lisp_nil); + + if (second == NULL) + second = &alsa_lisp_nil; + + return second; +} + +/* + * Syntax: (set name value) + */ +static struct alisp_object * F_set(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1 = eval(instance, car(args)), + * p2 = eval(instance, car(cdr(args))); + + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + if (!check_set_object(instance, p1)) { + delete_tree(instance, p2); + p2 = &alsa_lisp_nil; + } else { + if (set_object(instance, p1, p2) == NULL) { + delete_tree(instance, p1); + delete_tree(instance, p2); + return NULL; + } + } + delete_tree(instance, p1); + return incref_tree(instance, p2); +} + +/* + * Syntax: (unset name) + */ +static struct alisp_object * F_unset(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1 = eval(instance, car(args)); + + delete_tree(instance, unset_object(instance, p1)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + return p1; +} + +/* + * Syntax: (setq name value...) + * Syntax: (setf name value...) + * `name' is not evalled + */ +static struct alisp_object * F_setq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1, * p2 = NULL, *n; + + do { + p1 = car(p); + p2 = eval(instance, car(cdr(p))); + n = cdr(cdr(p)); + delete_object(instance, cdr(p)); + delete_object(instance, p); + if (!check_set_object(instance, p1)) { + delete_tree(instance, p2); + p2 = &alsa_lisp_nil; + } else { + if (set_object(instance, p1, p2) == NULL) { + delete_tree(instance, p1); + delete_tree(instance, p2); + return NULL; + } + } + delete_tree(instance, p1); + p = n; + } while (p != &alsa_lisp_nil); + + return incref_tree(instance, p2); +} + +/* + * Syntax: (unsetq name...) + * Syntax: (unsetf name...) + * `name' is not evalled + */ +static struct alisp_object * F_unsetq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1 = NULL, * n; + + do { + if (p1) + delete_tree(instance, p1); + p1 = unset_object(instance, car(p)); + delete_tree(instance, car(p)); + p = cdr(n = p); + delete_object(instance, n); + } while (p != &alsa_lisp_nil); + + return p1; +} + +/* + * Syntax: (defun name arglist expr...) + * `name' is not evalled + * `arglist' is not evalled + */ +static struct alisp_object * F_defun(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1 = car(args), + * p2 = car(cdr(args)), + * p3 = cdr(cdr(args)); + struct alisp_object * lexpr; + + lexpr = new_object(instance, ALISP_OBJ_CONS); + if (lexpr) { + lexpr->value.c.car = new_identifier(instance, "lambda"); + if (lexpr->value.c.car == NULL) { + delete_object(instance, lexpr); + delete_tree(instance, args); + return NULL; + } + if ((lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS)) == NULL) { + delete_object(instance, lexpr->value.c.car); + delete_object(instance, lexpr); + delete_tree(instance, args); + return NULL; + } + lexpr->value.c.cdr->value.c.car = p2; + lexpr->value.c.cdr->value.c.cdr = p3; + delete_object(instance, cdr(args)); + delete_object(instance, args); + if (set_object(instance, p1, lexpr) == NULL) { + delete_tree(instance, p1); + delete_tree(instance, lexpr); + return NULL; + } + delete_tree(instance, p1); + } else { + delete_tree(instance, args); + } + return &alsa_lisp_nil; +} + +static struct alisp_object * eval_func(struct alisp_instance *instance, struct alisp_object * p, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * p3, * p4; + struct alisp_object ** eval_objs, ** save_objs; + int i; + + p1 = car(p); + if (alisp_compare_type(p1, ALISP_OBJ_IDENTIFIER) && + !strcmp(p1->value.s, "lambda")) { + p2 = car(cdr(p)); + p3 = args; + + if ((i = count_list(p2)) != count_list(p3)) { + lisp_warn(instance, "wrong number of parameters"); + goto _delete; + } + + eval_objs = malloc(2 * i * sizeof(struct alisp_object *)); + if (eval_objs == NULL) { + nomem(); + goto _delete; + } + save_objs = eval_objs + i; + + /* + * Save the new variable values. + */ + i = 0; + while (p3 != &alsa_lisp_nil) { + eval_objs[i++] = eval(instance, car(p3)); + p3 = cdr(p4 = p3); + delete_object(instance, p4); + } + + /* + * Save the old variable values and set the new ones. + */ + i = 0; + while (p2 != &alsa_lisp_nil) { + p3 = car(p2); + save_objs[i] = replace_object(instance, p3, eval_objs[i]); + if (save_objs[i] == NULL && + set_object_direct(instance, p3, eval_objs[i]) == NULL) { + p4 = NULL; + goto _end; + } + p2 = cdr(p2); + ++i; + } + + p4 = F_progn(instance, cdr(incref_tree(instance, p3 = cdr(p)))); + + /* + * Restore the old variable values. + */ + p2 = car(p3); + delete_object(instance, p3); + i = 0; + while (p2 != &alsa_lisp_nil) { + p3 = car(p2); + if (save_objs[i] == NULL) { + p3 = unset_object(instance, p3); + } else { + p3 = replace_object(instance, p3, save_objs[i]); + } + i++; + delete_tree(instance, p3); + delete_tree(instance, car(p2)); + p2 = cdr(p3 = p2); + delete_object(instance, p3); + } + + _end: + free(eval_objs); + + return p4; + } else { + _delete: + delete_tree(instance, args); + } + return &alsa_lisp_nil; +} + +struct alisp_object * F_gc(struct alisp_instance *instance ATTRIBUTE_UNUSED, struct alisp_object * args ATTRIBUTE_UNUSED) +{ + /* improved: no more traditional gc */ + return &alsa_lisp_t; +} + +/* + * Syntax: (path what) + * what is string ('data') + */ +struct alisp_object * F_path(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (!alisp_compare_type(p1, ALISP_OBJ_STRING)) { + delete_tree(instance, p1); + return &alsa_lisp_nil; + } + if (!strcmp(p1->value.s, "data")) { + delete_tree(instance, p1); + return new_string(instance, ALSA_CONFIG_DIR); + } + delete_tree(instance, p1); + return &alsa_lisp_nil; +} + +/* + * Syntax: (include filename...) + */ +struct alisp_object * F_include(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1; + int res = -ENOENT; + + do { + p1 = eval(instance, car(p)); + if (alisp_compare_type(p1, ALISP_OBJ_STRING)) + res = alisp_include_file(instance, p1->value.s); + delete_tree(instance, p1); + p = cdr(p1 = p); + delete_object(instance, p1); + } while (p != &alsa_lisp_nil); + + return new_integer(instance, res); +} + +/* + * Syntax: (string-to-integer value) + * 'value' can be integer or float type + */ +struct alisp_object * F_string_to_integer(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = eval(instance, car(args)), * p1; + + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (alisp_compare_type(p, ALISP_OBJ_INTEGER)) + return p; + if (alisp_compare_type(p, ALISP_OBJ_FLOAT)) { + p1 = new_integer(instance, floor(p->value.f)); + } else { + lisp_warn(instance, "expected an integer or float for integer conversion"); + p1 = &alsa_lisp_nil; + } + delete_tree(instance, p); + return p1; +} + +/* + * Syntax: (string-to-float value) + * 'value' can be integer or float type + */ +struct alisp_object * F_string_to_float(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = eval(instance, car(args)), * p1; + + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (alisp_compare_type(p, ALISP_OBJ_FLOAT)) + return p; + if (alisp_compare_type(p, ALISP_OBJ_INTEGER)) { + p1 = new_float(instance, p->value.i); + } else { + lisp_warn(instance, "expected an integer or float for integer conversion"); + p1 = &alsa_lisp_nil; + } + delete_tree(instance, p); + return p1; +} + +static int append_to_string(char **s, int *len, char *from, int size) +{ + if (*len == 0) { + *s = malloc(*len = size + 1); + if (*s == NULL) { + nomem(); + return -ENOMEM; + } + memcpy(*s, from, size); + } else { + *len += size; + *s = realloc(*s, *len); + if (*s == NULL) { + nomem(); + return -ENOMEM; + } + memcpy(*s + strlen(*s), from, size); + } + (*s)[*len - 1] = '\0'; + return 0; +} + +static int format_parse_char(struct alisp_instance *instance, char **s, int *len, struct alisp_object *p) +{ + char b; + + if (!alisp_compare_type(p, ALISP_OBJ_INTEGER)) { + lisp_warn(instance, "format: expected integer\n"); + return 0; + } + b = p->value.i; + return append_to_string(s, len, &b, 1); +} + +static int format_parse_integer(struct alisp_instance *instance, char **s, int *len, struct alisp_object *p) +{ + int res; + char *s1; + + if (!alisp_compare_type(p, ALISP_OBJ_INTEGER) && + !alisp_compare_type(p, ALISP_OBJ_FLOAT)) { + lisp_warn(instance, "format: expected integer or float\n"); + return 0; + } + s1 = malloc(64); + if (s1 == NULL) { + nomem(); + return -ENOMEM; + } + sprintf(s1, "%li", alisp_compare_type(p, ALISP_OBJ_FLOAT) ? (long)floor(p->value.f) : p->value.i); + res = append_to_string(s, len, s1, strlen(s1)); + free(s1); + return res; +} + +static int format_parse_float(struct alisp_instance *instance, char **s, int *len, struct alisp_object *p) +{ + int res; + char *s1; + + if (!alisp_compare_type(p, ALISP_OBJ_INTEGER) && + !alisp_compare_type(p, ALISP_OBJ_FLOAT)) { + lisp_warn(instance, "format: expected integer or float\n"); + return 0; + } + s1 = malloc(64); + if (s1 == NULL) { + nomem(); + return -ENOMEM; + } + sprintf(s1, "%f", alisp_compare_type(p, ALISP_OBJ_FLOAT) ? p->value.f : (double)p->value.i); + res = append_to_string(s, len, s1, strlen(s1)); + free(s1); + return res; +} + +static int format_parse_string(struct alisp_instance *instance, char **s, int *len, struct alisp_object *p) +{ + if (!alisp_compare_type(p, ALISP_OBJ_STRING)) { + lisp_warn(instance, "format: expected string\n"); + return 0; + } + return append_to_string(s, len, p->value.s, strlen(p->value.s)); +} + +/* + * Syntax: (format format value...) + * 'format' is C-like format string + */ +struct alisp_object * F_format(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = eval(instance, car(args)), * p1 = cdr(args), * n; + char *s, *s1, *s2; + int len; + + delete_object(instance, args); + if (!alisp_compare_type(p, ALISP_OBJ_STRING)) { + delete_tree(instance, p1); + delete_tree(instance, p); + lisp_warn(instance, "format: expected an format string"); + return &alsa_lisp_nil; + } + s = p->value.s; + s1 = NULL; + len = 0; + n = eval(instance, car(p1)); + do { + while (1) { + s2 = s; + while (*s2 && *s2 != '%') + s2++; + if (s2 != s) { + if (append_to_string(&s1, &len, s, s2 - s) < 0) { + __error: + delete_tree(instance, n); + delete_tree(instance, cdr(p1)); + delete_object(instance, p1); + delete_tree(instance, p); + return NULL; + } + } + if (*s2 == '%') + s2++; + switch (*s2) { + case '%': + if (append_to_string(&s1, &len, s2, 1) < 0) + goto __error; + s = s2 + 1; + break; + case 'c': + if (format_parse_char(instance, &s1, &len, n) < 0) + goto __error; + s = s2 + 1; + goto __next; + case 'd': + case 'i': + if (format_parse_integer(instance, &s1, &len, n) < 0) + goto __error; + s = s2 + 1; + goto __next; + case 'f': + if (format_parse_float(instance, &s1, &len, n) < 0) + goto __error; + s = s2 + 1; + goto __next; + case 's': + if (format_parse_string(instance, &s1, &len, n) < 0) + goto __error; + s = s2 + 1; + goto __next; + case '\0': + goto __end; + default: + lisp_warn(instance, "unknown format char '%c'", *s2); + s = s2 + 1; + goto __next; + } + } + __next: + delete_tree(instance, n); + p1 = cdr(n = p1); + delete_object(instance, n); + n = eval(instance, car(p1)); + } while (*s); + __end: + delete_tree(instance, n); + delete_tree(instance, cdr(p1)); + delete_object(instance, p1); + delete_tree(instance, p); + if (len > 0) { + p1 = new_string(instance, s1); + free(s1); + } else { + p1 = &alsa_lisp_nil; + } + return p1; +} + +/* + * Syntax: (compare-strings str1 start1 end1 str2 start2 end2 /opt-case-insensitive) + * 'str1' is first compared string + * 'start1' is first char (0..) + * 'end1' is last char (0..) + * 'str2' is second compared string + * 'start2' is first char (0..) + * 'end2' is last char (0..) + * /opt-case-insensitive true - case insensitive match + */ +struct alisp_object * F_compare_strings(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1 = args, * n, * p[7]; + char *s1, *s2; + int start1, end1, start2, end2; + + for (start1 = 0; start1 < 7; start1++) { + p[start1] = eval(instance, car(p1)); + p1 = cdr(n = p1); + delete_object(instance, n); + } + delete_tree(instance, p1); + if (alisp_compare_type(p[0], ALISP_OBJ_STRING)) { + lisp_warn(instance, "compare-strings: first argument must be string\n"); + p1 = &alsa_lisp_nil; + goto __err; + } + if (alisp_compare_type(p[1], ALISP_OBJ_INTEGER)) { + lisp_warn(instance, "compare-strings: second argument must be integer\n"); + p1 = &alsa_lisp_nil; + goto __err; + } + if (alisp_compare_type(p[2], ALISP_OBJ_INTEGER)) { + lisp_warn(instance, "compare-strings: third argument must be integer\n"); + p1 = &alsa_lisp_nil; + goto __err; + } + if (alisp_compare_type(p[3], ALISP_OBJ_STRING)) { + lisp_warn(instance, "compare-strings: fifth argument must be string\n"); + p1 = &alsa_lisp_nil; + goto __err; + } + if (!alisp_compare_type(p[4], ALISP_OBJ_NIL) && + !alisp_compare_type(p[4], ALISP_OBJ_INTEGER)) { + lisp_warn(instance, "compare-strings: fourth argument must be integer\n"); + p1 = &alsa_lisp_nil; + goto __err; + } + if (!alisp_compare_type(p[5], ALISP_OBJ_NIL) && + !alisp_compare_type(p[5], ALISP_OBJ_INTEGER)) { + lisp_warn(instance, "compare-strings: sixth argument must be integer\n"); + p1 = &alsa_lisp_nil; + goto __err; + } + s1 = p[0]->value.s; + start1 = p[1]->value.i; + end1 = p[2]->value.i; + s2 = p[3]->value.s; + start2 = alisp_compare_type(p[4], ALISP_OBJ_NIL) ? 0 : p[4]->value.i; + end2 = alisp_compare_type(p[5], ALISP_OBJ_NIL) ? start2 + (end1 - start1) : p[5]->value.i; + if (start1 < 0 || start2 < 0 || end1 < 0 || end2 < 0 || + start1 >= (int)strlen(s1) || start2 >= (int)strlen(s2) || + (end1 - start1) != (end2 - start2)) { + p1 = &alsa_lisp_nil; + goto __err; + } + if (p[6] != &alsa_lisp_nil) { + while (start1 < end1) { + if (s1[start1] == '\0' || + s2[start2] == '\0' || + tolower(s1[start1]) != tolower(s2[start2])) { + p1 = &alsa_lisp_nil; + goto __err; + } + start1++; + start2++; + } + } else { + while (start1 < end1) { + if (s1[start1] == '\0' || + s2[start2] == '\0' || + s1[start1] != s2[start2]) { + p1 = &alsa_lisp_nil; + goto __err; + } + start1++; + start2++; + } + } + p1 = &alsa_lisp_t; + + __err: + for (start1 = 0; start1 < 7; start1++) + delete_tree(instance, p[start1]); + return p1; +} + +/* + * Syntax: (assoc key alist) + */ +struct alisp_object * F_assoc(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * n; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + do { + if (eq(p1, car(car(p2)))) { + n = car(p2); + delete_tree(instance, p1); + delete_tree(instance, cdr(p2)); + delete_object(instance, p2); + return n; + } + delete_tree(instance, car(p2)); + p2 = cdr(n = p2); + delete_object(instance, n); + } while (p2 != &alsa_lisp_nil); + + delete_tree(instance, p1); + return &alsa_lisp_nil; +} + +/* + * Syntax: (rassoc value alist) + */ +struct alisp_object * F_rassoc(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, *p2, * n; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + do { + if (eq(p1, cdr(car(p2)))) { + n = car(p2); + delete_tree(instance, p1); + delete_tree(instance, cdr(p2)); + delete_object(instance, p2); + return n; + } + delete_tree(instance, car(p2)); + p2 = cdr(n = p2); + delete_object(instance, n); + } while (p2 != &alsa_lisp_nil); + + delete_tree(instance, p1); + return &alsa_lisp_nil; +} + +/* + * Syntax: (assq key alist) + */ +struct alisp_object * F_assq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * n; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + do { + if (equal(p1, car(car(p2)))) { + n = car(p2); + delete_tree(instance, p1); + delete_tree(instance, cdr(p2)); + delete_object(instance, p2); + return n; + } + delete_tree(instance, car(p2)); + p2 = cdr(n = p2); + delete_object(instance, n); + } while (p2 != &alsa_lisp_nil); + + delete_tree(instance, p1); + return &alsa_lisp_nil; +} + +/* + * Syntax: (nth index alist) + */ +struct alisp_object * F_nth(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * n; + long idx; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + if (!alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + delete_tree(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; + } + if (!alisp_compare_type(p2, ALISP_OBJ_CONS)) { + delete_object(instance, p1); + delete_tree(instance, p2); + return &alsa_lisp_nil; + } + idx = p1->value.i; + delete_object(instance, p1); + while (idx-- > 0) { + delete_tree(instance, car(p2)); + p2 = cdr(n = p2); + delete_object(instance, n); + } + n = car(p2); + delete_tree(instance, cdr(p2)); + delete_object(instance, p2); + return n; +} + +/* + * Syntax: (rassq value alist) + */ +struct alisp_object * F_rassq(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, * p2, * n; + + p1 = eval(instance, car(args)); + p2 = eval(instance, car(cdr(args))); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + + do { + if (equal(p1, cdr(car(p2)))) { + n = car(p2); + delete_tree(instance, p1); + delete_tree(instance, cdr(p2)); + delete_object(instance, p2); + return n; + } + delete_tree(instance, car(p2)); + p2 = cdr(n = p2); + delete_object(instance, n); + } while (p2 != &alsa_lisp_nil); + + delete_tree(instance, p1); + return &alsa_lisp_nil; +} + +static struct alisp_object * F_dump_memory(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = car(args); + + if (p != &alsa_lisp_nil && cdr(args) == &alsa_lisp_nil && + alisp_compare_type(p, ALISP_OBJ_STRING)) { + if (strlen(p->value.s) > 0) { + dump_objects(instance, p->value.s); + delete_tree(instance, args); + return &alsa_lisp_t; + } else + lisp_warn(instance, "expected filename"); + } else + lisp_warn(instance, "wrong number of parameters (expected string)"); + + delete_tree(instance, args); + return &alsa_lisp_nil; +} + +static struct alisp_object * F_stat_memory(struct alisp_instance *instance, struct alisp_object * args) +{ + snd_output_printf(instance->out, "*** Memory stats\n"); + snd_output_printf(instance->out, " used_objs = %li, free_objs = %li, max_objs = %li, obj_size = %i (total bytes = %li, max bytes = %li)\n", + instance->used_objs, + instance->free_objs, + instance->max_objs, + (int)sizeof(struct alisp_object), + (long)((instance->used_objs + instance->free_objs) * sizeof(struct alisp_object)), + (long)(instance->max_objs * sizeof(struct alisp_object))); + delete_tree(instance, args); + return &alsa_lisp_nil; +} + +static struct alisp_object * F_check_memory(struct alisp_instance *instance, struct alisp_object * args) +{ + delete_tree(instance, args); + if (instance->used_objs > 0) { + fprintf(stderr, "!!!alsa lisp - check memory failed!!!\n"); + F_stat_memory(instance, &alsa_lisp_nil); + exit(EXIT_FAILURE); + } + return &alsa_lisp_t; +} + +static struct alisp_object * F_dump_objects(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = car(args); + + if (p != &alsa_lisp_nil && cdr(args) == &alsa_lisp_nil && + alisp_compare_type(p, ALISP_OBJ_STRING)) { + if (strlen(p->value.s) > 0) { + dump_obj_lists(instance, p->value.s); + delete_tree(instance, args); + return &alsa_lisp_t; + } else + lisp_warn(instance, "expected filename"); + } else + lisp_warn(instance, "wrong number of parameters (expected string)"); + + delete_tree(instance, args); + return &alsa_lisp_nil; +} + +struct intrinsic { + const char *name; + struct alisp_object * (*func)(struct alisp_instance *instance, struct alisp_object * args); +}; + +static const struct intrinsic intrinsics[] = { + { "!=", F_numneq }, + { "%", F_mod }, + { "&check-memory", F_check_memory }, + { "&dump-memory", F_dump_memory }, + { "&dump-objects", F_dump_objects }, + { "&stat-memory", F_stat_memory }, + { "*", F_mul }, + { "+", F_add }, + { "-", F_sub }, + { "/", F_div }, + { "<", F_lt }, + { "<=", F_le }, + { "=", F_numeq }, + { ">", F_gt }, + { ">=", F_ge }, + { "and", F_and }, + { "assoc", F_assoc }, + { "assq", F_assq }, + { "atom", F_atom }, + { "car", F_car }, + { "cdr", F_cdr }, + { "compare-strings", F_compare_strings }, + { "concat", F_concat }, + { "cond", F_cond }, + { "cons", F_cons }, + { "defun", F_defun }, + { "eq", F_eq }, + { "equal", F_equal }, + { "eval", F_eval }, + { "exfun", F_exfun }, + { "format", F_format }, + { "funcall", F_funcall }, + { "garbage-collect", F_gc }, + { "gc", F_gc }, + { "if", F_if }, + { "include", F_include }, + { "list", F_list }, + { "not", F_not }, + { "nth", F_nth }, + { "null", F_not }, + { "or", F_or }, + { "path", F_path }, + { "princ", F_princ }, + { "prog1", F_prog1 }, + { "prog2", F_prog2 }, + { "progn", F_progn }, + { "quote", F_quote }, + { "rassoc", F_rassoc }, + { "rassq", F_rassq }, + { "set", F_set }, + { "setf", F_setq }, + { "setq", F_setq }, + { "string-equal", F_equal }, + { "string-to-float", F_string_to_float }, + { "string-to-integer", F_string_to_integer }, + { "string-to-number", F_string_to_float }, + { "string=", F_equal }, + { "unless", F_unless }, + { "unset", F_unset }, + { "unsetf", F_unsetq }, + { "unsetq", F_unsetq }, + { "when", F_when }, + { "while", F_while }, +}; + +#include "alisp_snd.c" + +static int compar(const void *p1, const void *p2) +{ + return strcmp(((struct intrinsic *)p1)->name, + ((struct intrinsic *)p2)->name); +} + +static inline struct alisp_object * eval_cons1(struct alisp_instance *instance, struct alisp_object * p1, struct alisp_object * p2) +{ + struct alisp_object * p3; + struct intrinsic key, *item; + + key.name = p1->value.s; + + if ((item = bsearch(&key, intrinsics, + sizeof intrinsics / sizeof intrinsics[0], + sizeof intrinsics[0], compar)) != NULL) { + delete_object(instance, p1); + return item->func(instance, p2); + } + + if ((item = bsearch(&key, snd_intrinsics, + sizeof snd_intrinsics / sizeof snd_intrinsics[0], + sizeof snd_intrinsics[0], compar)) != NULL) { + delete_object(instance, p1); + return item->func(instance, p2); + } + + if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil) { + delete_object(instance, p1); + return eval_func(instance, p3, p2); + } else { + lisp_warn(instance, "function `%s' is undefined", p1->value.s); + delete_object(instance, p1); + delete_tree(instance, p2); + } + + return &alsa_lisp_nil; +} + +/* + * Syntax: (funcall function args...) + */ +static struct alisp_object * F_funcall(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = eval(instance, car(args)), * p1; + + if (!alisp_compare_type(p, ALISP_OBJ_IDENTIFIER) && + !alisp_compare_type(p, ALISP_OBJ_STRING)) { + lisp_warn(instance, "expected an function name"); + delete_tree(instance, p); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + return &alsa_lisp_nil; + } + p1 = cdr(args); + delete_object(instance, args); + return eval_cons1(instance, p, p1); +} + +static inline struct alisp_object * eval_cons(struct alisp_instance *instance, struct alisp_object * p) +{ + struct alisp_object * p1 = car(p), * p2; + + if (p1 != &alsa_lisp_nil && alisp_compare_type(p1, ALISP_OBJ_IDENTIFIER)) { + if (!strcmp(p1->value.s, "lambda")) + return p; + + p2 = cdr(p); + delete_object(instance, p); + return eval_cons1(instance, p1, p2); + } else { + delete_tree(instance, p); + } + + return &alsa_lisp_nil; +} + +static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_object * p) +{ + switch (alisp_get_type(p)) { + case ALISP_OBJ_IDENTIFIER: { + struct alisp_object *r = incref_tree(instance, get_object(instance, p)); + delete_object(instance, p); + return r; + } + case ALISP_OBJ_INTEGER: + case ALISP_OBJ_FLOAT: + case ALISP_OBJ_STRING: + case ALISP_OBJ_POINTER: + return p; + case ALISP_OBJ_CONS: + return eval_cons(instance, p); + default: + break; + } + + return p; +} + +static struct alisp_object * F_eval(struct alisp_instance *instance, struct alisp_object * args) +{ + return eval(instance, eval(instance, car(args))); +} + +/* + * main routine + */ + +static int alisp_include_file(struct alisp_instance *instance, const char *filename) +{ + snd_input_t *old_in; + struct alisp_object *p, *p1; + char *name; + int retval = 0, err; + + err = snd_user_file(filename, &name); + if (err < 0) + return err; + old_in = instance->in; + err = snd_input_stdio_open(&instance->in, name, "r"); + if (err < 0) { + retval = err; + goto _err; + } + if (instance->verbose) + lisp_verbose(instance, "** include filename '%s'", name); + + for (;;) { + if ((p = parse_object(instance, 0)) == NULL) + break; + if (instance->verbose) { + lisp_verbose(instance, "** code"); + princ_object(instance->vout, p); + snd_output_putc(instance->vout, '\n'); + } + p1 = eval(instance, p); + if (p1 == NULL) { + retval = -ENOMEM; + break; + } + if (instance->verbose) { + lisp_verbose(instance, "** result"); + princ_object(instance->vout, p1); + snd_output_putc(instance->vout, '\n'); + } + delete_tree(instance, p1); + if (instance->debug) { + lisp_debug(instance, "** objects after operation"); + print_obj_lists(instance, instance->dout); + } + } + + snd_input_close(instance->in); + _err: + free(name); + instance->in = old_in; + return retval; +} + +int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance) +{ + struct alisp_instance *instance; + struct alisp_object *p, *p1; + int i, j, retval = 0; + + instance = (struct alisp_instance *)malloc(sizeof(struct alisp_instance)); + if (instance == NULL) { + nomem(); + return -ENOMEM; + } + memset(instance, 0, sizeof(struct alisp_instance)); + instance->verbose = cfg->verbose && cfg->vout; + instance->warning = cfg->warning && cfg->wout; + instance->debug = cfg->debug && cfg->dout; + instance->in = cfg->in; + instance->out = cfg->out; + instance->vout = cfg->vout; + instance->eout = cfg->eout; + instance->wout = cfg->wout; + instance->dout = cfg->dout; + INIT_LIST_HEAD(&instance->free_objs_list); + for (i = 0; i < ALISP_OBJ_PAIR_HASH_SIZE; i++) { + for (j = 0; j <= ALISP_OBJ_LAST_SEARCH; j++) + INIT_LIST_HEAD(&instance->used_objs_list[i][j]); + INIT_LIST_HEAD(&instance->setobjs_list[i]); + } + + init_lex(instance); + + for (;;) { + if ((p = parse_object(instance, 0)) == NULL) + break; + if (instance->verbose) { + lisp_verbose(instance, "** code"); + princ_object(instance->vout, p); + snd_output_putc(instance->vout, '\n'); + } + p1 = eval(instance, p); + if (p1 == NULL) { + retval = -ENOMEM; + break; + } + if (instance->verbose) { + lisp_verbose(instance, "** result"); + princ_object(instance->vout, p1); + snd_output_putc(instance->vout, '\n'); + } + delete_tree(instance, p1); + if (instance->debug) { + lisp_debug(instance, "** objects after operation"); + print_obj_lists(instance, instance->dout); + } + } + + if (_instance) + *_instance = instance; + else + alsa_lisp_free(instance); + + return 0; +} + +void alsa_lisp_free(struct alisp_instance *instance) +{ + if (instance == NULL) + return; + done_lex(instance); + free_objects(instance); + free(instance); +} + +struct alisp_cfg *alsa_lisp_default_cfg(snd_input_t *input) +{ + snd_output_t *output, *eoutput; + struct alisp_cfg *cfg; + int err; + + err = snd_output_stdio_attach(&output, stdout, 0); + if (err < 0) + return NULL; + err = snd_output_stdio_attach(&eoutput, stderr, 0); + if (err < 0) { + snd_output_close(output); + return NULL; + } + cfg = calloc(1, sizeof(struct alisp_cfg)); + if (cfg == NULL) { + snd_output_close(eoutput); + snd_output_close(output); + return NULL; + } + cfg->out = output; + cfg->wout = eoutput; + cfg->eout = eoutput; + cfg->dout = eoutput; + cfg->in = input; + return cfg; +} + +void alsa_lisp_default_cfg_free(struct alisp_cfg *cfg) +{ + snd_input_close(cfg->in); + snd_output_close(cfg->out); + snd_output_close(cfg->dout); + free(cfg); +} + +int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterator **result, + const char *id, const char *args, ...) +{ + int err = 0; + struct alisp_object *aargs = NULL, *obj, *res; + + if (args && *args != 'n') { + va_list ap; + struct alisp_object *p; + p = NULL; + va_start(ap, args); + while (*args) { + if (*args++ != '%') { + err = -EINVAL; + break; + } + if (*args == '\0') { + err = -EINVAL; + break; + } + obj = NULL; + err = 0; + switch (*args++) { + case 's': + obj = new_string(instance, va_arg(ap, char *)); + break; + case 'i': + obj = new_integer(instance, va_arg(ap, int)); + break; + case 'l': + obj = new_integer(instance, va_arg(ap, long)); + break; + case 'f': + case 'd': + obj = new_integer(instance, va_arg(ap, double)); + break; + case 'p': { + char _ptrid[24]; + char *ptrid = _ptrid; + while (*args && *args != '%') + *ptrid++ = *args++; + *ptrid = 0; + if (ptrid == _ptrid) { + err = -EINVAL; + break; + } + obj = new_cons_pointer(instance, _ptrid, va_arg(ap, void *)); + obj = quote_object(instance, obj); + break; + } + default: + err = -EINVAL; + break; + } + if (err < 0) + goto __args_end; + if (obj == NULL) { + err = -ENOMEM; + goto __args_end; + } + if (p == NULL) { + p = aargs = new_object(instance, ALISP_OBJ_CONS); + } else { + p->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); + p = p->value.c.cdr; + } + if (p == NULL) { + err = -ENOMEM; + goto __args_end; + } + p->value.c.car = obj; + } + __args_end: + va_end(ap); + if (err < 0) + return err; +#if 0 + snd_output_printf(instance->wout, ">>>"); + princ_object(instance->wout, aargs); + snd_output_printf(instance->wout, "<<<\n"); +#endif + } + + err = -ENOENT; + if (aargs == NULL) + aargs = &alsa_lisp_nil; + if ((obj = get_object1(instance, id)) != &alsa_lisp_nil) { + res = eval_func(instance, obj, aargs); + err = 0; + } else { + struct intrinsic key, *item; + key.name = id; + if ((item = bsearch(&key, intrinsics, + sizeof intrinsics / sizeof intrinsics[0], + sizeof intrinsics[0], compar)) != NULL) { + res = item->func(instance, aargs); + err = 0; + } else if ((item = bsearch(&key, snd_intrinsics, + sizeof snd_intrinsics / sizeof snd_intrinsics[0], + sizeof snd_intrinsics[0], compar)) != NULL) { + res = item->func(instance, aargs); + err = 0; + } else { + res = &alsa_lisp_nil; + } + } + if (res == NULL) + err = -ENOMEM; + if (err == 0 && result) { + *result = res; + } else { + delete_tree(instance, res); + } + + return 0; +} + +void alsa_lisp_result_free(struct alisp_instance *instance, + struct alisp_seq_iterator *result) +{ + delete_tree(instance, result); +} + +int alsa_lisp_seq_first(struct alisp_instance *instance, const char *id, + struct alisp_seq_iterator **seq) +{ + struct alisp_object * p1; + + p1 = get_object1(instance, id); + if (p1 == NULL) + return -ENOMEM; + *seq = p1; + return 0; +} + +int alsa_lisp_seq_next(struct alisp_seq_iterator **seq) +{ + struct alisp_object * p1 = *seq; + + p1 = cdr(p1); + if (p1 == &alsa_lisp_nil) + return -ENOENT; + *seq = p1; + return 0; +} + +int alsa_lisp_seq_count(struct alisp_seq_iterator *seq) +{ + int count = 0; + + while (seq != &alsa_lisp_nil) { + count++; + seq = cdr(seq); + } + return count; +} + +int alsa_lisp_seq_integer(struct alisp_seq_iterator *seq, long *val) +{ + if (alisp_compare_type(seq, ALISP_OBJ_CONS)) + seq = seq->value.c.cdr; + if (alisp_compare_type(seq, ALISP_OBJ_INTEGER)) + *val = seq->value.i; + else + return -EINVAL; + return 0; +} + +int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, void **ptr) +{ + struct alisp_object * p2; + + if (alisp_compare_type(seq, ALISP_OBJ_CONS) && + alisp_compare_type(seq->value.c.car, ALISP_OBJ_CONS)) + seq = seq->value.c.car; + if (alisp_compare_type(seq, ALISP_OBJ_CONS)) { + p2 = seq->value.c.car; + if (!alisp_compare_type(p2, ALISP_OBJ_STRING)) + return -EINVAL; + if (strcmp(p2->value.s, ptr_id)) + return -EINVAL; + p2 = seq->value.c.cdr; + if (!alisp_compare_type(p2, ALISP_OBJ_POINTER)) + return -EINVAL; + *ptr = (void *)seq->value.ptr; + } else + return -EINVAL; + return 0; +} diff --git a/src/alisp/alisp_local.h b/src/alisp/alisp_local.h new file mode 100644 index 0000000..4558ebb --- /dev/null +++ b/src/alisp/alisp_local.h @@ -0,0 +1,151 @@ +/* + * ALSA lisp implementation + * Copyright (c) 2003 by Jaroslav Kysela + * + * Based on work of Sandro Sigala (slisp-1.2) + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "list.h" + +enum alisp_tokens { + ALISP_IDENTIFIER, + ALISP_INTEGER, + ALISP_FLOAT, + ALISP_FLOATE, + ALISP_STRING +}; + +enum alisp_objects { + ALISP_OBJ_INTEGER, + ALISP_OBJ_FLOAT, + ALISP_OBJ_IDENTIFIER, + ALISP_OBJ_STRING, + ALISP_OBJ_POINTER, + ALISP_OBJ_CONS, + ALISP_OBJ_LAST_SEARCH = ALISP_OBJ_CONS, + ALISP_OBJ_NIL, + ALISP_OBJ_T, +}; + +struct alisp_object; + +#define ALISP_TYPE_MASK 0xf0000000 +#define ALISP_TYPE_SHIFT 28 +#define ALISP_REFS_MASK 0x0fffffff +#define ALISP_REFS_SHIFT 0 +#define ALISP_MAX_REFS (ALISP_REFS_MASK>>ALISP_REFS_SHIFT) +#define ALISP_MAX_REFS_LIMIT ((ALISP_MAX_REFS + 1) / 2) + +struct alisp_object { + struct list_head list; + unsigned int type_refs; /* type and count of references */ + union { + char *s; + long i; + double f; + const void *ptr; + struct { + struct alisp_object *car; + struct alisp_object *cdr; + } c; + } value; +}; + +static inline enum alisp_objects alisp_get_type(struct alisp_object *p) +{ + return (p->type_refs >> ALISP_TYPE_SHIFT); +} + +static inline void alisp_set_type(struct alisp_object *p, enum alisp_objects type) +{ + p->type_refs &= ~ALISP_TYPE_MASK; + p->type_refs |= (unsigned int)type << ALISP_TYPE_SHIFT; +} + +static inline int alisp_compare_type(struct alisp_object *p, enum alisp_objects type) +{ + return ((unsigned int)type << ALISP_TYPE_SHIFT) == + (p->type_refs & ALISP_TYPE_MASK); +} + +static inline void alisp_set_refs(struct alisp_object *p, unsigned int refs) +{ + p->type_refs &= ~ALISP_REFS_MASK; + p->type_refs |= refs & ALISP_REFS_MASK; +} + +static inline unsigned int alisp_get_refs(struct alisp_object *p) +{ + return p->type_refs & ALISP_REFS_MASK; +} + +static inline unsigned int alisp_inc_refs(struct alisp_object *p) +{ + unsigned r = alisp_get_refs(p) + 1; + alisp_set_refs(p, r); + return r; +} + +static inline unsigned int alisp_dec_refs(struct alisp_object *p) +{ + unsigned r = alisp_get_refs(p) - 1; + alisp_set_refs(p, r); + return r; +} + +struct alisp_object_pair { + struct list_head list; + const char *name; + struct alisp_object *value; +}; + +#define ALISP_LEX_BUF_MAX 16 +#define ALISP_OBJ_PAIR_HASH_SHIFT 4 +#define ALISP_OBJ_PAIR_HASH_SIZE (1< + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +struct acall_table { + const char *name; + struct alisp_object * (*func) (struct alisp_instance *instance, struct acall_table * item, struct alisp_object * args); + void * xfunc; + const char *prefix; +}; + +/* + * helper functions + */ + +static inline int get_integer(struct alisp_object * obj) +{ + if (alisp_compare_type(obj, ALISP_OBJ_INTEGER)) + return obj->value.i; + return 0; +} + +static inline const void *get_pointer(struct alisp_object * obj) +{ + if (alisp_compare_type(obj, ALISP_OBJ_POINTER)) + return obj->value.ptr; + return NULL; +} + +static const char *get_string(struct alisp_object * obj, const char * deflt) +{ + if (obj == &alsa_lisp_t) + return "true"; + if (alisp_compare_type(obj, ALISP_OBJ_STRING) || + alisp_compare_type(obj, ALISP_OBJ_IDENTIFIER)) + return obj->value.s; + return deflt; +} + +struct flags { + const char *key; + unsigned int mask; +}; + +static unsigned int get_flags(struct alisp_instance * instance, + struct alisp_object * obj, + const struct flags * flags, + unsigned int deflt) +{ + const char *key; + int invert; + unsigned int result; + const struct flags *ptr; + struct alisp_object *n; + + if (obj == &alsa_lisp_nil) + return deflt; + result = deflt; + do { + key = get_string(obj, NULL); + if (key) { + invert = key[0] == '!'; + key += invert; + ptr = flags; + while (ptr->key) { + if (!strcmp(ptr->key, key)) { + if (invert) + result &= ~ptr->mask; + else + result |= ptr->mask; + break; + } + ptr++; + } + } + delete_tree(instance, car(obj)); + obj = cdr(n = obj); + delete_object(instance, n); + } while (obj != &alsa_lisp_nil); + return result; +} + +static const void *get_ptr(struct alisp_instance * instance, + struct alisp_object * obj, + const char *_ptr_id) +{ + const char *ptr_id; + const void *ptr; + + ptr_id = get_string(car(obj), NULL); + if (ptr_id == NULL) { + delete_tree(instance, obj); + return NULL; + } + if (strcmp(ptr_id, _ptr_id)) { + delete_tree(instance, obj); + return NULL; + } + ptr = get_pointer(cdr(obj)); + delete_tree(instance, obj); + return ptr; +} + +static struct alisp_object * new_lexpr(struct alisp_instance * instance, int err) +{ + struct alisp_object * lexpr; + + lexpr = new_object(instance, ALISP_OBJ_CONS); + if (lexpr == NULL) + return NULL; + lexpr->value.c.car = new_integer(instance, err); + if (lexpr->value.c.car == NULL) { + delete_object(instance, lexpr); + return NULL; + } + lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); + if (lexpr->value.c.cdr == NULL) { + delete_object(instance, lexpr->value.c.car); + delete_object(instance, lexpr); + return NULL; + } + return lexpr; +} + +static struct alisp_object * add_cons(struct alisp_instance * instance, + struct alisp_object *lexpr, + int cdr, const char *id, + struct alisp_object *obj) +{ + struct alisp_object * p1, * p2; + + if (lexpr == NULL || obj == NULL) { + delete_tree(instance, obj); + return NULL; + } + if (cdr) { + p1 = lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); + } else { + p1 = lexpr->value.c.car = new_object(instance, ALISP_OBJ_CONS); + } + lexpr = p1; + if (p1 == NULL) { + delete_tree(instance, obj); + return NULL; + } + p1->value.c.car = new_object(instance, ALISP_OBJ_CONS); + if ((p2 = p1->value.c.car) == NULL) + goto __err; + p2->value.c.car = new_string(instance, id); + if (p2->value.c.car == NULL) { + __err: + if (cdr) + lexpr->value.c.cdr = NULL; + else + lexpr->value.c.car = NULL; + delete_tree(instance, p1); + delete_tree(instance, obj); + return NULL; + } + p2->value.c.cdr = obj; + return lexpr; +} + +static struct alisp_object * add_cons2(struct alisp_instance * instance, + struct alisp_object *lexpr, + int cdr, struct alisp_object *obj) +{ + struct alisp_object * p1; + + if (lexpr == NULL || obj == NULL) { + delete_tree(instance, obj); + return NULL; + } + if (cdr) { + p1 = lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS); + } else { + p1 = lexpr->value.c.car = new_object(instance, ALISP_OBJ_CONS); + } + lexpr = p1; + if (p1 == NULL) { + delete_tree(instance, obj); + return NULL; + } + p1->value.c.car = obj; + return lexpr; +} + +static struct alisp_object * new_result1(struct alisp_instance * instance, + int err, const char *ptr_id, void *ptr) +{ + struct alisp_object * lexpr, * p1; + + if (err < 0) + ptr = NULL; + lexpr = new_object(instance, ALISP_OBJ_CONS); + if (lexpr == NULL) + return NULL; + lexpr->value.c.car = new_integer(instance, err); + if (lexpr->value.c.car == NULL) { + delete_object(instance, lexpr); + return NULL; + } + p1 = add_cons(instance, lexpr, 1, ptr_id, new_pointer(instance, ptr)); + if (p1 == NULL) { + delete_object(instance, lexpr); + return NULL; + } + return lexpr; +} + +static struct alisp_object * new_result2(struct alisp_instance * instance, + int err, int val) +{ + struct alisp_object * lexpr, * p1; + + if (err < 0) + val = 0; + lexpr = new_lexpr(instance, err); + if (lexpr == NULL) + return NULL; + p1 = lexpr->value.c.cdr; + p1->value.c.car = new_integer(instance, val); + if (p1->value.c.car == NULL) { + delete_object(instance, lexpr); + return NULL; + } + return lexpr; +} + +static struct alisp_object * new_result3(struct alisp_instance * instance, + int err, const char *str) +{ + struct alisp_object * lexpr, * p1; + + if (err < 0) + str = ""; + lexpr = new_lexpr(instance, err); + if (lexpr == NULL) + return NULL; + p1 = lexpr->value.c.cdr; + p1->value.c.car = new_string(instance, str); + if (p1->value.c.car == NULL) { + delete_object(instance, lexpr); + return NULL; + } + return lexpr; +} + +/* + * macros + */ + +/* + * HCTL functions + */ + +typedef int (*snd_int_pp_strp_int_t)(void **rctl, const char *name, int mode); +typedef int (*snd_int_pp_p_t)(void **rctl, void *handle); +typedef int (*snd_int_p_t)(void *rctl); +typedef char * (*snd_str_p_t)(void *rctl); +typedef int (*snd_int_intp_t)(int *val); +typedef int (*snd_int_str_t)(const char *str); +typedef int (*snd_int_int_strp_t)(int val, char **str); +typedef void *(*snd_p_p_t)(void *handle); + +static struct alisp_object * FA_int_pp_strp_int(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + const char *name; + int err, mode; + void *handle; + struct alisp_object *p1, *p2; + static const struct flags flags[] = { + { "nonblock", SND_CTL_NONBLOCK }, + { "async", SND_CTL_ASYNC }, + { "readonly", SND_CTL_READONLY }, + { NULL, 0 } + }; + + name = get_string(p1 = eval(instance, car(args)), NULL); + if (name == NULL) + return &alsa_lisp_nil; + mode = get_flags(instance, p2 = eval(instance, car(cdr(args))), flags, 0); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + delete_tree(instance, p2); + err = ((snd_int_pp_strp_int_t)item->xfunc)(&handle, name, mode); + delete_tree(instance, p1); + return new_result1(instance, err, item->prefix, handle); +} + +static struct alisp_object * FA_int_pp_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + int err; + void *handle; + const char *prefix1; + struct alisp_object *p1; + + if (item->xfunc == &snd_hctl_open_ctl) + prefix1 = "ctl"; + else { + delete_tree(instance, args); + return &alsa_lisp_nil; + } + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (void *)get_ptr(instance, p1, prefix1); + if (handle == NULL) + return &alsa_lisp_nil; + err = ((snd_int_pp_p_t)item->xfunc)(&handle, handle); + return new_result1(instance, err, item->prefix, handle); +} + +static struct alisp_object * FA_p_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + void *handle; + const char *prefix1; + struct alisp_object * p1; + + if (item->xfunc == &snd_hctl_first_elem || + item->xfunc == &snd_hctl_last_elem || + item->xfunc == &snd_hctl_elem_next || + item->xfunc == &snd_hctl_elem_prev) + prefix1 = "hctl_elem"; + else if (item->xfunc == &snd_hctl_ctl) + prefix1 = "ctl"; + else { + delete_tree(instance, args); + return &alsa_lisp_nil; + } + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (void *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + handle = ((snd_p_p_t)item->xfunc)(handle); + return new_cons_pointer(instance, prefix1, handle); +} + +static struct alisp_object * FA_int_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + void *handle; + struct alisp_object * p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (void *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + return new_integer(instance, ((snd_int_p_t)item->xfunc)(handle)); +} + +static struct alisp_object * FA_str_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + void *handle; + struct alisp_object * p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (void *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + return new_string(instance, ((snd_str_p_t)item->xfunc)(handle)); +} + +static struct alisp_object * FA_int_intp(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + int val, err; + struct alisp_object * p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (!alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + delete_tree(instance, p1); + return &alsa_lisp_nil; + } + val = p1->value.i; + delete_tree(instance, p1); + err = ((snd_int_intp_t)item->xfunc)(&val); + return new_result2(instance, err, val); +} + +static struct alisp_object * FA_int_str(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + int err; + struct alisp_object * p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (!alisp_compare_type(p1, ALISP_OBJ_STRING) && + !alisp_compare_type(p1, ALISP_OBJ_IDENTIFIER)) { + delete_tree(instance, p1); + return &alsa_lisp_nil; + } + err = ((snd_int_str_t)item->xfunc)(p1->value.s); + delete_tree(instance, p1); + return new_integer(instance, err); +} + +static struct alisp_object * FA_int_int_strp(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + int err; + char *str; + long val; + struct alisp_object * p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + if (!alisp_compare_type(p1, ALISP_OBJ_INTEGER)) { + delete_tree(instance, p1); + return &alsa_lisp_nil; + } + val = p1->value.i; + delete_tree(instance, p1); + err = ((snd_int_int_strp_t)item->xfunc)(val, &str); + return new_result3(instance, err, str); +} + +static struct alisp_object * FA_card_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_ctl_t *handle; + struct alisp_object * lexpr, * p1; + snd_ctl_card_info_t * info; + int err; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (snd_ctl_t *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + snd_ctl_card_info_alloca(&info); + err = snd_ctl_card_info(handle, info); + lexpr = new_lexpr(instance, err); + if (err < 0) + return lexpr; + p1 = add_cons(instance, lexpr->value.c.cdr, 0, "id", new_string(instance, snd_ctl_card_info_get_id(info))); + p1 = add_cons(instance, p1, 1, "driver", new_string(instance, snd_ctl_card_info_get_driver(info))); + p1 = add_cons(instance, p1, 1, "name", new_string(instance, snd_ctl_card_info_get_name(info))); + p1 = add_cons(instance, p1, 1, "longname", new_string(instance, snd_ctl_card_info_get_longname(info))); + p1 = add_cons(instance, p1, 1, "mixername", new_string(instance, snd_ctl_card_info_get_mixername(info))); + p1 = add_cons(instance, p1, 1, "components", new_string(instance, snd_ctl_card_info_get_components(info))); + if (p1 == NULL) { + delete_tree(instance, lexpr); + return NULL; + } + return lexpr; +} + +static struct alisp_object * create_ctl_elem_id(struct alisp_instance * instance, snd_ctl_elem_id_t * id, struct alisp_object * cons) +{ + cons = add_cons(instance, cons, 0, "numid", new_integer(instance, snd_ctl_elem_id_get_numid(id))); + cons = add_cons(instance, cons, 1, "iface", new_string(instance, snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id)))); + cons = add_cons(instance, cons, 1, "dev", new_integer(instance, snd_ctl_elem_id_get_device(id))); + cons = add_cons(instance, cons, 1, "subdev", new_integer(instance, snd_ctl_elem_id_get_subdevice(id))); + cons = add_cons(instance, cons, 1, "name", new_string(instance, snd_ctl_elem_id_get_name(id))); + cons = add_cons(instance, cons, 1, "index", new_integer(instance, snd_ctl_elem_id_get_index(id))); + return cons; +} + +static int parse_ctl_elem_id(struct alisp_instance * instance, + struct alisp_object * cons, + snd_ctl_elem_id_t * id) +{ + struct alisp_object *p1; + const char *xid; + + if (cons == NULL) + return -ENOMEM; + snd_ctl_elem_id_clear(id); + id->numid = 0; + do { + p1 = car(cons); + if (alisp_compare_type(p1, ALISP_OBJ_CONS)) { + xid = get_string(p1->value.c.car, NULL); + if (xid == NULL) { + /* noop */ + } else if (!strcmp(xid, "numid")) { + snd_ctl_elem_id_set_numid(id, get_integer(p1->value.c.cdr)); + } else if (!strcmp(xid, "iface")) { + snd_ctl_elem_id_set_interface(id, snd_config_get_ctl_iface_ascii(get_string(p1->value.c.cdr, "0"))); + } else if (!strcmp(xid, "dev")) { + snd_ctl_elem_id_set_device(id, get_integer(p1->value.c.cdr)); + } else if (!strcmp(xid, "subdev")) { + snd_ctl_elem_id_set_subdevice(id, get_integer(p1->value.c.cdr)); + } else if (!strcmp(xid, "name")) { + snd_ctl_elem_id_set_name(id, get_string(p1->value.c.cdr, "?")); + } else if (!strcmp(xid, "index")) { + snd_ctl_elem_id_set_index(id, get_integer(p1->value.c.cdr)); + } + } + delete_tree(instance, p1); + cons = cdr(p1 = cons); + delete_object(instance, p1); + } while (cons != &alsa_lisp_nil); + return 0; +} + +static struct alisp_object * FA_hctl_find_elem(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_hctl_t *handle; + snd_ctl_elem_id_t *id; + struct alisp_object *p1; + + handle = (snd_hctl_t *)get_ptr(instance, car(args), item->prefix); + if (handle == NULL) { + delete_tree(instance, cdr(args)); + delete_object(instance, args); + return &alsa_lisp_nil; + } + snd_ctl_elem_id_alloca(&id); + p1 = car(cdr(args)); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + if (parse_ctl_elem_id(instance, eval(instance, p1), id) < 0) + return &alsa_lisp_nil; + return new_cons_pointer(instance, "hctl_elem", snd_hctl_find_elem(handle, id)); +} + +static struct alisp_object * FA_hctl_elem_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_hctl_elem_t *handle; + struct alisp_object * lexpr, * p1, * p2; + snd_ctl_elem_info_t *info; + snd_ctl_elem_id_t *id; + snd_ctl_elem_type_t type; + int err; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (snd_hctl_elem_t *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_id_alloca(&id); + err = snd_hctl_elem_info(handle, info); + lexpr = new_lexpr(instance, err); + if (err < 0) + return lexpr; + type = snd_ctl_elem_info_get_type(info); + p1 = add_cons(instance, lexpr->value.c.cdr, 0, "id", p2 = new_object(instance, ALISP_OBJ_CONS)); + snd_ctl_elem_info_get_id(info, id); + if (create_ctl_elem_id(instance, id, p2) == NULL) { + delete_tree(instance, lexpr); + return NULL; + } + p1 = add_cons(instance, p1, 1, "type", new_string(instance, snd_ctl_elem_type_name(type))); + p1 = add_cons(instance, p1, 1, "readable", new_integer(instance, snd_ctl_elem_info_is_readable(info))); + p1 = add_cons(instance, p1, 1, "writeable", new_integer(instance, snd_ctl_elem_info_is_writable(info))); + p1 = add_cons(instance, p1, 1, "volatile", new_integer(instance, snd_ctl_elem_info_is_volatile(info))); + p1 = add_cons(instance, p1, 1, "inactive", new_integer(instance, snd_ctl_elem_info_is_inactive(info))); + p1 = add_cons(instance, p1, 1, "locked", new_integer(instance, snd_ctl_elem_info_is_locked(info))); + p1 = add_cons(instance, p1, 1, "isowner", new_integer(instance, snd_ctl_elem_info_is_owner(info))); + p1 = add_cons(instance, p1, 1, "owner", new_integer(instance, snd_ctl_elem_info_get_owner(info))); + p1 = add_cons(instance, p1, 1, "count", new_integer(instance, snd_ctl_elem_info_get_count(info))); + err = snd_ctl_elem_info_get_dimensions(info); + if (err > 0) { + int idx; + p1 = add_cons(instance, p1, 1, "dimensions", p2 = new_object(instance, ALISP_OBJ_CONS)); + for (idx = 0; idx < err; idx++) + p2 = add_cons2(instance, p2, idx > 0, new_integer(instance, snd_ctl_elem_info_get_dimension(info, idx))); + } + switch (type) { + case SND_CTL_ELEM_TYPE_ENUMERATED: { + unsigned int items, item; + items = snd_ctl_elem_info_get_items(info); + p1 = add_cons(instance, p1, 1, "items", p2 = new_object(instance, ALISP_OBJ_CONS)); + for (item = 0; item < items; item++) { + snd_ctl_elem_info_set_item(info, item); + err = snd_hctl_elem_info(handle, info); + if (err < 0) { + p2 = add_cons2(instance, p2, item, &alsa_lisp_nil); + } else { + p2 = add_cons2(instance, p2, item, new_string(instance, snd_ctl_elem_info_get_item_name(info))); + } + } + break; + } + case SND_CTL_ELEM_TYPE_INTEGER: + p1 = add_cons(instance, p1, 1, "min", new_integer(instance, snd_ctl_elem_info_get_min(info))); + p1 = add_cons(instance, p1, 1, "max", new_integer(instance, snd_ctl_elem_info_get_max(info))); + p1 = add_cons(instance, p1, 1, "step", new_integer(instance, snd_ctl_elem_info_get_step(info))); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + p1 = add_cons(instance, p1, 1, "min64", new_float(instance, snd_ctl_elem_info_get_min64(info))); + p1 = add_cons(instance, p1, 1, "max64", new_float(instance, snd_ctl_elem_info_get_max64(info))); + p1 = add_cons(instance, p1, 1, "step64", new_float(instance, snd_ctl_elem_info_get_step64(info))); + break; + default: + break; + } + if (p1 == NULL) { + delete_tree(instance, lexpr); + return NULL; + } + return lexpr; +} + +static struct alisp_object * FA_hctl_elem_read(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_hctl_elem_t *handle; + struct alisp_object * lexpr, * p1 = NULL, * obj; + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *value; + snd_ctl_elem_type_t type; + unsigned int idx, count; + int err; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (snd_hctl_elem_t *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_value_alloca(&value); + err = snd_hctl_elem_info(handle, info); + if (err >= 0) + err = snd_hctl_elem_read(handle, value); + lexpr = new_lexpr(instance, err); + if (err < 0) + return lexpr; + type = snd_ctl_elem_info_get_type(info); + count = snd_ctl_elem_info_get_count(info); + if (type == SND_CTL_ELEM_TYPE_IEC958) { + count = sizeof(snd_aes_iec958_t); + type = SND_CTL_ELEM_TYPE_BYTES; + } + for (idx = 0; idx < count; idx++) { + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + obj = new_integer(instance, snd_ctl_elem_value_get_boolean(value, idx)); + break; + case SND_CTL_ELEM_TYPE_INTEGER: + obj = new_integer(instance, snd_ctl_elem_value_get_integer(value, idx)); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + obj = new_integer(instance, snd_ctl_elem_value_get_integer64(value, idx)); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + obj = new_integer(instance, snd_ctl_elem_value_get_enumerated(value, idx)); + break; + case SND_CTL_ELEM_TYPE_BYTES: + obj = new_integer(instance, snd_ctl_elem_value_get_byte(value, idx)); + break; + default: + obj = NULL; + break; + } + if (idx == 0) { + p1 = add_cons2(instance, lexpr->value.c.cdr, 0, obj); + } else { + p1 = add_cons2(instance, p1, 1, obj); + } + } + if (p1 == NULL) { + delete_tree(instance, lexpr); + return &alsa_lisp_nil; + } + return lexpr; +} + +static struct alisp_object * FA_hctl_elem_write(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_hctl_elem_t *handle; + struct alisp_object * p1 = NULL, * obj; + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *value; + snd_ctl_elem_type_t type; + unsigned int idx, count; + int err; + + p1 = car(cdr(args)); + obj = eval(instance, car(args)); + delete_tree(instance, cdr(cdr(args))); + delete_object(instance, cdr(args)); + delete_object(instance, args); + handle = (snd_hctl_elem_t *)get_ptr(instance, obj, item->prefix); + if (handle == NULL) { + delete_tree(instance, p1); + return &alsa_lisp_nil; + } + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_value_alloca(&value); + err = snd_hctl_elem_info(handle, info); + if (err < 0) { + delete_tree(instance, p1); + return new_integer(instance, err); + } + type = snd_ctl_elem_info_get_type(info); + count = snd_ctl_elem_info_get_count(info); + if (type == SND_CTL_ELEM_TYPE_IEC958) { + count = sizeof(snd_aes_iec958_t); + type = SND_CTL_ELEM_TYPE_BYTES; + } + idx = -1; + do { + if (++idx >= count) { + delete_tree(instance, p1); + break; + } + obj = car(p1); + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + snd_ctl_elem_value_set_boolean(value, idx, get_integer(obj)); + break; + case SND_CTL_ELEM_TYPE_INTEGER: + snd_ctl_elem_value_set_integer(value, idx, get_integer(obj)); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + snd_ctl_elem_value_set_integer64(value, idx, get_integer(obj)); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + snd_ctl_elem_value_set_enumerated(value, idx, get_integer(obj)); + break; + case SND_CTL_ELEM_TYPE_BYTES: + snd_ctl_elem_value_set_byte(value, idx, get_integer(obj)); + break; + default: + break; + } + delete_tree(instance, obj); + p1 = cdr(obj = p1); + delete_object(instance, obj); + } while (p1 != &alsa_lisp_nil); + err = snd_hctl_elem_write(handle, value); + return new_integer(instance, err); +} + +static struct alisp_object * FA_pcm_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args) +{ + snd_pcm_t *handle; + struct alisp_object * lexpr, * p1; + snd_pcm_info_t *info; + int err; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + handle = (snd_pcm_t *)get_ptr(instance, p1, item->prefix); + if (handle == NULL) + return &alsa_lisp_nil; + snd_pcm_info_alloca(&info); + err = snd_pcm_info(handle, info); + lexpr = new_lexpr(instance, err); + if (err < 0) + return lexpr; + p1 = add_cons(instance, lexpr->value.c.cdr, 0, "card", new_integer(instance, snd_pcm_info_get_card(info))); + p1 = add_cons(instance, p1, 1, "device", new_integer(instance, snd_pcm_info_get_device(info))); + p1 = add_cons(instance, p1, 1, "subdevice", new_integer(instance, snd_pcm_info_get_subdevice(info))); + p1 = add_cons(instance, p1, 1, "id", new_string(instance, snd_pcm_info_get_id(info))); + p1 = add_cons(instance, p1, 1, "name", new_string(instance, snd_pcm_info_get_name(info))); + p1 = add_cons(instance, p1, 1, "subdevice_name", new_string(instance, snd_pcm_info_get_subdevice_name(info))); + p1 = add_cons(instance, p1, 1, "class", new_integer(instance, snd_pcm_info_get_class(info))); + p1 = add_cons(instance, p1, 1, "subclass", new_integer(instance, snd_pcm_info_get_subclass(info))); + p1 = add_cons(instance, p1, 1, "subdevices_count", new_integer(instance, snd_pcm_info_get_subdevices_count(info))); + p1 = add_cons(instance, p1, 1, "subdevices_avail", new_integer(instance, snd_pcm_info_get_subdevices_avail(info))); + //p1 = add_cons(instance, p1, 1, "sync", new_string(instance, snd_pcm_info_get_sync(info))); + return lexpr; +} + +/* + * main code + */ + +static const struct acall_table acall_table[] = { + { "card_get_index", &FA_int_str, (void *)snd_card_get_index, NULL }, + { "card_get_longname", &FA_int_int_strp, (void *)snd_card_get_longname, NULL }, + { "card_get_name", &FA_int_int_strp, (void *)snd_card_get_name, NULL }, + { "card_next", &FA_int_intp, (void *)&snd_card_next, NULL }, + { "ctl_card_info", &FA_card_info, NULL, "ctl" }, + { "ctl_close", &FA_int_p, (void *)&snd_ctl_close, "ctl" }, + { "ctl_open", &FA_int_pp_strp_int, (void *)&snd_ctl_open, "ctl" }, + { "hctl_close", &FA_int_p, (void *)&snd_hctl_close, "hctl" }, + { "hctl_ctl", &FA_p_p, (void *)&snd_hctl_ctl, "hctl" }, + { "hctl_elem_info", &FA_hctl_elem_info, (void *)&snd_hctl_elem_info, "hctl_elem" }, + { "hctl_elem_next", &FA_p_p, (void *)&snd_hctl_elem_next, "hctl_elem" }, + { "hctl_elem_prev", &FA_p_p, (void *)&snd_hctl_elem_prev, "hctl_elem" }, + { "hctl_elem_read", &FA_hctl_elem_read, (void *)&snd_hctl_elem_read, "hctl_elem" }, + { "hctl_elem_write", &FA_hctl_elem_write, (void *)&snd_hctl_elem_write, "hctl_elem" }, + { "hctl_find_elem", &FA_hctl_find_elem, (void *)&snd_hctl_find_elem, "hctl" }, + { "hctl_first_elem", &FA_p_p, (void *)&snd_hctl_first_elem, "hctl" }, + { "hctl_free", &FA_int_p, (void *)&snd_hctl_free, "hctl" }, + { "hctl_last_elem", &FA_p_p, (void *)&snd_hctl_last_elem, "hctl" }, + { "hctl_load", &FA_int_p, (void *)&snd_hctl_load, "hctl" }, + { "hctl_open", &FA_int_pp_strp_int, (void *)&snd_hctl_open, "hctl" }, + { "hctl_open_ctl", &FA_int_pp_p, (void *)&snd_hctl_open_ctl, "hctl" }, + { "pcm_info", &FA_pcm_info, NULL, "pcm" }, + { "pcm_name", &FA_str_p, (void *)&snd_pcm_name, "pcm" }, +}; + +static int acall_compar(const void *p1, const void *p2) +{ + return strcmp(((struct acall_table *)p1)->name, + ((struct acall_table *)p2)->name); +} + +static struct alisp_object * F_acall(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p1, *p2; + struct acall_table key, *item; + + p1 = eval(instance, car(args)); + p2 = cdr(args); + delete_object(instance, args); + if (!alisp_compare_type(p1, ALISP_OBJ_IDENTIFIER) && + !alisp_compare_type(p1, ALISP_OBJ_STRING)) { + delete_tree(instance, p2); + return &alsa_lisp_nil; + } + key.name = p1->value.s; + if ((item = bsearch(&key, acall_table, + sizeof acall_table / sizeof acall_table[0], + sizeof acall_table[0], acall_compar)) != NULL) { + delete_tree(instance, p1); + return item->func(instance, item, p2); + } + delete_tree(instance, p1); + delete_tree(instance, p2); + lisp_warn(instance, "acall function %s' is undefined", p1->value.s); + return &alsa_lisp_nil; +} + +static struct alisp_object * F_ahandle(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object *p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + args = car(cdr(p1)); + delete_tree(instance, cdr(cdr(p1))); + delete_object(instance, cdr(p1)); + delete_tree(instance, car(p1)); + delete_object(instance, p1); + return args; +} + +static struct alisp_object * F_aerror(struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object *p1; + + p1 = eval(instance, car(args)); + delete_tree(instance, cdr(args)); + delete_object(instance, args); + args = car(p1); + if (args == &alsa_lisp_nil) { + delete_tree(instance, p1); + return new_integer(instance, SND_ERROR_ALISP_NIL); + } else { + delete_tree(instance, cdr(p1)); + delete_object(instance, p1); + } + return args; +} + +static int common_error(snd_output_t **rout, struct alisp_instance *instance, struct alisp_object * args) +{ + struct alisp_object * p = args, * p1; + snd_output_t *out; + int err; + + err = snd_output_buffer_open(&out); + if (err < 0) { + delete_tree(instance, args); + return err; + } + + do { + p1 = eval(instance, car(p)); + if (alisp_compare_type(p1, ALISP_OBJ_STRING)) + snd_output_printf(out, "%s", p1->value.s); + else + princ_object(out, p1); + delete_tree(instance, p1); + p = cdr(p1 = p); + delete_object(instance, p1); + } while (p != &alsa_lisp_nil); + + *rout = out; + return 0; +} + +static struct alisp_object * F_snderr(struct alisp_instance *instance, struct alisp_object * args) +{ + snd_output_t *out; + char *str; + + if (common_error(&out, instance, args) < 0) + return &alsa_lisp_nil; + snd_output_buffer_string(out, &str); + SNDERR(str); + snd_output_close(out); + return &alsa_lisp_t; +} + +static struct alisp_object * F_syserr(struct alisp_instance *instance, struct alisp_object * args) +{ + snd_output_t *out; + char *str; + + if (common_error(&out, instance, args) < 0) + return &alsa_lisp_nil; + snd_output_buffer_string(out, &str); + SYSERR(str); + snd_output_close(out); + return &alsa_lisp_t; +} + +static const struct intrinsic snd_intrinsics[] = { + { "Acall", F_acall }, + { "Aerror", F_aerror }, + { "Ahandle", F_ahandle }, + { "Aresult", F_ahandle }, + { "Asnderr", F_snderr }, + { "Asyserr", F_syserr } +}; diff --git a/src/async.c b/src/async.c new file mode 100644 index 0000000..98aec78 --- /dev/null +++ b/src/async.c @@ -0,0 +1,206 @@ +/** + * \file async.c + * \brief Async notification helpers + * \author Abramo Bagnara + * \date 2001 + */ +/* + * Async notification helpers + * Copyright (c) 2001 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm/pcm_local.h" +#include "control/control_local.h" +#include + +#ifdef SND_ASYNC_RT_SIGNAL +/** async signal number */ +static int snd_async_signo; + +void snd_async_init(void) __attribute__ ((constructor)); + +void snd_async_init(void) +{ + snd_async_signo = __libc_allocate_rtsig(0); + if (snd_async_signo < 0) { + SNDERR("Unable to find a RT signal to use for snd_async"); + exit(1); + } +} +#else +/** async signal number */ +static const int snd_async_signo = SIGIO; +#endif + +static LIST_HEAD(snd_async_handlers); + +static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) +{ + int fd; + struct list_head *i; + //assert(siginfo->si_code == SI_SIGIO); + fd = siginfo->si_fd; + list_for_each(i, &snd_async_handlers) { + snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); + if (h->fd == fd && h->callback) + h->callback(h); + } +} + +/** + * \brief Registers an async handler. + * \param handler The function puts the pointer to the new async handler + * object at the address specified by \p handler. + * \param fd The file descriptor to be associated with the callback. + * \param callback The async callback function. + * \param private_data Private data for the async callback function. + * \result Zero if successful, otherwise a negative error code. + * + * This function associates the callback function with the given file, + * and saves this association in a \c snd_async_handler_t object. + * + * Whenever the \c SIGIO signal is raised for the file \p fd, the callback + * function will be called with its parameter pointing to the async handler + * object returned by this function. + * + * The ALSA \c sigaction handler for the \c SIGIO signal automatically + * multiplexes the notifications to the registered async callbacks. + * However, the application is responsible for instructing the device driver + * to generate the \c SIGIO signal. + * + * The \c SIGIO signal may have been replaced with another signal, + * see #snd_async_handler_get_signo. + * + * When the async handler isn't needed anymore, you must delete it with + * #snd_async_del_handler. + * + * \see snd_async_add_pcm_handler, snd_async_add_ctl_handler + */ +int snd_async_add_handler(snd_async_handler_t **handler, int fd, + snd_async_callback_t callback, void *private_data) +{ + snd_async_handler_t *h; + int was_empty; + assert(handler); + h = malloc(sizeof(*h)); + if (!h) + return -ENOMEM; + h->fd = fd; + h->callback = callback; + h->private_data = private_data; + was_empty = list_empty(&snd_async_handlers); + list_add_tail(&h->glist, &snd_async_handlers); + INIT_LIST_HEAD(&h->hlist); + *handler = h; + if (was_empty) { + int err; + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_flags = SA_RESTART | SA_SIGINFO; + act.sa_sigaction = snd_async_handler; + sigemptyset(&act.sa_mask); + err = sigaction(snd_async_signo, &act, NULL); + if (err < 0) { + SYSERR("sigaction"); + return -errno; + } + } + return 0; +} + +/** + * \brief Deletes an async handler. + * \param handler Handle of the async handler to delete. + * \result Zero if successful, otherwise a negative error code. + */ +int snd_async_del_handler(snd_async_handler_t *handler) +{ + int err = 0; + assert(handler); + list_del(&handler->glist); + if (list_empty(&snd_async_handlers)) { + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_flags = 0; + act.sa_handler = SIG_DFL; + err = sigaction(snd_async_signo, &act, NULL); + if (err < 0) { + SYSERR("sigaction"); + return -errno; + } + } + if (handler->type == SND_ASYNC_HANDLER_GENERIC) + goto _end; + if (!list_empty(&handler->hlist)) + list_del(&handler->hlist); + if (!list_empty(&handler->hlist)) + goto _end; + switch (handler->type) { +#ifdef BUILD_PCM + case SND_ASYNC_HANDLER_PCM: + err = snd_pcm_async(handler->u.pcm, -1, 1); + break; +#endif + case SND_ASYNC_HANDLER_CTL: + err = snd_ctl_async(handler->u.ctl, -1, 1); + break; + default: + assert(0); + } + _end: + free(handler); + return err; +} + +/** + * \brief Returns the signal number assigned to an async handler. + * \param handler Handle to an async handler. + * \result The signal number if successful, otherwise a negative error code. + * + * The signal number for async handlers usually is \c SIGIO, + * but wizards can redefine it to a realtime signal + * when compiling the ALSA library. + */ +int snd_async_handler_get_signo(snd_async_handler_t *handler) +{ + assert(handler); + return snd_async_signo; +} + +/** + * \brief Returns the file descriptor assigned to an async handler. + * \param handler Handle to an async handler. + * \result The file descriptor if successful, otherwise a negative error code. + */ +int snd_async_handler_get_fd(snd_async_handler_t *handler) +{ + assert(handler); + return handler->fd; +} + +/** + * \brief Returns the private data assigned to an async handler. + * \param handler Handle to an async handler. + * \result The \c private_data value registered with the async handler. + */ +void *snd_async_handler_get_callback_private(snd_async_handler_t *handler) +{ + assert(handler); + return handler->private_data; +} + diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am new file mode 100644 index 0000000..01f54fc --- /dev/null +++ b/src/compat/Makefile.am @@ -0,0 +1,8 @@ +noinst_LTLIBRARIES = libcompat.la +EXTRA_libcompat_la_SOURCES = hsearch_r.c + +if ALSA_HSEARCH_R +libcompat_la_SOURCES = empty.c hsearch_r.c +else +libcompat_la_SOURCES = empty.c +endif diff --git a/src/compat/Makefile.in b/src/compat/Makefile.in new file mode 100644 index 0000000..b40821e --- /dev/null +++ b/src/compat/Makefile.in @@ -0,0 +1,502 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/compat +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libcompat_la_LIBADD = +am__libcompat_la_SOURCES_DIST = empty.c hsearch_r.c +@ALSA_HSEARCH_R_FALSE@am_libcompat_la_OBJECTS = empty.lo +@ALSA_HSEARCH_R_TRUE@am_libcompat_la_OBJECTS = empty.lo hsearch_r.lo +libcompat_la_OBJECTS = $(am_libcompat_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libcompat_la_SOURCES) $(EXTRA_libcompat_la_SOURCES) +DIST_SOURCES = $(am__libcompat_la_SOURCES_DIST) \ + $(EXTRA_libcompat_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libcompat.la +EXTRA_libcompat_la_SOURCES = hsearch_r.c +@ALSA_HSEARCH_R_FALSE@libcompat_la_SOURCES = empty.c +@ALSA_HSEARCH_R_TRUE@libcompat_la_SOURCES = empty.c hsearch_r.c +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/compat/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/compat/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libcompat.la: $(libcompat_la_OBJECTS) $(libcompat_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libcompat_la_OBJECTS) $(libcompat_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/empty.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hsearch_r.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/compat/empty.c b/src/compat/empty.c new file mode 100644 index 0000000..e69de29 diff --git a/src/compat/hsearch_r.c b/src/compat/hsearch_r.c new file mode 100644 index 0000000..96ceac1 --- /dev/null +++ b/src/compat/hsearch_r.c @@ -0,0 +1,236 @@ +/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1993. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include + +#define __USE_GNU +#ifndef __set_errno +#define __set_errno(e) errno = (e) +#endif +#include + +/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 + [Knuth] The Art of Computer Programming, part 3 (6.4) */ + + +/* The reentrant version has no static variables to maintain the state. + Instead the interface of all functions is extended to take an argument + which describes the current status. */ +typedef struct _ENTRY +{ + unsigned int used; + ENTRY entry; +} +_ENTRY; + + +/* For the used double hash method the table size has to be a prime. To + correct the user given table size we need a prime test. This trivial + algorithm is adequate because + a) the code is (most probably) called a few times per program run and + b) the number is small because the table must fit in the core */ +static int +isprime (unsigned int number) +{ + /* no even number will be passed */ + unsigned int div = 3; + + while (div * div < number && number % div != 0) + div += 2; + + return number % div != 0; +} + + +/* Before using the hash table we must allocate memory for it. + Test for an existing table are done. We allocate one element + more as the found prime number says. This is done for more effective + indexing as explained in the comment for the hsearch function. + The contents of the table is zeroed, especially the field used + becomes zero. */ +int +hcreate_r (nel, htab) + size_t nel; + struct hsearch_data *htab; +{ + /* Test for correct arguments. */ + if (htab == NULL) + { + __set_errno (EINVAL); + return 0; + } + + /* There is still another table active. Return with error. */ + if (htab->table != NULL) + return 0; + + /* Change nel to the first prime number not smaller as nel. */ + nel |= 1; /* make odd */ + while (!isprime (nel)) + nel += 2; + + htab->size = nel; + htab->filled = 0; + + /* allocate memory and zero out */ + htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY)); + if (htab->table == NULL) + return 0; + + /* everything went alright */ + return 1; +} + + +/* After using the hash table it has to be destroyed. The used memory can + be freed and the local static variable can be marked as not used. */ +void +hdestroy_r (htab) + struct hsearch_data *htab; +{ + /* Test for correct arguments. */ + if (htab == NULL) + { + __set_errno (EINVAL); + return; + } + + if (htab->table != NULL) + /* free used memory */ + free (htab->table); + + /* the sign for an existing table is an value != NULL in htable */ + htab->table = NULL; +} + + +/* This is the search function. It uses double hashing with open addressing. + The argument item.key has to be a pointer to an zero terminated, most + probably strings of chars. The function for generating a number of the + strings is simple but fast. It can be replaced by a more complex function + like ajw (see [Aho,Sethi,Ullman]) if the needs are shown. + + We use an trick to speed up the lookup. The table is created by hcreate + with one more element available. This enables us to use the index zero + special. This index will never be used because we store the first hash + index in the field used where zero means not used. Every other value + means used. The used field can be used as a first fast comparison for + equality of the stored and the parameter value. This helps to prevent + unnecessary expensive calls of strcmp. */ +int +hsearch_r (item, action, retval, htab) + ENTRY item; + ACTION action; + ENTRY **retval; + struct hsearch_data *htab; +{ + unsigned int hval; + unsigned int count; + unsigned int len = strlen (item.key); + unsigned int idx; + + /* Compute an value for the given string. Perhaps use a better method. */ + hval = len; + count = len; + while (count-- > 0) + { + hval <<= 4; + hval += item.key[count]; + } + + /* First hash function: simply take the modulo but prevent zero. */ + hval %= htab->size; + if (hval == 0) + ++hval; + + /* The first index tried. */ + idx = hval; + + if (htab->table[idx].used) + { + /* Further action might be required according to the action value. */ + unsigned hval2; + + if (htab->table[idx].used == hval + && strcmp (item.key, htab->table[idx].entry.key) == 0) + { + if (action == ENTER) + htab->table[idx].entry.data = item.data; + + *retval = &htab->table[idx].entry; + return 1; + } + + /* Second hash function, as suggested in [Knuth] */ + hval2 = 1 + hval % (htab->size - 2); + + do + { + /* Because SIZE is prime this guarantees to step through all + available indexes. */ + if (idx <= hval2) + idx = htab->size + idx - hval2; + else + idx -= hval2; + + /* If we visited all entries leave the loop unsuccessfully. */ + if (idx == hval) + break; + + /* If entry is found use it. */ + if (htab->table[idx].used == hval + && strcmp (item.key, htab->table[idx].entry.key) == 0) + { + if (action == ENTER) + htab->table[idx].entry.data = item.data; + + *retval = &htab->table[idx].entry; + return 1; + } + } + while (htab->table[idx].used); + } + + /* An empty bucket has been found. */ + if (action == ENTER) + { + /* If table is full and another entry should be entered return + with error. */ + if (action == ENTER && htab->filled == htab->size) + { + __set_errno (ENOMEM); + *retval = NULL; + return 0; + } + + htab->table[idx].used = hval; + htab->table[idx].entry = item; + + ++htab->filled; + + *retval = &htab->table[idx].entry; + return 1; + } + + __set_errno (ESRCH); + *retval = NULL; + return 0; +} diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000..8939d62 --- /dev/null +++ b/src/conf.c @@ -0,0 +1,4770 @@ +/** + * \file conf.c + * \ingroup Configuration + * \brief Configuration helper functions + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2000-2001 + * + * Tree based, full nesting configuration functions. + * + * See the \ref conf page for more details. + */ +/* + * Configuration helper functions + * Copyright (c) 2000 by Abramo Bagnara , + * Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page conf Configuration files + +

Configuration files use a simple format allowing modern +data description like nesting and array assignments.

+ +\section conf_whitespace Whitespace + +Whitespace is the collective name given to spaces (blanks), horizontal and +vertical tabs, newline characters, and comments. Whitespace can +indicate where configuration tokens start and end, but beyond this function, +any surplus whitespace is discarded. For example, the two sequences + +\code + a 1 b 2 +\endcode + +and + +\code + a 1 + b 2 +\endcode + +are lexically equivalent and parse identically to give the four tokens: + +\code +a +1 +b +2 +\endcode + +The ASCII characters representing whitespace can occur within literal +strings, in which case they are protected from the normal parsing process +(they remain as part of the string). For example: + +\code + name "John Smith" +\endcode + +parses to two tokens, including the single literal-string token "John +Smith". + +\section conf_linesplicing Line continuation with \ + +A special case occurs if a newline character in a string is preceded +by a backslash (\). The backslash and the new line are both discarded, +allowing two physical lines of text to be treated as one unit. + +\code +"John \ +Smith" +\endcode + +is parsed as "John Smith". + +\section conf_comments Comments + +A single-line comment begins with the character #. The comment can start +at any position, and extends to the end of the line. + +\code + a 1 # this is a comment +\endcode + +\section conf_include Including configuration files + +To include another configuration file, write the file name in angle brackets. +The prefix \c confdir: will reference the global configuration directory. + +\code + + +\endcode + +\section conf_punctuators Punctuators + +The configuration punctuators (also known as separators) are: + +\code + {} [] , ; = . ' " new-line form-feed carriage-return whitespace +\endcode + +\subsection conf_braces Braces + +Opening and closing braces { } indicate the start and end of a compound +statement: + +\code +a { + b 1 +} +\endcode + +\subsection conf_brackets Brackets + +Opening and closing brackets indicate a single array definition. The +identifiers are automatically generated starting with zero. + +\code +a [ + "first" + "second" +] +\endcode + +The above code is equal to + +\code +a.0 "first" +a.1 "second" +\endcode + +\subsection conf_comma_semicolon Comma and semicolon + +The comma (,) or semicolon (;) can separate value assignments. It is not +strictly required to use these separators because whitespace suffices to +separate tokens. + +\code +a 1; +b 1, +\endcode + +\subsection conf_equal Equal sign + +The equal sign (=) can separate variable declarations from +initialization lists: + +\code +a=1 +b=2 +\endcode + +Using equal signs is not required because whitespace suffices to separate +tokens. + +\section conf_assigns Assignments + +The configuration file defines id (key) and value pairs. The id (key) can be +composed from ASCII digits, characters from a to z and A to Z, and the +underscore (_). The value can be either a string, an integer, a real number, +or a compound statement. + +\subsection conf_single Single assignments + +\code +a 1 # is equal to +a=1 # is equal to +a=1; # is equal to +a 1, +\endcode + +\subsection conf_compound Compound assignments (definitions using braces) + +\code +a { + b = 1 +} +a={ + b 1, +} +\endcode + +\section conf_compound1 Compound assignments (one key definitions) + +\code +a.b 1 +a.b=1 +\endcode + +\subsection conf_array Array assignments (definitions using brackets) + +\code +a [ + "first" + "second" +] +\endcode + +\subsection conf_array1 Array assignments (one key definitions) + +\code +a.0 "first" +a.1 "second" +\endcode + +\section conf_mode Operation modes for parsing nodes + +By default, the node operation mode is 'merge+create', i.e., if +a configuration node is not present a new one is created, otherwise +the latest assignment is merged (if possible - type checking). The +'merge+create' operation mode is specified with the prefix character plus (+). + +The operation mode 'merge' merges the node with the old one (which must +exist). Type checking is done, so strings cannot be assigned to integers +and so on. This mode is specified with the prefix character minus (-). + +The operation mode 'do not override' ignores a new configuration node +if a configuration node with the same name exists. This mode is specified with +the prefix character question mark (?). + +The operation mode 'override' always overrides the old configuration node +with new contents. This mode is specified with the prefix character +exclamation mark (!). + +\code +defaults.pcm.!device 1 +\endcode + +\section conf_syntax_summary Syntax summary + +\code +# Configuration file syntax + +# Include a new configuration file + + +# Simple assignment +name [=] value [,|;] + +# Compound assignment (first style) +name [=] { + name1 [=] value [,|;] + ... +} + +# Compound assignment (second style) +name.name1 [=] value [,|;] + +# Array assignment (first style) +name [ + value0 [,|;] + value1 [,|;] + ... +] + +# Array assignment (second style) +name.0 [=] value0 [,|;] +name.1 [=] value1 [,|;] +\endcode + +\section conf_syntax_ref References + +\ref confarg +\ref conffunc +\ref confhooks + +*/ + +/*! \page confarg Runtime arguments in configuration files + +

The ALSA library can accept runtime arguments for some configuration +blocks. This extension is built on top of the basic configuration file +syntax.

+ +\section confarg_define Defining arguments + +Arguments are defined using the id (key) \c \@args and array values containing +the string names of the arguments: + +\code +@args [ CARD ] # or +@args.0 CARD +\endcode + +\section confarg_type Defining argument types and default values + +An argument's type is specified with the id (key) \c \@args and the argument +name. The type and the default value are specified in the compound block: + +\code +@args.CARD { + type string + default "abcd" +} +\endcode + +\section confarg_refer Referring to arguments + +Arguments are referred to with a dollar-sign ($) and the name of the argument: + +\code + card $CARD +\endcode + +\section confarg_usage Usage + +To use a block with arguments, write the argument values after the key, +separated with a colon (:). For example, all these names for PCM interfaces +give the same result: + +\code +hw:0,1 +hw:CARD=0,DEV=1 +hw:{CARD 0 DEV 1} +plug:"hw:0,1" +plug:{SLAVE="hw:{CARD 0 DEV 1}"} +\endcode + +As you see, arguments can be specified in their proper order or by name. +Note that arguments enclosed in braces are parsed in the same way as in +configuration files, but using the override method by default. + +\section confarg_example Example + +\code +pcm.demo { + @args [ CARD DEVICE ] + @args.CARD { + type string + default "supersonic" + } + @args.DEVICE { + type integer + default 0 + } + type hw + card $CARD + device $DEVICE +} +\endcode + +*/ + +/*! \page conffunc Runtime functions in configuration files + +

The ALSA library can modify the configuration at runtime. +Several built-in functions are available.

+ +

A function is defined with the id \c \@func and the function name. All other +values in the current compound are used as configuration for the function. +If the compound func.\ is defined in the root node, then the +library and function from this compound configuration are used, otherwise +'snd_func_' is prefixed to the string and code from the ALSA library is used. +The definition of a function looks like:

+ +\code +func.remove_first_char { + lib "/usr/lib/libasoundextend.so" + func "extend_remove_first_char" +} +\endcode + +*/ + +/*! \page confhooks Hooks in configuration files + +

The hook extension in the ALSA library allows expansion of configuration +nodes at run-time. The existence of a hook is determined by the +presence of a \@hooks compound node.

+ +

This example defines a hook which loads two configuration files at the +beginning:

+ +\code +@hooks [ + { + func load + files [ + "/etc/asound.conf" + "~/.asoundrc" + ] + errors false + } +] +\endcode + +\section confhooks_ref Function reference + +
    +
  • The function load - \c snd_config_hook_load() - loads and parses the + given configuration files. +
  • The function load_for_all_cards - \c snd_config_hook_load_for_all_cards() - + loads and parses the given configuration files for each installed sound + card. The driver name (the type of the sound card) is passed in the + private configuration node. +
+ +*/ + + +#include +#include +#include +#include +#include "local.h" +#ifdef HAVE_LIBPTHREAD +#include +#endif + +#ifndef DOC_HIDDEN + +#ifdef HAVE_LIBPTHREAD +static pthread_mutex_t snd_config_update_mutex = + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#endif + +struct _snd_config { + char *id; + snd_config_type_t type; + union { + long integer; + long long integer64; + char *string; + double real; + const void *ptr; + struct { + struct list_head fields; + int join; + } compound; + } u; + struct list_head list; + snd_config_t *parent; + int hop; +}; + +struct filedesc { + char *name; + snd_input_t *in; + unsigned int line, column; + struct filedesc *next; +}; + +#define LOCAL_ERROR (-0x68000000) + +#define LOCAL_UNTERMINATED_STRING (LOCAL_ERROR - 0) +#define LOCAL_UNTERMINATED_QUOTE (LOCAL_ERROR - 1) +#define LOCAL_UNEXPECTED_CHAR (LOCAL_ERROR - 2) +#define LOCAL_UNEXPECTED_EOF (LOCAL_ERROR - 3) + +typedef struct { + struct filedesc *current; + int unget; + int ch; +} input_t; + +#ifdef HAVE_LIBPTHREAD + +static inline void snd_config_lock(void) +{ + pthread_mutex_lock(&snd_config_update_mutex); +} + +static inline void snd_config_unlock(void) +{ + pthread_mutex_unlock(&snd_config_update_mutex); +} + +#else + +static inline void snd_config_lock(void) { } +static inline void snd_config_unlock(void) { } + +#endif + +static int safe_strtoll(const char *str, long long *val) +{ + long long v; + int endidx; + if (!*str) + return -EINVAL; + errno = 0; + if (sscanf(str, "%Li%n", &v, &endidx) < 1) + return -EINVAL; + if (str[endidx]) + return -EINVAL; + *val = v; + return 0; +} + +int safe_strtol(const char *str, long *val) +{ + char *end; + long v; + if (!*str) + return -EINVAL; + errno = 0; + v = strtol(str, &end, 0); + if (errno) + return -errno; + if (*end) + return -EINVAL; + *val = v; + return 0; +} + +static int safe_strtod(const char *str, double *val) +{ + char *end; + double v; +#ifdef HAVE_USELOCALE + locale_t saved_locale, c_locale; +#else + char *saved_locale; + char locstr[64]; /* enough? */ +#endif + int err; + + if (!*str) + return -EINVAL; +#ifdef HAVE_USELOCALE + c_locale = newlocale(LC_NUMERIC_MASK, "C", 0); + saved_locale = uselocale(c_locale); +#else + saved_locale = setlocale(LC_NUMERIC, NULL); + if (saved_locale) { + snprintf(locstr, sizeof(locstr), "%s", saved_locale); + setlocale(LC_NUMERIC, "C"); + } +#endif + errno = 0; + v = strtod(str, &end); + err = -errno; +#ifdef HAVE_USELOCALE + if (c_locale != (locale_t)0) { + uselocale(saved_locale); + freelocale(c_locale); + } +#else + if (saved_locale) + setlocale(LC_NUMERIC, locstr); +#endif + if (err) + return err; + if (*end) + return -EINVAL; + *val = v; + return 0; +} + +static int get_char(input_t *input) +{ + int c; + struct filedesc *fd; + if (input->unget) { + input->unget = 0; + return input->ch; + } + again: + fd = input->current; + c = snd_input_getc(fd->in); + switch (c) { + case '\n': + fd->column = 0; + fd->line++; + break; + case '\t': + fd->column += 8 - fd->column % 8; + break; + case EOF: + if (fd->next) { + snd_input_close(fd->in); + free(fd->name); + input->current = fd->next; + free(fd); + goto again; + } + return LOCAL_UNEXPECTED_EOF; + default: + fd->column++; + break; + } + return (unsigned char)c; +} + +static void unget_char(int c, input_t *input) +{ + assert(!input->unget); + input->ch = c; + input->unget = 1; +} + +static int get_delimstring(char **string, int delim, input_t *input); + +static int get_char_skip_comments(input_t *input) +{ + int c; + while (1) { + c = get_char(input); + if (c == '<') { + char *str; + snd_input_t *in; + struct filedesc *fd; + int err = get_delimstring(&str, '>', input); + if (err < 0) + return err; + if (!strncmp(str, "confdir:", 8)) { + char *tmp = malloc(strlen(ALSA_CONFIG_DIR) + 1 + strlen(str + 8) + 1); + if (tmp == NULL) { + free(str); + return -ENOMEM; + } + sprintf(tmp, ALSA_CONFIG_DIR "/%s", str + 8); + free(str); + str = tmp; + } + err = snd_input_stdio_open(&in, str, "r"); + if (err < 0) { + SNDERR("Cannot access file %s", str); + free(str); + return err; + } + fd = malloc(sizeof(*fd)); + if (!fd) { + free(str); + return -ENOMEM; + } + fd->name = str; + fd->in = in; + fd->next = input->current; + fd->line = 1; + fd->column = 0; + input->current = fd; + continue; + } + if (c != '#') + break; + while (1) { + c = get_char(input); + if (c < 0) + return c; + if (c == '\n') + break; + } + } + + return c; +} + + +static int get_nonwhite(input_t *input) +{ + int c; + while (1) { + c = get_char_skip_comments(input); + switch (c) { + case ' ': + case '\f': + case '\t': + case '\n': + case '\r': + break; + default: + return c; + } + } +} + +static int get_quotedchar(input_t *input) +{ + int c; + c = get_char(input); + switch (c) { + case 'n': + return '\n'; + case 't': + return '\t'; + case 'v': + return '\v'; + case 'b': + return '\b'; + case 'r': + return '\r'; + case 'f': + return '\f'; + case '0' ... '7': + { + int num = c - '0'; + int i = 1; + do { + c = get_char(input); + if (c < '0' || c > '7') { + unget_char(c, input); + break; + } + num = num * 8 + c - '0'; + i++; + } while (i < 3); + return num; + } + default: + return c; + } +} + +#define LOCAL_STR_BUFSIZE 64 +struct local_string { + char *buf; + size_t alloc; + size_t idx; + char tmpbuf[LOCAL_STR_BUFSIZE]; +}; + +static void init_local_string(struct local_string *s) +{ + memset(s, 0, sizeof(*s)); + s->buf = s->tmpbuf; + s->alloc = LOCAL_STR_BUFSIZE; +} + +static void free_local_string(struct local_string *s) +{ + if (s->buf != s->tmpbuf) + free(s->buf); +} + +static int add_char_local_string(struct local_string *s, int c) +{ + if (s->idx >= s->alloc) { + size_t nalloc = s->alloc * 2; + if (s->buf == s->tmpbuf) { + s->buf = malloc(nalloc); + if (s->buf == NULL) + return -ENOMEM; + memcpy(s->buf, s->tmpbuf, s->alloc); + } else { + char *ptr = realloc(s->buf, nalloc); + if (ptr == NULL) + return -ENOMEM; + s->buf = ptr; + } + s->alloc = nalloc; + } + s->buf[s->idx++] = c; + return 0; +} + +static char *copy_local_string(struct local_string *s) +{ + char *dst = malloc(s->idx + 1); + if (dst) { + memcpy(dst, s->buf, s->idx); + dst[s->idx] = '\0'; + } + return dst; +} + +static int get_freestring(char **string, int id, input_t *input) +{ + struct local_string str; + int c; + + init_local_string(&str); + while (1) { + c = get_char(input); + if (c < 0) { + if (c == LOCAL_UNEXPECTED_EOF) { + *string = copy_local_string(&str); + if (! *string) + c = -ENOMEM; + else + c = 0; + } + break; + } + switch (c) { + case '.': + if (!id) + break; + case ' ': + case '\f': + case '\t': + case '\n': + case '\r': + case '=': + case ',': + case ';': + case '{': + case '}': + case '[': + case ']': + case '\'': + case '"': + case '\\': + case '#': + *string = copy_local_string(&str); + if (! *string) + c = -ENOMEM; + else { + unget_char(c, input); + c = 0; + } + goto _out; + default: + break; + } + if (add_char_local_string(&str, c) < 0) { + c = -ENOMEM; + break; + } + } + _out: + free_local_string(&str); + return c; +} + +static int get_delimstring(char **string, int delim, input_t *input) +{ + struct local_string str; + int c; + + init_local_string(&str); + while (1) { + c = get_char(input); + if (c < 0) + break; + if (c == '\\') { + c = get_quotedchar(input); + if (c < 0) + break; + if (c == '\n') + continue; + } else if (c == delim) { + *string = copy_local_string(&str); + if (! *string) + c = -ENOMEM; + else + c = 0; + break; + } + if (add_char_local_string(&str, c) < 0) { + c = -ENOMEM; + break; + } + } + free_local_string(&str); + return c; +} + +/* Return 0 for free string, 1 for delimited string */ +static int get_string(char **string, int id, input_t *input) +{ + int c = get_nonwhite(input), err; + if (c < 0) + return c; + switch (c) { + case '=': + case ',': + case ';': + case '.': + case '{': + case '}': + case '[': + case ']': + case '\\': + return LOCAL_UNEXPECTED_CHAR; + case '\'': + case '"': + err = get_delimstring(string, c, input); + if (err < 0) + return err; + return 1; + default: + unget_char(c, input); + err = get_freestring(string, id, input); + if (err < 0) + return err; + return 0; + } +} + +static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type) +{ + snd_config_t *n; + assert(config); + n = calloc(1, sizeof(*n)); + if (n == NULL) { + if (*id) { + free(*id); + *id = NULL; + } + return -ENOMEM; + } + if (id) { + n->id = *id; + *id = NULL; + } + n->type = type; + if (type == SND_CONFIG_TYPE_COMPOUND) + INIT_LIST_HEAD(&n->u.compound.fields); + *config = n; + return 0; +} + + +static int _snd_config_make_add(snd_config_t **config, char **id, + snd_config_type_t type, snd_config_t *parent) +{ + snd_config_t *n; + int err; + assert(parent->type == SND_CONFIG_TYPE_COMPOUND); + err = _snd_config_make(&n, id, type); + if (err < 0) + return err; + n->parent = parent; + list_add_tail(&n->list, &parent->u.compound.fields); + *config = n; + return 0; +} + +static int _snd_config_search(snd_config_t *config, + const char *id, int len, snd_config_t **result) +{ + snd_config_iterator_t i, next; + snd_config_for_each(i, next, config) { + snd_config_t *n = snd_config_iterator_entry(i); + if (len < 0) { + if (strcmp(n->id, id) != 0) + continue; + } else if (strlen(n->id) != (size_t) len || + memcmp(n->id, id, (size_t) len) != 0) + continue; + if (result) + *result = n; + return 0; + } + return -ENOENT; +} + +static int parse_value(snd_config_t **_n, snd_config_t *parent, input_t *input, char **id, int skip) +{ + snd_config_t *n = *_n; + char *s; + int err; + + err = get_string(&s, 0, input); + if (err < 0) + return err; + if (skip) { + free(s); + return 0; + } + if (err == 0 && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) { + long long i; + errno = 0; + err = safe_strtoll(s, &i); + if (err < 0) { + double r; + err = safe_strtod(s, &r); + if (err >= 0) { + free(s); + if (n) { + if (n->type != SND_CONFIG_TYPE_REAL) { + SNDERR("%s is not a real", *id); + return -EINVAL; + } + } else { + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, parent); + if (err < 0) + return err; + } + n->u.real = r; + *_n = n; + return 0; + } + } else { + free(s); + if (n) { + if (n->type != SND_CONFIG_TYPE_INTEGER && n->type != SND_CONFIG_TYPE_INTEGER64) { + SNDERR("%s is not an integer", *id); + return -EINVAL; + } + } else { + if (i <= INT_MAX) + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, parent); + else + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, parent); + if (err < 0) + return err; + } + if (n->type == SND_CONFIG_TYPE_INTEGER) + n->u.integer = (long) i; + else + n->u.integer64 = i; + *_n = n; + return 0; + } + } + if (n) { + if (n->type != SND_CONFIG_TYPE_STRING) { + SNDERR("%s is not a string", *id); + free(s); + return -EINVAL; + } + } else { + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, parent); + if (err < 0) + return err; + } + free(n->u.string); + n->u.string = s; + *_n = n; + return 0; +} + +static int parse_defs(snd_config_t *parent, input_t *input, int skip, int override); +static int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override); + +static int parse_array_def(snd_config_t *parent, input_t *input, int idx, int skip, int override) +{ + char *id = NULL; + int c; + int err; + snd_config_t *n = NULL; + + if (!skip) { + char static_id[12]; + snprintf(static_id, sizeof(static_id), "%i", idx); + id = strdup(static_id); + if (id == NULL) + return -ENOMEM; + } + c = get_nonwhite(input); + if (c < 0) { + err = c; + goto __end; + } + switch (c) { + case '{': + case '[': + { + char endchr; + if (!skip) { + if (n) { + if (n->type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("%s is not a compound", id); + err = -EINVAL; + goto __end; + } + } else { + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); + if (err < 0) + goto __end; + } + } + if (c == '{') { + err = parse_defs(n, input, skip, override); + endchr = '}'; + } else { + err = parse_array_defs(n, input, skip, override); + endchr = ']'; + } + c = get_nonwhite(input); + if (c < 0) { + err = c; + goto __end; + } + if (c != endchr) { + if (n) + snd_config_delete(n); + err = LOCAL_UNEXPECTED_CHAR; + goto __end; + } + break; + } + default: + unget_char(c, input); + err = parse_value(&n, parent, input, &id, skip); + if (err < 0) + goto __end; + break; + } + err = 0; + __end: + free(id); + return err; +} + +static int parse_array_defs(snd_config_t *parent, input_t *input, int skip, int override) +{ + int idx = 0; + while (1) { + int c = get_nonwhite(input), err; + if (c < 0) + return c; + unget_char(c, input); + if (c == ']') + return 0; + err = parse_array_def(parent, input, idx++, skip, override); + if (err < 0) + return err; + } + return 0; +} + +static int parse_def(snd_config_t *parent, input_t *input, int skip, int override) +{ + char *id = NULL; + int c; + int err; + snd_config_t *n; + enum {MERGE_CREATE, MERGE, OVERRIDE, DONT_OVERRIDE} mode; + while (1) { + c = get_nonwhite(input); + if (c < 0) + return c; + switch (c) { + case '+': + mode = MERGE_CREATE; + break; + case '-': + mode = MERGE; + break; + case '?': + mode = DONT_OVERRIDE; + break; + case '!': + mode = OVERRIDE; + break; + default: + mode = !override ? MERGE_CREATE : OVERRIDE; + unget_char(c, input); + } + err = get_string(&id, 1, input); + if (err < 0) + return err; + c = get_nonwhite(input); + if (c != '.') + break; + if (skip) { + free(id); + continue; + } + if (_snd_config_search(parent, id, -1, &n) == 0) { + if (mode == DONT_OVERRIDE) { + skip = 1; + free(id); + continue; + } + if (mode != OVERRIDE) { + if (n->type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("%s is not a compound", id); + return -EINVAL; + } + n->u.compound.join = 1; + parent = n; + free(id); + continue; + } + snd_config_delete(n); + } + if (mode == MERGE) { + SNDERR("%s does not exists", id); + err = -ENOENT; + goto __end; + } + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); + if (err < 0) + goto __end; + n->u.compound.join = 1; + parent = n; + } + if (c == '=') { + c = get_nonwhite(input); + if (c < 0) + return c; + } + if (!skip) { + if (_snd_config_search(parent, id, -1, &n) == 0) { + if (mode == DONT_OVERRIDE) { + skip = 1; + n = NULL; + } else if (mode == OVERRIDE) { + snd_config_delete(n); + n = NULL; + } + } else { + n = NULL; + if (mode == MERGE) { + SNDERR("%s does not exists", id); + err = -ENOENT; + goto __end; + } + } + } + switch (c) { + case '{': + case '[': + { + char endchr; + if (!skip) { + if (n) { + if (n->type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("%s is not a compound", id); + err = -EINVAL; + goto __end; + } + } else { + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); + if (err < 0) + goto __end; + } + } + if (c == '{') { + err = parse_defs(n, input, skip, override); + endchr = '}'; + } else { + err = parse_array_defs(n, input, skip, override); + endchr = ']'; + } + c = get_nonwhite(input); + if (c != endchr) { + if (n) + snd_config_delete(n); + err = LOCAL_UNEXPECTED_CHAR; + goto __end; + } + break; + } + default: + unget_char(c, input); + err = parse_value(&n, parent, input, &id, skip); + if (err < 0) + goto __end; + break; + } + c = get_nonwhite(input); + switch (c) { + case ';': + case ',': + break; + default: + unget_char(c, input); + } + __end: + free(id); + return err; +} + +static int parse_defs(snd_config_t *parent, input_t *input, int skip, int override) +{ + int c, err; + while (1) { + c = get_nonwhite(input); + if (c < 0) + return c == LOCAL_UNEXPECTED_EOF ? 0 : c; + unget_char(c, input); + if (c == '}') + return 0; + err = parse_def(parent, input, skip, override); + if (err < 0) + return err; + } + return 0; +} + +static void string_print(char *str, int id, snd_output_t *out) +{ + unsigned char *p = (unsigned char *)str; + if (!p || !*p) { + snd_output_puts(out, "''"); + return; + } + if (!id) { + switch (*p) { + case '0' ... '9': + case '-': + goto quoted; + } + } + loop: + switch (*p) { + case 0: + goto nonquoted; + case 1 ... 31: + case 127 ... 255: + case ' ': + case '=': + case ';': + case ',': + case '.': + case '{': + case '}': + case '\'': + case '"': + goto quoted; + default: + p++; + goto loop; + } + nonquoted: + snd_output_puts(out, str); + return; + quoted: + snd_output_putc(out, '\''); + p = (unsigned char *)str; + while (*p) { + int c; + c = *p; + switch (c) { + case '\n': + snd_output_putc(out, '\\'); + snd_output_putc(out, 'n'); + break; + case '\t': + snd_output_putc(out, '\\'); + snd_output_putc(out, 't'); + break; + case '\v': + snd_output_putc(out, '\\'); + snd_output_putc(out, 'v'); + break; + case '\b': + snd_output_putc(out, '\\'); + snd_output_putc(out, 'b'); + break; + case '\r': + snd_output_putc(out, '\\'); + snd_output_putc(out, 'r'); + break; + case '\f': + snd_output_putc(out, '\\'); + snd_output_putc(out, 'f'); + break; + case '\'': + snd_output_putc(out, '\\'); + snd_output_putc(out, c); + break; + case 32 ... '\'' - 1: + case '\'' + 1 ... 126: + snd_output_putc(out, c); + break; + default: + snd_output_printf(out, "\\%04o", c); + break; + } + p++; + } + snd_output_putc(out, '\''); +} + +static int _snd_config_save_children(snd_config_t *config, snd_output_t *out, + unsigned int level, unsigned int joins); + +static int _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, + unsigned int level) +{ + int err; + unsigned int k; + switch (n->type) { + case SND_CONFIG_TYPE_INTEGER: + snd_output_printf(out, "%ld", n->u.integer); + break; + case SND_CONFIG_TYPE_INTEGER64: + snd_output_printf(out, "%Ld", n->u.integer64); + break; + case SND_CONFIG_TYPE_REAL: + snd_output_printf(out, "%-16g", n->u.real); + break; + case SND_CONFIG_TYPE_STRING: + string_print(n->u.string, 0, out); + break; + case SND_CONFIG_TYPE_POINTER: + SNDERR("cannot save runtime pointer type"); + return -EINVAL; + case SND_CONFIG_TYPE_COMPOUND: + snd_output_putc(out, '{'); + snd_output_putc(out, '\n'); + err = _snd_config_save_children(n, out, level + 1, 0); + if (err < 0) + return err; + for (k = 0; k < level; ++k) { + snd_output_putc(out, '\t'); + } + snd_output_putc(out, '}'); + break; + } + return 0; +} + +static void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins) +{ + if (joins > 0) { + assert(n->parent); + id_print(n->parent, out, joins - 1); + snd_output_putc(out, '.'); + } + string_print(n->id, 1, out); +} + +static int _snd_config_save_children(snd_config_t *config, snd_output_t *out, + unsigned int level, unsigned int joins) +{ + unsigned int k; + int err; + snd_config_iterator_t i, next; + assert(config && out); + snd_config_for_each(i, next, config) { + snd_config_t *n = snd_config_iterator_entry(i); + if (n->type == SND_CONFIG_TYPE_COMPOUND && + n->u.compound.join) { + err = _snd_config_save_children(n, out, level, joins + 1); + if (err < 0) + return err; + continue; + } + for (k = 0; k < level; ++k) { + snd_output_putc(out, '\t'); + } + id_print(n, out, joins); +#if 0 + snd_output_putc(out, ' '); + snd_output_putc(out, '='); +#endif + snd_output_putc(out, ' '); + err = _snd_config_save_node_value(n, out, level); + if (err < 0) + return err; +#if 0 + snd_output_putc(out, ';'); +#endif + snd_output_putc(out, '\n'); + } + return 0; +} +#endif + + +/** + * \brief Substitutes one configuration node to another. + * \param dst Handle to the destination node. + * \param src Handle to the source node. Must not be the same as \a dst. + * \return Zero if successful, otherwise a negative error code. + * + * If both nodes are compounds, the source compound node members are + * appended to the destination compound node. + * + * If the destination node is a compound and the source node is + * an ordinary type, the compound members are deleted (including + * their contents). + * + * Otherwise, the source node's value replaces the destination node's + * value. + * + * In any case, a successful call to this function frees the source + * node. + */ +int snd_config_substitute(snd_config_t *dst, snd_config_t *src) +{ + assert(dst && src); + if (dst->type == SND_CONFIG_TYPE_COMPOUND && + src->type == SND_CONFIG_TYPE_COMPOUND) { /* append */ + snd_config_iterator_t i, next; + snd_config_for_each(i, next, src) { + snd_config_t *n = snd_config_iterator_entry(i); + n->parent = dst; + } + src->u.compound.fields.next->prev = &dst->u.compound.fields; + src->u.compound.fields.prev->next = &dst->u.compound.fields; + } else if (dst->type == SND_CONFIG_TYPE_COMPOUND) { + int err; + err = snd_config_delete_compound_members(dst); + if (err < 0) + return err; + } + free(dst->id); + dst->id = src->id; + dst->type = src->type; + dst->u = src->u; + free(src); + return 0; +} + +/** + * \brief Converts an ASCII string to a configuration node type. + * \param[in] ascii A string containing a configuration node type. + * \param[out] type The node type corresponding to \a ascii. + * \return Zero if successful, otherwise a negative error code. + * + * This function recognizes at least the following node types: + *
+ *
integer
#SND_CONFIG_TYPE_INTEGER + *
integer64
#SND_CONFIG_TYPE_INTEGER64 + *
real
#SND_CONFIG_TYPE_REAL + *
string
#SND_CONFIG_TYPE_STRING + *
compound
#SND_CONFIG_TYPE_COMPOUND + *
+ * + * \par Errors: + *
+ *
-EINVAL
Unknown note type in \a type. + *
+ */ +int snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type) +{ + assert(ascii && type); + if (!strcmp(ascii, "integer")) { + *type = SND_CONFIG_TYPE_INTEGER; + return 0; + } + if (!strcmp(ascii, "integer64")) { + *type = SND_CONFIG_TYPE_INTEGER64; + return 0; + } + if (!strcmp(ascii, "real")) { + *type = SND_CONFIG_TYPE_REAL; + return 0; + } + if (!strcmp(ascii, "string")) { + *type = SND_CONFIG_TYPE_STRING; + return 0; + } + if (!strcmp(ascii, "compound")) { + *type = SND_CONFIG_TYPE_COMPOUND; + return 0; + } + return -EINVAL; +} + +/** + * \brief Returns the type of a configuration node. + * \param config Handle to the configuration node. + * \return The node's type. + * + * \par Conforming to: + * LSB 3.2 + */ +snd_config_type_t snd_config_get_type(const snd_config_t *config) +{ + return config->type; +} + +/** + * \brief Returns the id of a configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] id The function puts the pointer to the id string at the + * address specified by \a id. + * \return Zero if successful, otherwise a negative error code. + * + * The returned string is owned by the configuration node; the application + * must not modify or delete it, and the string becomes invalid when the + * node's id changes or when the node is freed. + * + * If the node does not have an id, \a *id is set to \c NULL. + * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_get_id(const snd_config_t *config, const char **id) +{ + assert(config && id); + *id = config->id; + return 0; +} + +/** + * \brief Sets the id of a configuration node. + * \param config Handle to the configuration node. + * \param id The new node id, must not be \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This function stores a copy of \a id in the node. + * + * \par Errors: + *
+ *
-EEXIST
One of \a config's siblings already has the id \a id. + *
-EINVAL
The id of a node with a parent cannot be set to \c NULL. + *
-ENOMEM
Out of memory. + *
+ */ +int snd_config_set_id(snd_config_t *config, const char *id) +{ + snd_config_iterator_t i, next; + char *new_id; + assert(config); + if (id) { + if (config->parent) { + snd_config_for_each(i, next, config->parent) { + snd_config_t *n = snd_config_iterator_entry(i); + if (n != config && strcmp(id, n->id) == 0) + return -EEXIST; + } + } + new_id = strdup(id); + if (!new_id) + return -ENOMEM; + } else { + if (config->parent) + return -EINVAL; + new_id = NULL; + } + free(config->id); + config->id = new_id; + return 0; +} + +/** + * \brief Creates a top level configuration node. + * \param[out] config Handle to the new node. + * \return Zero if successful, otherwise a negative error code. + * + * The returned node is an empty compound node without a parent and + * without an id. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_top(snd_config_t **config) +{ + assert(config); + return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND); +} + +static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override) +{ + int err; + input_t input; + struct filedesc *fd, *fd_next; + assert(config && in); + fd = malloc(sizeof(*fd)); + if (!fd) + return -ENOMEM; + fd->name = NULL; + fd->in = in; + fd->line = 1; + fd->column = 0; + fd->next = NULL; + input.current = fd; + input.unget = 0; + err = parse_defs(config, &input, 0, override); + fd = input.current; + if (err < 0) { + const char *str; + switch (err) { + case LOCAL_UNTERMINATED_STRING: + str = "Unterminated string"; + err = -EINVAL; + break; + case LOCAL_UNTERMINATED_QUOTE: + str = "Unterminated quote"; + err = -EINVAL; + break; + case LOCAL_UNEXPECTED_CHAR: + str = "Unexpected char"; + err = -EINVAL; + break; + case LOCAL_UNEXPECTED_EOF: + str = "Unexpected end of file"; + err = -EINVAL; + break; + default: + str = strerror(-err); + break; + } + SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str); + goto _end; + } + if (get_char(&input) != LOCAL_UNEXPECTED_EOF) { + SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column); + err = -EINVAL; + goto _end; + } + _end: + while (fd->next) { + fd_next = fd->next; + snd_input_close(fd->in); + free(fd->name); + free(fd); + fd = fd_next; + } + free(fd); + return err; +} + +/** + * \brief Loads a configuration tree. + * \param config Handle to a top level configuration node. + * \param in Input handle to read the configuration from. + * \return Zero if successful, otherwise a negative error code. + * + * The definitions loaded from the input are added to \a config, which + * must be a compound node. + * + * \par Errors: + * Any errors encountered when parsing the input or returned by hooks or + * functions. + * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_load(snd_config_t *config, snd_input_t *in) +{ + return snd_config_load1(config, in, 0); +} + +/** + * \brief Loads a configuration tree and overrides existing configuration nodes. + * \param config Handle to a top level configuration node. + * \param in Input handle to read the configuration from. + * \return Zero if successful, otherwise a negative error code. + * + * This function loads definitions from \a in into \a config like + * #snd_config_load, but the default mode for input nodes is 'override' + * (!) instead of 'merge+create' (+). + */ +int snd_config_load_override(snd_config_t *config, snd_input_t *in) +{ + return snd_config_load1(config, in, 1); +} + +/** + * \brief Adds a child to a compound configuration node. + * \param parent Handle to a compound configuration node. + * \param child Handle to the configuration node to be added. + * \return Zero if successful, otherwise a negative error code. + * + * This function makes the node \a child a child of the node \a parent. + * + * The parent node then owns the child node, i.e., the child node gets + * deleted together with its parent. + * + * \a child must have an id. + * + * \par Errors: + *
+ *
-EINVAL
\a child does not have an id. + *
-EINVAL
\a child already has a parent. + *
-EEXIST
\a parent already contains a child node with the same + * id as \a child. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_add(snd_config_t *parent, snd_config_t *child) +{ + snd_config_iterator_t i, next; + assert(parent && child); + if (!child->id || child->parent) + return -EINVAL; + snd_config_for_each(i, next, parent) { + snd_config_t *n = snd_config_iterator_entry(i); + if (strcmp(child->id, n->id) == 0) + return -EEXIST; + } + child->parent = parent; + list_add_tail(&child->list, &parent->u.compound.fields); + return 0; +} + +/** + * \brief Removes a configuration node from its tree. + * \param config Handle to the configuration node to be removed. + * \return Zero if successful, otherwise a negative error code. + * + * This function makes \a config a top-level node, i.e., if \a config + * has a parent, then \a config is removed from the list of the parent's + * children. + * + * This functions does \e not free the removed node. + * + * \sa snd_config_delete + */ +int snd_config_remove(snd_config_t *config) +{ + assert(config); + if (config->parent) + list_del(&config->list); + config->parent = NULL; + return 0; +} + +/** + * \brief Frees a configuration node. + * \param config Handle to the configuration node to be deleted. + * \return Zero if successful, otherwise a negative error code. + * + * This function frees a configuration node and all its resources. + * + * If the node is a child node, it is removed from the tree before being + * deleted. + * + * If the node is a compound node, its descendants (the whole subtree) + * are deleted recursively. + * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_config_remove + */ +int snd_config_delete(snd_config_t *config) +{ + assert(config); + switch (config->type) { + case SND_CONFIG_TYPE_COMPOUND: + { + int err; + struct list_head *i; + i = config->u.compound.fields.next; + while (i != &config->u.compound.fields) { + struct list_head *nexti = i->next; + snd_config_t *child = snd_config_iterator_entry(i); + err = snd_config_delete(child); + if (err < 0) + return err; + i = nexti; + } + break; + } + case SND_CONFIG_TYPE_STRING: + free(config->u.string); + break; + default: + break; + } + if (config->parent) + list_del(&config->list); + free(config->id); + free(config); + return 0; +} + +/** + * \brief Deletes the children of a node. + * \param config Handle to the compound configuration node. + * \return Zero if successful, otherwise a negative error code. + * + * This function removes and frees all children of a configuration node. + * + * Any compound nodes among the children of \a config are deleted + * recursively. + * + * After a successful call to this function, \a config is an empty + * compound node. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a compound node. + *
+ */ +int snd_config_delete_compound_members(const snd_config_t *config) +{ + int err; + struct list_head *i; + + assert(config); + if (config->type != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + i = config->u.compound.fields.next; + while (i != &config->u.compound.fields) { + struct list_head *nexti = i->next; + snd_config_t *child = snd_config_iterator_entry(i); + err = snd_config_delete(child); + if (err < 0) + return err; + i = nexti; + } + return 0; +} + +/** + * \brief Creates a configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] type The type of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This functions creates a new node of the specified type. + * The new node has id \a id, which may be \c NULL. + * + * The value of the new node is zero (for numbers), or \c NULL (for + * strings and pointers), or empty (for compound nodes). + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ */ +int snd_config_make(snd_config_t **config, const char *id, + snd_config_type_t type) +{ + char *id1; + assert(config); + if (id) { + id1 = strdup(id); + if (!id1) + return -ENOMEM; + } else + id1 = NULL; + return _snd_config_make(config, &id1, type); +} + +/** + * \brief Creates an integer configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and + * with value \c 0. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_config_imake_integer + */ +int snd_config_make_integer(snd_config_t **config, const char *id) +{ + return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER); +} + +/** + * \brief Creates a 64-bit-integer configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64 + * and with value \c 0. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_config_imake_integer64 + */ +int snd_config_make_integer64(snd_config_t **config, const char *id) +{ + return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64); +} + +/** + * \brief Creates a real number configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_REAL and + * with value \c 0.0. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \sa snd_config_imake_real + */ +int snd_config_make_real(snd_config_t **config, const char *id) +{ + return snd_config_make(config, id, SND_CONFIG_TYPE_REAL); +} + +/** + * \brief Creates a string configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_STRING and + * with value \c NULL. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_config_imake_string + */ +int snd_config_make_string(snd_config_t **config, const char *id) +{ + return snd_config_make(config, id, SND_CONFIG_TYPE_STRING); +} + +/** + * \brief Creates a pointer configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and + * with value \c NULL. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \sa snd_config_imake_pointer + */ +int snd_config_make_pointer(snd_config_t **config, const char *id) +{ + return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER); +} + +/** + * \brief Creates an empty compound configuration node. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] join Join flag. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new empty node of type + * #SND_CONFIG_TYPE_COMPOUND. + * + * \a join determines how the compound node's id is printed when the + * configuration is saved to a text file. For example, if the join flag + * of compound node \c a is zero, the output will look as follows: + * \code + * a { + * b "hello" + * c 42 + * } + * \endcode + * If, however, the join flag of \c a is nonzero, its id will be joined + * with its children's ids, like this: + * \code + * a.b "hello" + * a.c 42 + * \endcode + * An \e empty compound node with its join flag set would result in no + * output, i.e., after saving and reloading the configuration file, that + * compound node would be lost. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_make_compound(snd_config_t **config, const char *id, + int join) +{ + int err; + err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND); + if (err < 0) + return err; + (*config)->u.compound.join = join; + return 0; +} + +/** + * \brief Creates an integer configuration node with the given initial value. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] value The initial value of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and + * with value \a value. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_imake_integer(snd_config_t **config, const char *id, const long value) +{ + int err; + + err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER); + if (err < 0) + return err; + (*config)->u.integer = value; + return 0; +} + +/** + * \brief Creates a 64-bit-integer configuration node with the given initial value. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] value The initial value of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64 + * and with value \a value. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_imake_integer64(snd_config_t **config, const char *id, const long long value) +{ + int err; + + err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64); + if (err < 0) + return err; + (*config)->u.integer64 = value; + return 0; +} + +/** + * \brief Creates a real number configuration node with the given initial value. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] value The initial value of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_REAL and + * with value \a value. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ */ +int snd_config_imake_real(snd_config_t **config, const char *id, const double value) +{ + int err; + + err = snd_config_make(config, id, SND_CONFIG_TYPE_REAL); + if (err < 0) + return err; + (*config)->u.real = value; + return 0; +} + +/** + * \brief Creates a string configuration node with the given initial value. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] value The initial value of the new node. May be \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_STRING and + * with a copy of the string \c value. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_imake_string(snd_config_t **config, const char *id, const char *value) +{ + int err; + snd_config_t *tmp; + + err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING); + if (err < 0) + return err; + if (value) { + tmp->u.string = strdup(value); + if (!tmp->u.string) { + snd_config_delete(tmp); + return -ENOMEM; + } + } else { + tmp->u.string = NULL; + } + *config = tmp; + return 0; +} + +/** + * \brief Creates a pointer configuration node with the given initial value. + * \param[out] config The function puts the handle to the new node at + * the address specified by \a config. + * \param[in] id The id of the new node. + * \param[in] value The initial value of the new node. + * \return Zero if successful, otherwise a negative error code. + * + * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and + * with value \c value. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ */ +int snd_config_imake_pointer(snd_config_t **config, const char *id, const void *value) +{ + int err; + + err = snd_config_make(config, id, SND_CONFIG_TYPE_POINTER); + if (err < 0) + return err; + (*config)->u.ptr = value; + return 0; +} + +/** + * \brief Changes the value of an integer configuration node. + * \param config Handle to the configuration node. + * \param value The new value for the node. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not an integer node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_set_integer(snd_config_t *config, long value) +{ + assert(config); + if (config->type != SND_CONFIG_TYPE_INTEGER) + return -EINVAL; + config->u.integer = value; + return 0; +} + +/** + * \brief Changes the value of a 64-bit-integer configuration node. + * \param config Handle to the configuration node. + * \param value The new value for the node. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a 64-bit-integer node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_set_integer64(snd_config_t *config, long long value) +{ + assert(config); + if (config->type != SND_CONFIG_TYPE_INTEGER64) + return -EINVAL; + config->u.integer64 = value; + return 0; +} + +/** + * \brief Changes the value of a real-number configuration node. + * \param config Handle to the configuration node. + * \param value The new value for the node. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a real-number node. + *
+ */ +int snd_config_set_real(snd_config_t *config, double value) +{ + assert(config); + if (config->type != SND_CONFIG_TYPE_REAL) + return -EINVAL; + config->u.real = value; + return 0; +} + +/** + * \brief Changes the value of a string configuration node. + * \param config Handle to the configuration node. + * \param value The new value for the node. May be \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This function deletes the old string in the node and stores a copy of + * \a value string in the node. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a string node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_set_string(snd_config_t *config, const char *value) +{ + char *new_string; + assert(config); + if (config->type != SND_CONFIG_TYPE_STRING) + return -EINVAL; + if (value) { + new_string = strdup(value); + if (!new_string) + return -ENOMEM; + } else { + new_string = NULL; + } + free(config->u.string); + config->u.string = new_string; + return 0; +} + +/** + * \brief Changes the value of a pointer configuration node. + * \param config Handle to the configuration node. + * \param value The new value for the node. May be \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This function does not free the old pointer in the node. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a pointer node. + *
+ */ +int snd_config_set_pointer(snd_config_t *config, const void *value) +{ + assert(config); + if (config->type != SND_CONFIG_TYPE_POINTER) + return -EINVAL; + config->u.ptr = value; + return 0; +} + +/** + * \brief Changes the value of a configuration node. + * \param config Handle to the configuration node. + * \param ascii The new value for the node, as an ASCII string. + * \return Zero if successful, otherwise a negative error code. + * + * This function changes the node's value to a new value that is parsed + * from the string \a ascii. \a ascii must not be \c NULL, not even for + * a string node. + * + * The node's type does not change, i.e., the string must contain a + * valid value with the same type as the node's type. For a string + * node, the node's new value is a copy of \a ascii. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a number or string node. + *
-EINVAL
The value in \a ascii cannot be parsed. + *
-ERANGE
The value in \a ascii is too big for the node's type. + *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_set_ascii(snd_config_t *config, const char *ascii) +{ + assert(config && ascii); + switch (config->type) { + case SND_CONFIG_TYPE_INTEGER: + { + long i; + int err = safe_strtol(ascii, &i); + if (err < 0) + return err; + config->u.integer = i; + } + break; + case SND_CONFIG_TYPE_INTEGER64: + { + long long i; + int err = safe_strtoll(ascii, &i); + if (err < 0) + return err; + config->u.integer64 = i; + } + break; + case SND_CONFIG_TYPE_REAL: + { + double d; + int err = safe_strtod(ascii, &d); + if (err < 0) + return err; + config->u.real = d; + break; + } + case SND_CONFIG_TYPE_STRING: + { + char *ptr = strdup(ascii); + if (ptr == NULL) + return -ENOMEM; + free(config->u.string); + config->u.string = ptr; + } + break; + default: + return -EINVAL; + } + return 0; +} + +/** + * \brief Returns the value of an integer configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] ptr The node's value. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not an integer node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_get_integer(const snd_config_t *config, long *ptr) +{ + assert(config && ptr); + if (config->type != SND_CONFIG_TYPE_INTEGER) + return -EINVAL; + *ptr = config->u.integer; + return 0; +} + +/** + * \brief Returns the value of a 64-bit-integer configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] ptr The node's value. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a 64-bit-integer node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_get_integer64(const snd_config_t *config, long long *ptr) +{ + assert(config && ptr); + if (config->type != SND_CONFIG_TYPE_INTEGER64) + return -EINVAL; + *ptr = config->u.integer64; + return 0; +} + +/** + * \brief Returns the value of a real-number configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] ptr The node's value. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a real-number node. + *
+ */ +int snd_config_get_real(const snd_config_t *config, double *ptr) +{ + assert(config && ptr); + if (config->type != SND_CONFIG_TYPE_REAL) + return -EINVAL; + *ptr = config->u.real; + return 0; +} + +/** + * \brief Returns the value of a real or integer configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] ptr The node's value. + * \return Zero if successful, otherwise a negative error code. + * + * If the node's type is integer or integer64, the value is converted + * to the \c double type on the fly. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a number node. + *
+ */ +int snd_config_get_ireal(const snd_config_t *config, double *ptr) +{ + assert(config && ptr); + if (config->type == SND_CONFIG_TYPE_REAL) + *ptr = config->u.real; + else if (config->type == SND_CONFIG_TYPE_INTEGER) + *ptr = config->u.integer; + else if (config->type == SND_CONFIG_TYPE_INTEGER64) + *ptr = config->u.integer64; + else + return -EINVAL; + return 0; +} + +/** + * \brief Returns the value of a string configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] ptr The function puts the node's value at the address + * specified by \a ptr. + * \return Zero if successful, otherwise a negative error code. + * + * The returned string is owned by the configuration node; the + * application must not modify or delete it, and the string becomes + * invalid when the node's value changes or when the node is freed. + * + * The string may be \c NULL. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a string node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_get_string(const snd_config_t *config, const char **ptr) +{ + assert(config && ptr); + if (config->type != SND_CONFIG_TYPE_STRING) + return -EINVAL; + *ptr = config->u.string; + return 0; +} + +/** + * \brief Returns the value of a pointer configuration node. + * \param[in] config Handle to the configuration node. + * \param[out] ptr The function puts the node's value at the address + * specified by \a ptr. + * \return Zero if successful, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a string node. + *
+ */ +int snd_config_get_pointer(const snd_config_t *config, const void **ptr) +{ + assert(config && ptr); + if (config->type != SND_CONFIG_TYPE_POINTER) + return -EINVAL; + *ptr = config->u.ptr; + return 0; +} + +/** + * \brief Returns the value of a configuration node as a string. + * \param[in] config Handle to the configuration node. + * \param[out] ascii The function puts the pointer to the returned + * string at the address specified by \a ascii. + * \return Zero if successful, otherwise a negative error code. + * + * This function dynamically allocates the returned string. The + * application is responsible for deleting it with \c free() when it is + * no longer used. + * + * For a string node with \c NULL value, the returned string is \c NULL. + * + * Supported node types are #SND_CONFIG_TYPE_INTEGER, + * #SND_CONFIG_TYPE_INTEGER64, #SND_CONFIG_TYPE_REAL, and + * #SND_CONFIG_TYPE_STRING. + * + * \par Errors: + *
+ *
-EINVAL
\a config is not a (64-bit) integer or real number or + * string node. + *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_get_ascii(const snd_config_t *config, char **ascii) +{ + assert(config && ascii); + switch (config->type) { + case SND_CONFIG_TYPE_INTEGER: + { + char res[12]; + int err; + err = snprintf(res, sizeof(res), "%li", config->u.integer); + if (err < 0 || err == sizeof(res)) { + assert(0); + return -ENOMEM; + } + *ascii = strdup(res); + } + break; + case SND_CONFIG_TYPE_INTEGER64: + { + char res[32]; + int err; + err = snprintf(res, sizeof(res), "%Li", config->u.integer64); + if (err < 0 || err == sizeof(res)) { + assert(0); + return -ENOMEM; + } + *ascii = strdup(res); + } + break; + case SND_CONFIG_TYPE_REAL: + { + char res[32]; + int err; + err = snprintf(res, sizeof(res), "%-16g", config->u.real); + if (err < 0 || err == sizeof(res)) { + assert(0); + return -ENOMEM; + } + if (res[0]) { /* trim the string */ + char *ptr; + ptr = res + strlen(res) - 1; + while (ptr != res && *ptr == ' ') + ptr--; + if (*ptr != ' ') + ptr++; + *ptr = '\0'; + } + *ascii = strdup(res); + } + break; + case SND_CONFIG_TYPE_STRING: + if (config->u.string) + *ascii = strdup(config->u.string); + else { + *ascii = NULL; + return 0; + } + break; + default: + return -EINVAL; + } + if (*ascii == NULL) + return -ENOMEM; + return 0; +} + +/** + * \brief Compares the id of a configuration node to a given string. + * \param config Handle to the configuration node. + * \param id ASCII id. + * \return The same value as the result of the \c strcmp function, i.e., + * less than zero if \a config's id is lexicographically less + * than \a id, zero if \a config's id is equal to id, greater + * than zero otherwise. + */ +int snd_config_test_id(const snd_config_t *config, const char *id) +{ + assert(config && id); + if (config->id) + return strcmp(config->id, id); + else + return -1; +} + +/** + * \brief Dumps the contents of a configuration node or tree. + * \param config Handle to the (root) configuration node. + * \param out Output handle. + * \return Zero if successful, otherwise a negative error code. + * + * This function writes a textual representation of \a config's value to + * the output \a out. + * + * \par Errors: + *
+ *
-EINVAL
A node in the tree has a type that cannot be printed, + * i.e., #SND_CONFIG_TYPE_POINTER. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_save(snd_config_t *config, snd_output_t *out) +{ + assert(config && out); + if (config->type == SND_CONFIG_TYPE_COMPOUND) + return _snd_config_save_children(config, out, 0, 0); + else + return _snd_config_save_node_value(config, out, 0); +} + +/* + * *** search macros *** + */ + +#ifndef DOC_HIDDEN + +#define SND_CONFIG_SEARCH(config, key, result, extra_code) \ +{ \ + snd_config_t *n; \ + int err; \ + const char *p; \ + assert(config && key); \ + while (1) { \ + if (config->type != SND_CONFIG_TYPE_COMPOUND) \ + return -ENOENT; \ + { extra_code ; } \ + p = strchr(key, '.'); \ + if (p) { \ + err = _snd_config_search(config, key, p - key, &n); \ + if (err < 0) \ + return err; \ + config = n; \ + key = p + 1; \ + } else \ + return _snd_config_search(config, key, -1, result); \ + } \ +} + +#define SND_CONFIG_SEARCHA(root, config, key, result, fcn, extra_code) \ +{ \ + snd_config_t *n; \ + int err; \ + const char *p; \ + assert(config && key); \ + while (1) { \ + if (config->type != SND_CONFIG_TYPE_COMPOUND) { \ + if (snd_config_get_string(config, &p) < 0) \ + return -ENOENT; \ + err = fcn(root, root, p, &config); \ + if (err < 0) \ + return err; \ + } \ + { extra_code ; } \ + p = strchr(key, '.'); \ + if (p) { \ + err = _snd_config_search(config, key, p - key, &n); \ + if (err < 0) \ + return err; \ + config = n; \ + key = p + 1; \ + } else \ + return _snd_config_search(config, key, -1, result); \ + } \ +} + +#define SND_CONFIG_SEARCHV(config, result, fcn) \ +{ \ + snd_config_t *n; \ + va_list arg; \ + assert(config); \ + va_start(arg, result); \ + while (1) { \ + const char *k = va_arg(arg, const char *); \ + int err; \ + if (!k) \ + break; \ + err = fcn(config, k, &n); \ + if (err < 0) \ + return err; \ + config = n; \ + } \ + va_end(arg); \ + if (result) \ + *result = n; \ + return 0; \ +} + +#define SND_CONFIG_SEARCHVA(root, config, result, fcn) \ +{ \ + snd_config_t *n; \ + va_list arg; \ + assert(config); \ + va_start(arg, result); \ + while (1) { \ + const char *k = va_arg(arg, const char *); \ + int err; \ + if (!k) \ + break; \ + err = fcn(root, config, k, &n); \ + if (err < 0) \ + return err; \ + config = n; \ + } \ + va_end(arg); \ + if (result) \ + *result = n; \ + return 0; \ +} + +#define SND_CONFIG_SEARCH_ALIAS(config, base, key, result, fcn1, fcn2) \ +{ \ + snd_config_t *res = NULL; \ + char *old_key; \ + int err, first = 1, maxloop = 1000; \ + assert(config && key); \ + while (1) { \ + old_key = strdup(key); \ + if (old_key == NULL) { \ + err = -ENOMEM; \ + res = NULL; \ + break; \ + } \ + err = first && base ? -EIO : fcn1(config, config, key, &res); \ + if (err < 0) { \ + if (!base) \ + break; \ + err = fcn2(config, config, &res, base, key, NULL); \ + if (err < 0) \ + break; \ + } \ + if (snd_config_get_string(res, &key) < 0) \ + break; \ + assert(key); \ + if (!first && (strcmp(key, old_key) == 0 || maxloop <= 0)) { \ + if (maxloop == 0) \ + SNDERR("maximum loop count reached (circular configuration?)"); \ + else \ + SNDERR("key %s refers to itself", key); \ + err = -EINVAL; \ + res = NULL; \ + break; \ + } \ + free(old_key); \ + first = 0; \ + maxloop--; \ + } \ + free(old_key); \ + if (!res) \ + return err; \ + if (result) \ + *result = res; \ + return 0; \ +} + +#endif /* DOC_HIDDEN */ + +/** + * \brief Searches for a node in a configuration tree. + * \param[in] config Handle to the root of the configuration (sub)tree to search. + * \param[in] key Search key: one or more node ids, separated with dots. + * \param[out] result When \a result != \c NULL, the function puts the + * handle to the node found at the address specified + * by \a result. + * \return Zero if successful, otherwise a negative error code. + * + * This function searches for a child node of \a config that is + * identified by \a key, which contains either the id of a direct child + * node of \a config, or a series of ids, separated with dots, where + * each id specifies a node that is contained in the previous compound + * node. + * + * In the following example, the comment after each node shows the + * search key to find that node, assuming that \a config is a handle to + * the compound node with id \c config: + * \code + * config { + * a 42 # "a" + * b { # "b" + * c "cee" # "b.c" + * d { # "b.d" + * e 2.71828 # "b.d.e" + * } + * } + * } + * \endcode + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_search(snd_config_t *config, const char *key, snd_config_t **result) +{ + SND_CONFIG_SEARCH(config, key, result, ); +} + +/** + * \brief Searches for a node in a configuration tree, expanding aliases. + * \param[in] root Handle to the root configuration node containing + * alias definitions. + * \param[in] config Handle to the root of the configuration (sub)tree to search. + * \param[in] key Search key: one or more node keys, separated with dots. + * \param[out] result When \a result != \c NULL, the function puts the + * handle to the node found at the address specified + * by \a result. + * \return Zero if successful, otherwise a negative error code. + * + * This functions searches for a child node of \a config like + * #snd_config_search. However, any compound node can also be + * identified by an alias, which is a string node whose value is taken + * as the id of a compound node below \a root. + * + * \a root must be a compound node. + * \a root and \a config may be the same node. + * + * For example, with the following configuration, the call + * \code + * snd_config_searcha(root, config, "a.b.c.d", &result); + * \endcode + * would return the node with id \c d: + * \code + * config { + * a { + * b bb + * } + * } + * root { + * bb { + * c cc + * } + * cc ccc + * ccc { + * d { + * x "icks" + * } + * } + * } + * \endcode + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key or an alias id does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound or string node. + *
+ */ +int snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result) +{ + SND_CONFIG_SEARCHA(root, config, key, result, snd_config_searcha, ); +} + +/** + * \brief Searches for a node in a configuration tree. + * \param[in] config Handle to the root of the configuration (sub)tree to search. + * \param[out] result When \a result != \c NULL, the function puts the + * handle to the node found at the address specified + * by \a result. + * \param[in] ... One or more concatenated dot-separated search keys, + * terminated with \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This functions searches for a child node of \a config like + * #snd_config_search, but the search key is the concatenation of all + * passed search key strings. For example, the call + * \code + * snd_config_searchv(cfg, &res, "a", "b.c", "d.e", NULL); + * \endcode + * is equivalent to the call + * \code + * snd_config_search(cfg, "a.b.c.d.e", &res); + * \endcode + * + * \par Errors: + *
+ *
-ENOENT
An id in a search key does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_searchv(snd_config_t *config, snd_config_t **result, ...) +{ + SND_CONFIG_SEARCHV(config, result, snd_config_search); +} + +/** + * \brief Searches for a node in a configuration tree, expanding aliases. + * \param[in] root Handle to the root configuration node containing + * alias definitions. + * \param[in] config Handle to the root of the configuration (sub)tree to search. + * \param[out] result When \a result != \c NULL, the function puts the + * handle to the node found at the address specified + * by \a result. + * \param[in] ... One or more concatenated dot separated search keys, + * terminated with \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This function searches for a child node of \a config, allowing + * aliases, like #snd_config_searcha, but the search key is the + * concatenation of all passed seach key strings, like with + * #snd_config_searchv. + * + * \par Errors: + *
+ *
-ENOENT
An id in a search key does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound or string node. + *
+ */ +int snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t **result, ...) +{ + SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha); +} + +/** + * \brief Searches for a node in a configuration tree, expanding aliases. + * \param[in] config Handle to the root of the configuration (sub)tree to search. + * \param[in] base Search key base, or \c NULL. + * \param[in] key Search key suffix. + * \param[out] result When \a result != \c NULL, the function puts the + * handle to the node found at the address specified + * by \a result. + * \return Zero if successful, otherwise a negative error code. + * + * This functions searches for a child node of \a config, allowing + * aliases, like #snd_config_searcha. However, alias definitions are + * searched below \a config (there is no separate \a root parameter), + * and \a base specifies a seach key that identifies a compound node + * that is used to search for an alias definitions that is not found + * directly below \a config and that does not contain a period. In + * other words, when \c "id" is not found in \a config, this function + * also tries \c "base.id". + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key or an alias id does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound or string node. + *
+ */ +int snd_config_search_alias(snd_config_t *config, + const char *base, const char *key, + snd_config_t **result) +{ + SND_CONFIG_SEARCH_ALIAS(config, base, key, result, + snd_config_searcha, snd_config_searchva); +} + +static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data); + +/** + * \brief Searches for a node in a configuration tree and expands hooks. + * \param[in,out] config Handle to the root of the configuration + * (sub)tree to search. + * \param[in] key Search key: one or more node keys, separated with dots. + * \param[out] result The function puts the handle to the node found at + * the address specified by \a result. + * \return Zero if successful, otherwise a negative error code. + * + * This functions searches for a child node of \a config like + * #snd_config_search, but any compound nodes to be searched that + * contain hooks are modified by the respective hook functions. + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * Additionally, any errors encountered when parsing the hook + * definitions or returned by the hook functions. + */ +int snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result) +{ + SND_CONFIG_SEARCH(config, key, result, \ + err = snd_config_hooks(config, NULL); \ + if (err < 0) \ + return err; \ + ); +} + +/** + * \brief Searches for a node in a configuration tree, expanding aliases and hooks. + * \param[in] root Handle to the root configuration node containing + * alias definitions. + * \param[in,out] config Handle to the root of the configuration + * (sub)tree to search. + * \param[in] key Search key: one or more node keys, separated with dots. + * \param[out] result The function puts the handle to the node found at + * the address specified by \a result. + * \return Zero if successful, otherwise a negative error code. + * + * This function searches for a child node of \a config, allowing + * aliases, like #snd_config_searcha, and expanding hooks, like + * #snd_config_search_hooks. + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key or an alias id does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * Additionally, any errors encountered when parsing the hook + * definitions or returned by the hook functions. + */ +int snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result) +{ + SND_CONFIG_SEARCHA(root, config, key, result, + snd_config_searcha_hooks, + err = snd_config_hooks(config, NULL); \ + if (err < 0) \ + return err; \ + ); +} + +/** + * \brief Searches for a node in a configuration tree, expanding aliases and hooks. + * \param[in] root Handle to the root configuration node containing + * alias definitions. + * \param[in,out] config Handle to the root of the configuration + * (sub)tree to search. + * \param[out] result The function puts the handle to the node found at + * the address specified by \a result. + * \param[in] ... One or more concatenated dot separated search keys, + * terminated with \c NULL. + * \return Zero if successful, otherwise a negative error code. + * + * This function searches for a child node of \a config, allowing + * aliases and expanding hooks like #snd_config_searcha_hooks, but the + * search key is the concatenation of all passed seach key strings, like + * with #snd_config_searchv. + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key or an alias id does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * Additionally, any errors encountered when parsing the hook + * definitions or returned by the hook functions. + */ +int snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config, + snd_config_t **result, ...) +{ + SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha_hooks); +} + +/** + * \brief Searches for a node in a configuration tree, using an alias and expanding hooks. + * \param[in] config Handle to the root of the configuration (sub)tree + * to search. + * \param[in] base Search key base, or \c NULL. + * \param[in] key Search key suffix. + * \param[out] result The function puts the handle to the node found at + * the address specified by \a result. + * \return Zero if successful, otherwise a negative error code. + * + * This functions searches for a child node of \a config, allowing + * aliases, like #snd_config_search_alias, and expanding hooks, like + * #snd_config_search_hooks. + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key or an alias id does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * Additionally, any errors encountered when parsing the hook + * definitions or returned by the hook functions. + */ +int snd_config_search_alias_hooks(snd_config_t *config, + const char *base, const char *key, + snd_config_t **result) +{ + SND_CONFIG_SEARCH_ALIAS(config, base, key, result, + snd_config_searcha_hooks, + snd_config_searchva_hooks); +} + +/** The name of the environment variable containing the files list for #snd_config_update. */ +#define ALSA_CONFIG_PATH_VAR "ALSA_CONFIG_PATH" + +/** The name of the default files used by #snd_config_update. */ +#define ALSA_CONFIG_PATH_DEFAULT ALSA_CONFIG_DIR "/alsa.conf" + +/** + * \ingroup Config + * \brief Configuration top-level node (the global configuration). + * + * This variable contains a handle to the top-level configuration node, + * as loaded from global configuration file. + * + * This variable is initialized or updated by #snd_config_update. + * Functions like #snd_pcm_open (that use a device name from the global + * configuration) automatically call #snd_config_update. Before the + * first call to #snd_config_update, this variable is \c NULL. + * + * The global configuration files are specified in the environment + * variable \c ALSA_CONFIG_PATH. If this is not set, the default value + * is "/usr/share/alsa/alsa.conf". + * + * \warning Whenever the configuration tree is updated, all string + * pointers and configuration node handles previously obtained from this + * variable may become invalid. + * + * \par Conforming to: + * LSB 3.2 + */ +snd_config_t *snd_config = NULL; + +#ifndef DOC_HIDDEN +struct finfo { + char *name; + dev_t dev; + ino_t ino; + time_t mtime; +}; + +struct _snd_config_update { + unsigned int count; + struct finfo *finfo; +}; +#endif /* DOC_HIDDEN */ + +static snd_config_update_t *snd_config_global_update = NULL; + +static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data) +{ + void *h = NULL; + snd_config_t *c, *func_conf = NULL; + char *buf = NULL; + const char *lib = NULL, *func_name = NULL; + const char *str; + int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL; + int err; + + err = snd_config_search(config, "func", &c); + if (err < 0) { + SNDERR("Field func is missing"); + return err; + } + err = snd_config_get_string(c, &str); + if (err < 0) { + SNDERR("Invalid type for field func"); + return err; + } + assert(str); + err = snd_config_search_definition(root, "hook_func", str, &func_conf); + if (err >= 0) { + snd_config_iterator_t i, next; + if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for func %s definition", str); + goto _err; + } + snd_config_for_each(i, next, func_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = n->id; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "func") == 0) { + err = snd_config_get_string(n, &func_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + } + } + if (!func_name) { + int len = 16 + strlen(str) + 1; + buf = malloc(len); + if (! buf) { + err = -ENOMEM; + goto _err; + } + snprintf(buf, len, "snd_config_hook_%s", str); + buf[len-1] = '\0'; + func_name = buf; + } + h = snd_dlopen(lib, RTLD_NOW); + func = h ? snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_HOOK)) : NULL; + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!func) { + SNDERR("symbol %s is not defined inside %s", func_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (func_conf) + snd_config_delete(func_conf); + if (err >= 0) { + snd_config_t *nroot; + err = func(root, config, &nroot, private_data); + if (err < 0) + SNDERR("function %s returned error: %s", func_name, snd_strerror(err)); + snd_dlclose(h); + if (err >= 0 && nroot) + err = snd_config_substitute(root, nroot); + } + free(buf); + if (err < 0) + return err; + return 0; +} + +static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data) +{ + snd_config_t *n; + snd_config_iterator_t i, next; + int err, hit, idx = 0; + + if ((err = snd_config_search(config, "@hooks", &n)) < 0) + return 0; + snd_config_lock(); + snd_config_remove(n); + do { + hit = 0; + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = n->id; + long i; + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not and integer", id); + err = -EINVAL; + goto _err; + } + if (i == idx) { + err = snd_config_hooks_call(config, n, private_data); + if (err < 0) + goto _err; + idx++; + hit = 1; + } + } + } while (hit); + err = 0; + _err: + snd_config_delete(n); + snd_config_unlock(); + return err; +} + +/** + * \brief Loads and parses the given configurations files. + * \param[in] root Handle to the root configuration node. + * \param[in] config Handle to the configuration node for this hook. + * \param[out] dst The function puts the handle to the configuration + * node loaded from the file(s) at the address specified + * by \a dst. + * \param[in] private_data Handle to the private data configuration node. + * \return Zero if successful, otherwise a negative error code. + * + * See \ref confhooks for an example. + */ +int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) +{ + snd_config_t *n; + snd_config_iterator_t i, next; + struct finfo *fi = NULL; + int err, idx = 0, fi_count = 0, errors = 1, hit; + + assert(root && dst); + if ((err = snd_config_search(config, "errors", &n)) >= 0) { + char *tmp; + err = snd_config_get_ascii(n, &tmp); + if (err < 0) + return err; + errors = snd_config_get_bool_ascii(tmp); + free(tmp); + if (errors < 0) { + SNDERR("Invalid bool value in field errors"); + return errors; + } + } + if ((err = snd_config_search(config, "files", &n)) < 0) { + SNDERR("Unable to find field files in the pre-load section"); + return -EINVAL; + } + if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) { + SNDERR("Unable to expand filenames in the pre-load section"); + return err; + } + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for field filenames"); + goto _err; + } + snd_config_for_each(i, next, n) { + snd_config_t *c = snd_config_iterator_entry(i); + const char *str; + if ((err = snd_config_get_string(c, &str)) < 0) { + SNDERR("Field %s is not a string", c->id); + goto _err; + } + fi_count++; + } + fi = calloc(fi_count, sizeof(*fi)); + if (fi == NULL) { + err = -ENOMEM; + goto _err; + } + do { + hit = 0; + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = n->id; + long i; + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not and integer", id); + err = -EINVAL; + goto _err; + } + if (i == idx) { + char *name; + if ((err = snd_config_get_ascii(n, &name)) < 0) + goto _err; + if ((err = snd_user_file(name, &fi[idx].name)) < 0) + fi[idx].name = name; + else + free(name); + idx++; + hit = 1; + } + } + } while (hit); + for (idx = 0; idx < fi_count; idx++) { + snd_input_t *in; + if (!errors && access(fi[idx].name, R_OK) < 0) + continue; + err = snd_input_stdio_open(&in, fi[idx].name, "r"); + if (err >= 0) { + err = snd_config_load(root, in); + snd_input_close(in); + if (err < 0) { + SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name); + goto _err; + } + } else { + SNDERR("cannot access file %s", fi[idx].name); + } + } + *dst = NULL; + err = 0; + _err: + if (fi) + for (idx = 0; idx < fi_count; idx++) + free(fi[idx].name); + free(fi); + snd_config_delete(n); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_config_hook_load, SND_CONFIG_DLSYM_VERSION_HOOK); +#endif + +#ifndef DOC_HIDDEN +int snd_determine_driver(int card, char **driver); +#endif + +/** + * \brief Loads and parses the given configurations files for each + * installed sound card. + * \param[in] root Handle to the root configuration node. + * \param[in] config Handle to the configuration node for this hook. + * \param[out] dst The function puts the handle to the configuration + * node loaded from the file(s) at the address specified + * by \a dst. + * \param[in] private_data Handle to the private data configuration node. + * \return Zero if successful, otherwise a negative error code. + * + * This function works like #snd_config_hook_load, but the files are + * loaded once for each sound card. The driver name is available with + * the \c private_string function to customize the file name. + */ +int snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data ATTRIBUTE_UNUSED) +{ + int card = -1, err; + + do { + err = snd_card_next(&card); + if (err < 0) + return err; + if (card >= 0) { + snd_config_t *n, *private_data = NULL; + const char *driver; + char *fdriver = NULL; + err = snd_determine_driver(card, &fdriver); + if (err < 0) + return err; + if (snd_config_search(root, fdriver, &n) >= 0) { + if (snd_config_get_string(n, &driver) < 0) + goto __err; + assert(driver); + while (1) { + char *s = strchr(driver, '.'); + if (s == NULL) + break; + driver = s + 1; + } + if (snd_config_search(root, driver, &n) >= 0) + goto __err; + } else { + driver = fdriver; + } + err = snd_config_imake_string(&private_data, "string", driver); + if (err < 0) + goto __err; + err = snd_config_hook_load(root, config, &n, private_data); + __err: + if (private_data) + snd_config_delete(private_data); + free(fdriver); + if (err < 0) + return err; + } + } while (card >= 0); + *dst = NULL; + return 0; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VERSION_HOOK); +#endif + +/** + * \brief Updates a configuration tree by rereading the configuration files (if needed). + * \param[in,out] _top Address of the handle to the top-level node. + * \param[in,out] _update Address of a pointer to private update information. + * \param[in] cfgs A list of configuration file names, delimited with ':'. + * If \p cfgs is \c NULL, the default global + * configuration file is used. + * \return 0 if \a _top was up to date, 1 if the configuration files + * have been reread, otherwise a negative error code. + * + * The variables pointed to by \a _top and \a _update can be initialized + * to \c NULL before the first call to this function. The private + * update information holds information about all used configuration + * files that allows this function to detects changes to them; this data + * can be freed with #snd_config_update_free. + * + * The global configuration files are specified in the environment variable + * \c ALSA_CONFIG_PATH. + * + * \warning If the configuration tree is reread, all string pointers and + * configuration node handles previously obtained from this tree become + * invalid. + * + * \par Errors: + * Any errors encountered when parsing the input or returned by hooks or + * functions. + */ +int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs) +{ + int err; + const char *configs, *c; + unsigned int k; + size_t l; + snd_config_update_t *local; + snd_config_update_t *update; + snd_config_t *top; + + assert(_top && _update); + top = *_top; + update = *_update; + configs = cfgs; + if (!configs) { + configs = getenv(ALSA_CONFIG_PATH_VAR); + if (!configs || !*configs) + configs = ALSA_CONFIG_PATH_DEFAULT; + } + for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { + c += l; + k++; + if (!*c) + break; + c++; + } + if (k == 0) { + local = NULL; + goto _reread; + } + local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t)); + if (!local) + return -ENOMEM; + local->count = k; + local->finfo = calloc(local->count, sizeof(struct finfo)); + if (!local->finfo) { + free(local); + return -ENOMEM; + } + for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { + char name[l + 1]; + memcpy(name, c, l); + name[l] = 0; + err = snd_user_file(name, &local->finfo[k].name); + if (err < 0) + goto _end; + c += l; + k++; + if (!*c) + break; + c++; + } + for (k = 0; k < local->count; ++k) { + struct stat st; + struct finfo *lf = &local->finfo[k]; + if (stat(lf->name, &st) >= 0) { + lf->dev = st.st_dev; + lf->ino = st.st_ino; + lf->mtime = st.st_mtime; + } else { + SNDERR("Cannot access file %s", lf->name); + free(lf->name); + memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1)); + k--; + local->count--; + } + } + if (!update) + goto _reread; + if (local->count != update->count) + goto _reread; + for (k = 0; k < local->count; ++k) { + struct finfo *lf = &local->finfo[k]; + struct finfo *uf = &update->finfo[k]; + if (strcmp(lf->name, uf->name) != 0 || + lf->dev != uf->dev || + lf->ino != uf->ino || + lf->mtime != uf->mtime) + goto _reread; + } + err = 0; + + _end: + if (err < 0) { + if (top) { + snd_config_delete(top); + *_top = NULL; + } + if (update) { + snd_config_update_free(update); + *_update = NULL; + } + } + if (local) + snd_config_update_free(local); + return err; + + _reread: + *_top = NULL; + *_update = NULL; + if (update) { + snd_config_update_free(update); + update = NULL; + } + if (top) { + snd_config_delete(top); + top = NULL; + } + err = snd_config_top(&top); + if (err < 0) + goto _end; + if (!local) + goto _skip; + for (k = 0; k < local->count; ++k) { + snd_input_t *in; + err = snd_input_stdio_open(&in, local->finfo[k].name, "r"); + if (err >= 0) { + err = snd_config_load(top, in); + snd_input_close(in); + if (err < 0) { + SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name); + goto _end; + } + } else { + SNDERR("cannot access file %s", local->finfo[k].name); + } + } + _skip: + err = snd_config_hooks(top, NULL); + if (err < 0) { + SNDERR("hooks failed, removing configuration"); + goto _end; + } + *_top = top; + *_update = local; + return 1; +} + +/** + * \brief Updates #snd_config by rereading the global configuration files (if needed). + * \return 0 if #snd_config was up to date, 1 if #snd_config was + * updated, otherwise a negative error code. + * + * \warning Whenever #snd_config is updated, all string pointers and + * configuration node handles previously obtained from it may become + * invalid. + * + * \par Errors: + * Any errors encountered when parsing the input or returned by hooks or + * functions. + * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_update(void) +{ + int err; + + snd_config_lock(); + err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL); + snd_config_unlock(); + return err; +} + +/** + * \brief Frees a private update structure. + * \param[in] update The private update structure to free. + * \return Zero if successful, otherwise a negative error code. + */ +int snd_config_update_free(snd_config_update_t *update) +{ + unsigned int k; + + assert(update); + for (k = 0; k < update->count; k++) + free(update->finfo[k].name); + free(update->finfo); + free(update); + return 0; +} + +/** + * \brief Frees the global configuration tree in #snd_config. + * \return Zero if successful, otherwise a negative error code. + * + * This functions releases all resources of the global configuration + * tree, and sets #snd_config to \c NULL. + * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_update_free_global(void) +{ + snd_config_lock(); + if (snd_config) + snd_config_delete(snd_config); + snd_config = NULL; + if (snd_config_global_update) + snd_config_update_free(snd_config_global_update); + snd_config_global_update = NULL; + snd_config_unlock(); + /* FIXME: better to place this in another place... */ + snd_dlobj_cache_cleanup(); + + return 0; +} + +/** + * \brief Returns an iterator pointing to a node's first child. + * \param[in] config Handle to a configuration node. + * \return An iterator pointing to \a config's first child. + * + * \a config must be a compound node. + * + * The returned iterator is valid if it is not equal to the return value + * of #snd_config_iterator_end on \a config. + * + * Use #snd_config_iterator_entry to get the handle of the node pointed + * to. + * + * \par Conforming to: + * LSB 3.2 + */ +snd_config_iterator_t snd_config_iterator_first(const snd_config_t *config) +{ + assert(config->type == SND_CONFIG_TYPE_COMPOUND); + return config->u.compound.fields.next; +} + +/** + * \brief Returns an iterator pointing to the next sibling. + * \param[in] iterator An iterator pointing to a child configuration node. + * \return An iterator pointing to the next sibling of \a iterator. + * + * The returned iterator is valid if it is not equal to the return value + * of #snd_config_iterator_end on the node's parent. + * + * Use #snd_config_iterator_entry to get the handle of the node pointed + * to. + * + * \par Conforming to: + * LSB 3.2 + */ +snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator) +{ + return iterator->next; +} + +/** + * \brief Returns an iterator that ends a node's children list. + * \param[in] config Handle to a configuration node. + * \return An iterator that indicates the end of \a config's children list. + * + * \a config must be a compound node. + * + * The return value can be understood as pointing past the last child of + * \a config. + * + * \par Conforming to: + * LSB 3.2 + */ +snd_config_iterator_t snd_config_iterator_end(const snd_config_t *config) +{ + assert(config->type == SND_CONFIG_TYPE_COMPOUND); + return (const snd_config_iterator_t)&config->u.compound.fields; +} + +/** + * \brief Returns the configuration node handle pointed to by an iterator. + * \param[in] iterator A configuration node iterator. + * \return The configuration node handle pointed to by \a iterator. + * + * \par Conforming to: + * LSB 3.2 + */ +snd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator) +{ + return list_entry(iterator, snd_config_t, list); +} + +#ifndef DOC_HIDDEN +typedef enum _snd_config_walk_pass { + SND_CONFIG_WALK_PASS_PRE, + SND_CONFIG_WALK_PASS_POST, + SND_CONFIG_WALK_PASS_LEAF, +} snd_config_walk_pass_t; +#endif + +/* Return 1 if node needs to be attached to parent */ +/* Return 2 if compound is replaced with standard node */ +#ifndef DOC_HIDDEN +typedef int (*snd_config_walk_callback_t)(snd_config_t *src, + snd_config_t *root, + snd_config_t **dst, + snd_config_walk_pass_t pass, + snd_config_t *private_data); +#endif + +static int snd_config_walk(snd_config_t *src, + snd_config_t *root, + snd_config_t **dst, + snd_config_walk_callback_t callback, + snd_config_t *private_data) +{ + int err; + snd_config_iterator_t i, next; + + switch (snd_config_get_type(src)) { + case SND_CONFIG_TYPE_COMPOUND: + err = callback(src, root, dst, SND_CONFIG_WALK_PASS_PRE, private_data); + if (err <= 0) + return err; + snd_config_for_each(i, next, src) { + snd_config_t *s = snd_config_iterator_entry(i); + snd_config_t *d = NULL; + + err = snd_config_walk(s, root, (dst && *dst) ? &d : NULL, + callback, private_data); + if (err < 0) + goto _error; + if (err && d) { + err = snd_config_add(*dst, d); + if (err < 0) + goto _error; + } + } + err = callback(src, root, dst, SND_CONFIG_WALK_PASS_POST, private_data); + if (err <= 0) { + _error: + if (dst && *dst) + snd_config_delete(*dst); + } + break; + default: + err = callback(src, root, dst, SND_CONFIG_WALK_PASS_LEAF, private_data); + break; + } + return err; +} + +static int _snd_config_copy(snd_config_t *src, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t **dst, + snd_config_walk_pass_t pass, + snd_config_t *private_data ATTRIBUTE_UNUSED) +{ + int err; + const char *id = src->id; + snd_config_type_t type = snd_config_get_type(src); + switch (pass) { + case SND_CONFIG_WALK_PASS_PRE: + err = snd_config_make_compound(dst, id, src->u.compound.join); + if (err < 0) + return err; + break; + case SND_CONFIG_WALK_PASS_LEAF: + err = snd_config_make(dst, id, type); + if (err < 0) + return err; + switch (type) { + case SND_CONFIG_TYPE_INTEGER: + { + long v; + err = snd_config_get_integer(src, &v); + assert(err >= 0); + snd_config_set_integer(*dst, v); + break; + } + case SND_CONFIG_TYPE_INTEGER64: + { + long long v; + err = snd_config_get_integer64(src, &v); + assert(err >= 0); + snd_config_set_integer64(*dst, v); + break; + } + case SND_CONFIG_TYPE_REAL: + { + double v; + err = snd_config_get_real(src, &v); + assert(err >= 0); + snd_config_set_real(*dst, v); + break; + } + case SND_CONFIG_TYPE_STRING: + { + const char *s; + err = snd_config_get_string(src, &s); + assert(err >= 0); + err = snd_config_set_string(*dst, s); + if (err < 0) + return err; + break; + } + default: + assert(0); + } + break; + default: + break; + } + return 1; +} + +/** + * \brief Creates a copy of a configuration node. + * \param[out] dst The function puts the handle to the new configuration + * node at the address specified by \a dst. + * \param[in] src Handle to the source configuration node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * This function creates a deep copy, i.e., if \a src is a compound + * node, all children are copied recursively. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + *
+ * + * \par Conforming to: + * LSB 3.2 + */ +int snd_config_copy(snd_config_t **dst, + snd_config_t *src) +{ + return snd_config_walk(src, NULL, dst, _snd_config_copy, NULL); +} + +static int _snd_config_expand(snd_config_t *src, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t **dst, + snd_config_walk_pass_t pass, + snd_config_t *private_data) +{ + int err; + const char *id = src->id; + snd_config_type_t type = snd_config_get_type(src); + switch (pass) { + case SND_CONFIG_WALK_PASS_PRE: + { + if (id && strcmp(id, "@args") == 0) + return 0; + err = snd_config_make_compound(dst, id, src->u.compound.join); + if (err < 0) + return err; + break; + } + case SND_CONFIG_WALK_PASS_LEAF: + switch (type) { + case SND_CONFIG_TYPE_INTEGER: + { + long v; + err = snd_config_get_integer(src, &v); + assert(err >= 0); + err = snd_config_imake_integer(dst, id, v); + if (err < 0) + return err; + break; + } + case SND_CONFIG_TYPE_INTEGER64: + { + long long v; + err = snd_config_get_integer64(src, &v); + assert(err >= 0); + err = snd_config_imake_integer64(dst, id, v); + if (err < 0) + return err; + break; + } + case SND_CONFIG_TYPE_REAL: + { + double v; + err = snd_config_get_real(src, &v); + assert(err >= 0); + err = snd_config_imake_real(dst, id, v); + if (err < 0) + return err; + break; + } + case SND_CONFIG_TYPE_STRING: + { + const char *s; + snd_config_t *val; + snd_config_t *vars = private_data; + snd_config_get_string(src, &s); + if (s && *s == '$') { + s++; + if (snd_config_search(vars, s, &val) < 0) + return 0; + err = snd_config_copy(dst, val); + if (err < 0) + return err; + err = snd_config_set_id(*dst, id); + if (err < 0) { + snd_config_delete(*dst); + return err; + } + } else { + err = snd_config_imake_string(dst, id, s); + if (err < 0) + return err; + } + break; + } + default: + assert(0); + } + break; + default: + break; + } + return 1; +} + +static int _snd_config_evaluate(snd_config_t *src, + snd_config_t *root, + snd_config_t **dst ATTRIBUTE_UNUSED, + snd_config_walk_pass_t pass, + snd_config_t *private_data) +{ + int err; + if (pass == SND_CONFIG_WALK_PASS_PRE) { + char *buf = NULL; + const char *lib = NULL, *func_name = NULL; + const char *str; + int (*func)(snd_config_t **dst, snd_config_t *root, + snd_config_t *src, snd_config_t *private_data) = NULL; + void *h = NULL; + snd_config_t *c, *func_conf = NULL; + err = snd_config_search(src, "@func", &c); + if (err < 0) + return 1; + err = snd_config_get_string(c, &str); + if (err < 0) { + SNDERR("Invalid type for @func"); + return err; + } + assert(str); + err = snd_config_search_definition(root, "func", str, &func_conf); + if (err >= 0) { + snd_config_iterator_t i, next; + if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for func %s definition", str); + goto _err; + } + snd_config_for_each(i, next, func_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = n->id; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "func") == 0) { + err = snd_config_get_string(n, &func_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + } + } + if (!func_name) { + int len = 9 + strlen(str) + 1; + buf = malloc(len); + if (! buf) { + err = -ENOMEM; + goto _err; + } + snprintf(buf, len, "snd_func_%s", str); + buf[len-1] = '\0'; + func_name = buf; + } + h = snd_dlopen(lib, RTLD_NOW); + if (h) + func = snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_EVALUATE)); + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + goto _errbuf; + } else if (!func) { + SNDERR("symbol %s is not defined inside %s", func_name, lib); + snd_dlclose(h); + err = -ENXIO; + goto _errbuf; + } + _err: + if (func_conf) + snd_config_delete(func_conf); + if (err >= 0) { + snd_config_t *eval; + err = func(&eval, root, src, private_data); + if (err < 0) + SNDERR("function %s returned error: %s", func_name, snd_strerror(err)); + snd_dlclose(h); + if (err >= 0 && eval) { + /* substitute merges compound members */ + /* we don't want merging at all */ + err = snd_config_delete_compound_members(src); + if (err >= 0) + err = snd_config_substitute(src, eval); + } + } + _errbuf: + free(buf); + if (err < 0) + return err; + return 0; + } + return 1; +} + +/** + * \brief Evaluates a configuration node at runtime. + * \param[in,out] config Handle to the source configuration node. + * \param[in] root Handle to the root of the source configuration. + * \param[in] private_data Handle to the private data node for runtime evaluation. + * \param result Must be \c NULL. + * \return A non-negative value if successful, otherwise a negative error code. + * + * This function evaluates any functions (\c \@func) in \a config and + * replaces those nodes with the respective function results. + */ +int snd_config_evaluate(snd_config_t *config, snd_config_t *root, + snd_config_t *private_data, snd_config_t **result) +{ + /* FIXME: Only in place evaluation is currently implemented */ + assert(result == NULL); + return snd_config_walk(config, root, result, _snd_config_evaluate, private_data); +} + +static int load_defaults(snd_config_t *subs, snd_config_t *defs) +{ + snd_config_iterator_t d, dnext; + snd_config_for_each(d, dnext, defs) { + snd_config_t *def = snd_config_iterator_entry(d); + snd_config_iterator_t f, fnext; + if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) + continue; + snd_config_for_each(f, fnext, def) { + snd_config_t *fld = snd_config_iterator_entry(f); + const char *id = fld->id; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "default") == 0) { + snd_config_t *deflt; + int err; + err = snd_config_copy(&deflt, fld); + if (err < 0) + return err; + err = snd_config_set_id(deflt, def->id); + if (err < 0) { + snd_config_delete(deflt); + return err; + } + err = snd_config_add(subs, deflt); + if (err < 0) { + snd_config_delete(deflt); + return err; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + } + return 0; +} + +static void skip_blank(const char **ptr) +{ + while (1) { + switch (**ptr) { + case ' ': + case '\f': + case '\t': + case '\n': + case '\r': + break; + default: + return; + } + (*ptr)++; + } +} + +static int parse_char(const char **ptr) +{ + int c; + assert(**ptr == '\\'); + (*ptr)++; + c = **ptr; + switch (c) { + case 'n': + c = '\n'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case 'b': + c = '\b'; + break; + case 'r': + c = '\r'; + break; + case 'f': + c = '\f'; + break; + case '0' ... '7': + { + int num = c - '0'; + int i = 1; + (*ptr)++; + do { + c = **ptr; + if (c < '0' || c > '7') + break; + num = num * 8 + c - '0'; + i++; + (*ptr)++; + } while (i < 3); + return num; + } + default: + break; + } + (*ptr)++; + return c; +} + +static int parse_id(const char **ptr) +{ + if (!**ptr) + return -EINVAL; + while (1) { + switch (**ptr) { + case '\f': + case '\t': + case '\n': + case '\r': + case ',': + case '=': + case '\0': + return 0; + default: + break; + } + (*ptr)++; + } +} + +static int parse_string(const char **ptr, char **val) +{ + const size_t bufsize = 256; + char _buf[bufsize]; + char *buf = _buf; + size_t alloc = bufsize; + char delim = **ptr; + size_t idx = 0; + (*ptr)++; + while (1) { + int c = **ptr; + switch (c) { + case '\0': + SNDERR("Unterminated string"); + return -EINVAL; + case '\\': + c = parse_char(ptr); + if (c < 0) + return c; + break; + default: + (*ptr)++; + if (c == delim) { + *val = malloc(idx + 1); + if (!*val) + return -ENOMEM; + memcpy(*val, buf, idx); + (*val)[idx] = 0; + if (alloc > bufsize) + free(buf); + return 0; + } + } + if (idx >= alloc) { + size_t old_alloc = alloc; + alloc *= 2; + if (old_alloc == bufsize) { + buf = malloc(alloc); + memcpy(buf, _buf, old_alloc); + } else { + buf = realloc(buf, alloc); + } + if (!buf) + return -ENOMEM; + } + buf[idx++] = c; + } +} + + +/* Parse var=val or val */ +static int parse_arg(const char **ptr, unsigned int *varlen, char **val) +{ + const char *str; + int err, vallen; + skip_blank(ptr); + str = *ptr; + if (*str == '"' || *str == '\'') { + err = parse_string(ptr, val); + if (err < 0) + return err; + *varlen = 0; + return 0; + } + err = parse_id(ptr); + if (err < 0) + return err; + vallen = *ptr - str; + skip_blank(ptr); + if (**ptr != '=') { + *varlen = 0; + goto _value; + } + *varlen = vallen; + (*ptr)++; + skip_blank(ptr); + str = *ptr; + if (*str == '"' || *str == '\'') { + err = parse_string(ptr, val); + if (err < 0) + return err; + return 0; + } + err = parse_id(ptr); + if (err < 0) + return err; + vallen = *ptr - str; + _value: + *val = malloc(vallen + 1); + if (!*val) + return -ENOMEM; + memcpy(*val, str, vallen); + (*val)[vallen] = 0; + return 0; +} + + +/* val1, val2, ... + * var1=val1,var2=val2,... + * { conf syntax } + */ +static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) +{ + int err; + int arg = 0; + if (str == NULL) + return 0; + skip_blank(&str); + if (!*str) + return 0; + if (*str == '{') { + int len = strlen(str); + snd_input_t *input; + snd_config_iterator_t i, next; + while (1) { + switch (str[--len]) { + case ' ': + case '\f': + case '\t': + case '\n': + case '\r': + continue; + default: + break; + } + break; + } + if (str[len] != '}') + return -EINVAL; + err = snd_input_buffer_open(&input, str + 1, len - 1); + if (err < 0) + return err; + err = snd_config_load_override(subs, input); + snd_input_close(input); + if (err < 0) + return err; + snd_config_for_each(i, next, subs) { + snd_config_t *n = snd_config_iterator_entry(i); + snd_config_t *d; + const char *id = n->id; + err = snd_config_search(defs, id, &d); + if (err < 0) { + SNDERR("Unknown parameter %s", id); + return err; + } + } + return 0; + } + + while (1) { + char buf[256]; + const char *var = buf; + unsigned int varlen; + snd_config_t *def, *sub, *typ; + const char *new = str; + const char *tmp; + char *val = NULL; + err = parse_arg(&new, &varlen, &val); + if (err < 0) + goto _err; + if (varlen > 0) { + assert(varlen < sizeof(buf)); + memcpy(buf, str, varlen); + buf[varlen] = 0; + } else { + sprintf(buf, "%d", arg); + } + err = snd_config_search_alias(defs, NULL, var, &def); + if (err < 0) { + SNDERR("Unknown parameter %s", var); + goto _err; + } + if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Parameter %s definition is not correct", var); + err = -EINVAL; + goto _err; + } + var = def->id; + err = snd_config_search(subs, var, &sub); + if (err >= 0) + snd_config_delete(sub); + err = snd_config_search(def, "type", &typ); + if (err < 0) { + _invalid_type: + SNDERR("Parameter %s definition is missing a valid type info", var); + goto _err; + } + err = snd_config_get_string(typ, &tmp); + if (err < 0 || !tmp) + goto _invalid_type; + if (strcmp(tmp, "integer") == 0) { + long v; + err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER); + if (err < 0) + goto _err; + err = safe_strtol(val, &v); + if (err < 0) { + SNDERR("Parameter %s must be an integer", var); + goto _err; + } + err = snd_config_set_integer(sub, v); + if (err < 0) + goto _err; + } else if (strcmp(tmp, "integer64") == 0) { + long long v; + err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER64); + if (err < 0) + goto _err; + err = safe_strtoll(val, &v); + if (err < 0) { + SNDERR("Parameter %s must be an integer", var); + goto _err; + } + err = snd_config_set_integer64(sub, v); + if (err < 0) + goto _err; + } else if (strcmp(tmp, "real") == 0) { + double v; + err = snd_config_make(&sub, var, SND_CONFIG_TYPE_REAL); + if (err < 0) + goto _err; + err = safe_strtod(val, &v); + if (err < 0) { + SNDERR("Parameter %s must be a real", var); + goto _err; + } + err = snd_config_set_real(sub, v); + if (err < 0) + goto _err; + } else if (strcmp(tmp, "string") == 0) { + err = snd_config_make(&sub, var, SND_CONFIG_TYPE_STRING); + if (err < 0) + goto _err; + err = snd_config_set_string(sub, val); + if (err < 0) + goto _err; + } else { + err = -EINVAL; + goto _invalid_type; + } + err = snd_config_set_id(sub, var); + if (err < 0) + goto _err; + err = snd_config_add(subs, sub); + if (err < 0) { + _err: + free(val); + return err; + } + free(val); + if (!*new) + break; + if (*new != ',') + return -EINVAL; + str = new + 1; + arg++; + } + return 0; +} + +/** + * \brief Expands a configuration node, applying arguments and functions. + * \param[in] config Handle to the configuration node. + * \param[in] root Handle to the root configuration node. + * \param[in] args Arguments string, can be \c NULL. + * \param[in] private_data Handle to the private data node for functions. + * \param[out] result The function puts the handle to the result + * configuration node at the address specified by + * \a result. + * \return A non-negative value if successful, otherwise a negative error code. + * + * If \a config has arguments (defined by a child with id \c \@args), + * this function replaces any string node beginning with $ with the + * respective argument value, or the default argument value, or nothing. + * Furthermore, any functions are evaluated (see #snd_config_evaluate). + * The resulting copy of \a config is returned in \a result. + */ +int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args, + snd_config_t *private_data, snd_config_t **result) +{ + int err; + snd_config_t *defs, *subs = NULL, *res; + err = snd_config_search(config, "@args", &defs); + if (err < 0) { + if (args != NULL) { + SNDERR("Unknown parameters %s", args); + return -EINVAL; + } + err = snd_config_copy(&res, config); + if (err < 0) + return err; + } else { + err = snd_config_top(&subs); + if (err < 0) + return err; + err = load_defaults(subs, defs); + if (err < 0) { + SNDERR("Load defaults error: %s", snd_strerror(err)); + goto _end; + } + err = parse_args(subs, args, defs); + if (err < 0) { + SNDERR("Parse arguments error: %s", snd_strerror(err)); + goto _end; + } + err = snd_config_evaluate(subs, root, private_data, NULL); + if (err < 0) { + SNDERR("Args evaluate error: %s", snd_strerror(err)); + goto _end; + } + err = snd_config_walk(config, root, &res, _snd_config_expand, subs); + if (err < 0) { + SNDERR("Expand error (walk): %s", snd_strerror(err)); + goto _end; + } + } + err = snd_config_evaluate(res, root, private_data, NULL); + if (err < 0) { + SNDERR("Evaluate error: %s", snd_strerror(err)); + snd_config_delete(res); + goto _end; + } + *result = res; + err = 1; + _end: + if (subs) + snd_config_delete(subs); + return err; +} + +/** + * \brief Searches for a definition in a configuration tree, using + * aliases and expanding hooks and arguments. + * \param[in] config Handle to the configuration (sub)tree to search. + * \param[in] base Implicit key base, or \c NULL for none. + * \param[in] name Key suffix, optionally with arguments. + * \param[out] result The function puts the handle to the expanded found + * node at the address specified by \a result. + * \return A non-negative value if successful, otherwise a negative error code. + * + * This functions searches for a child node of \a config, allowing + * aliases and expanding hooks, like #snd_config_search_alias_hooks. + * + * If \a name contains a colon (:), the rest of the string after the + * colon contains arguments that are expanded as with + * #snd_config_expand. + * + * In any case, \a result is a new node that must be freed by the + * caller. + * + * \par Errors: + *
+ *
-ENOENT
An id in \a key or an alias id does not exist. + *
-ENOENT
\a config or one of its child nodes to be searched is + * not a compound node. + *
+ * Additionally, any errors encountered when parsing the hook + * definitions or arguments, or returned by (hook) functions. + */ +int snd_config_search_definition(snd_config_t *config, + const char *base, const char *name, + snd_config_t **result) +{ + snd_config_t *conf; + char *key; + const char *args = strchr(name, ':'); + int err; + if (args) { + args++; + key = alloca(args - name); + memcpy(key, name, args - name - 1); + key[args - name - 1] = '\0'; + } else { + key = (char *) name; + } + /* + * if key contains dot (.), the implicit base is ignored + * and the key starts from root given by the 'config' parameter + */ + snd_config_lock(); + err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf); + if (err < 0) { + snd_config_unlock(); + return err; + } + err = snd_config_expand(conf, config, args, NULL, result); + snd_config_unlock(); + return err; +} + +#ifndef DOC_HIDDEN +void snd_config_set_hop(snd_config_t *conf, int hop) +{ + conf->hop = hop; +} + +int snd_config_check_hop(snd_config_t *conf) +{ + if (conf) { + if (conf->hop >= SND_CONF_MAX_HOPS) { + SYSERR("Too many definition levels (looped?)\n"); + return -EINVAL; + } + return conf->hop; + } + return 0; +} +#endif + +#if 0 +/* Not strictly needed, but useful to check for memory leaks */ +void _snd_config_end(void) __attribute__ ((destructor)); + +static void _snd_config_end(void) +{ + int k; + if (snd_config) + snd_config_delete(snd_config); + snd_config = 0; + for (k = 0; k < files_info_count; ++k) + free(files_info[k].name); + free(files_info); + files_info = NULL; + files_info_count = 0; +} +#endif diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am new file mode 100644 index 0000000..2e5d0bf --- /dev/null +++ b/src/conf/Makefile.am @@ -0,0 +1,15 @@ +SUBDIRS=cards pcm + +cfg_files = alsa.conf +if BUILD_ALISP +cfg_files += sndo-mixer.alisp +endif +if BUILD_MODULES +cfg_files += smixer.conf +endif + +EXTRA_DIST = $(cfg_files) + +alsaconfigdir = @ALSA_CONFIG_DIR@ +alsadir = $(alsaconfigdir) +alsa_DATA = $(cfg_files) diff --git a/src/conf/Makefile.in b/src/conf/Makefile.in new file mode 100644 index 0000000..68b9b69 --- /dev/null +++ b/src/conf/Makefile.in @@ -0,0 +1,624 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_ALISP_TRUE@am__append_1 = sndo-mixer.alisp +@BUILD_MODULES_TRUE@am__append_2 = smixer.conf +subdir = src/conf +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(alsadir)" +DATA = $(alsa_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = cards pcm +cfg_files = alsa.conf $(am__append_1) $(am__append_2) +EXTRA_DIST = $(cfg_files) +alsaconfigdir = @ALSA_CONFIG_DIR@ +alsadir = $(alsaconfigdir) +alsa_DATA = $(cfg_files) +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/conf/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/conf/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-alsaDATA: $(alsa_DATA) + @$(NORMAL_INSTALL) + test -z "$(alsadir)" || $(MKDIR_P) "$(DESTDIR)$(alsadir)" + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(alsadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(alsadir)" || exit $$?; \ + done + +uninstall-alsaDATA: + @$(NORMAL_UNINSTALL) + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(alsadir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(alsadir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(alsadir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-alsaDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-alsaDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-alsaDATA install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-alsaDATA uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf new file mode 100644 index 0000000..1889f01 --- /dev/null +++ b/src/conf/alsa.conf @@ -0,0 +1,609 @@ +# +# ALSA library configuration file +# + +# pre-load the configuration files + +@hooks [ + { + func load + files [ + "/etc/asound.conf" + "~/.asoundrc" + ] + errors false + } +] + +# load card-specific configuration files (on request) + +cards.@hooks [ + { + func load + files [ + { + @func concat + strings [ + { @func datadir } + "/cards/aliases.conf" + ] + } + ] + } + { + func load_for_all_cards + files [ + { + @func concat + strings [ + { @func datadir } + "/cards/" + { @func private_string } + ".conf" + ] + } + ] + errors false + } +] + +# +# defaults +# + +# show all name hints also for definitions without hint {} section +defaults.namehint.showall off +# show just basic name hints +defaults.namehint.basic on +# show extended name hints +defaults.namehint.extended off +# +defaults.ctl.card 0 +defaults.pcm.card 0 +defaults.pcm.device 0 +defaults.pcm.subdevice -1 +defaults.pcm.nonblock 1 +defaults.pcm.compat 0 +defaults.pcm.minperiodtime 5000 # in us +defaults.pcm.ipc_key 5678293 +defaults.pcm.ipc_gid audio +defaults.pcm.ipc_perm 0660 +defaults.pcm.dmix.max_periods 0 +defaults.pcm.dmix.rate 48000 +defaults.pcm.dmix.format "unchanged" +defaults.pcm.dmix.card defaults.pcm.card +defaults.pcm.dmix.device defaults.pcm.device +defaults.pcm.dsnoop.card defaults.pcm.card +defaults.pcm.dsnoop.device defaults.pcm.device +defaults.pcm.front.card defaults.pcm.card +defaults.pcm.front.device defaults.pcm.device +defaults.pcm.rear.card defaults.pcm.card +defaults.pcm.rear.device defaults.pcm.device +defaults.pcm.center_lfe.card defaults.pcm.card +defaults.pcm.center_lfe.device defaults.pcm.device +defaults.pcm.side.card defaults.pcm.card +defaults.pcm.side.device defaults.pcm.device +defaults.pcm.surround40.card defaults.pcm.card +defaults.pcm.surround40.device defaults.pcm.device +defaults.pcm.surround41.card defaults.pcm.card +defaults.pcm.surround41.device defaults.pcm.device +defaults.pcm.surround50.card defaults.pcm.card +defaults.pcm.surround50.device defaults.pcm.device +defaults.pcm.surround51.card defaults.pcm.card +defaults.pcm.surround51.device defaults.pcm.device +defaults.pcm.surround71.card defaults.pcm.card +defaults.pcm.surround71.device defaults.pcm.device +defaults.pcm.iec958.card defaults.pcm.card +defaults.pcm.iec958.device defaults.pcm.device +defaults.pcm.modem.card defaults.pcm.card +defaults.pcm.modem.device defaults.pcm.device +# truncate files via file or tee PCM +defaults.pcm.file_format "raw" +defaults.pcm.file_truncate true +defaults.rawmidi.card 0 +defaults.rawmidi.device 0 +defaults.rawmidi.subdevice -1 +defaults.hwdep.card 0 +defaults.hwdep.device 0 +defaults.timer.class 2 +defaults.timer.sclass 0 +defaults.timer.card 0 +defaults.timer.device 0 +defaults.timer.subdevice 0 + +# +# PCM interface +# + +# redirect to load-on-demand extended pcm definitions +pcm.cards cards.pcm + +pcm.default cards.pcm.default +pcm.front cards.pcm.front +pcm.rear cards.pcm.rear +pcm.center_lfe cards.pcm.center_lfe +pcm.side cards.pcm.side +pcm.surround40 cards.pcm.surround40 +pcm.surround41 cards.pcm.surround41 +pcm.surround50 cards.pcm.surround50 +pcm.surround51 cards.pcm.surround51 +pcm.surround71 cards.pcm.surround71 +pcm.iec958 cards.pcm.iec958 +pcm.spdif iec958 +pcm.hdmi cards.pcm.hdmi +pcm.dmix cards.pcm.dmix +pcm.dsnoop cards.pcm.dsnoop +pcm.modem cards.pcm.modem +pcm.phoneline cards.pcm.phoneline + +pcm.hw { + @args [ CARD DEV SUBDEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_PCM_DEVICE + ] + default { + @func refer + name defaults.pcm.device + } + } + } + @args.SUBDEV { + type integer + default { + @func refer + name defaults.pcm.subdevice + } + } + type hw + card $CARD + device $DEV + subdevice $SUBDEV + hint { + show { + @func refer + name defaults.namehint.extended + } + description "Direct hardware device without any conversions" + } +} + +pcm.plughw { + @args [ CARD DEV SUBDEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_PCM_DEVICE + ] + default { + @func refer + name defaults.pcm.device + } + } + } + @args.SUBDEV { + type integer + default { + @func refer + name defaults.pcm.subdevice + } + } + type plug + slave.pcm { + type hw + card $CARD + device $DEV + subdevice $SUBDEV + } + hint { + show { + @func refer + name defaults.namehint.extended + } + description "Hardware device with all software conversions" + } +} + +pcm.plug { + @args [ SLAVE ] + @args.SLAVE { + type string + } + type plug + slave.pcm $SLAVE +} + +pcm.shm { + @args [ SOCKET PCM ] + @args.SOCKET { + type string + } + @args.PCM { + type string + } + type shm + server $SOCKET + pcm $PCM +} + +pcm.tee { + @args [ SLAVE FILE FORMAT ] + @args.SLAVE { + type string + } + @args.FILE { + type string + } + @args.FORMAT { + type string + default { + @func refer + name defaults.pcm.file_format + } + } + type file + slave.pcm $SLAVE + file $FILE + format $FORMAT + truncate { + @func refer + name defaults.pcm.file_truncate + } +} + +pcm.file { + @args [ FILE FORMAT ] + @args.FILE { + type string + } + @args.FORMAT { + type string + default { + @func refer + name defaults.pcm.file_format + } + } + type file + slave.pcm null + file $FILE + format $FORMAT + truncate { + @func refer + name defaults.pcm.file_truncate + } +} + +pcm.null { + type null + hint { + show { + @func refer + name defaults.namehint.basic + } + description "Discard all samples (playback) or generate zero samples (capture)" + } +} + +# +# Control interface +# + +ctl.default { + type hw + card { + @func getenv + vars [ + ALSA_CTL_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.ctl.card + } + } +} + +ctl.hw { + @args [ CARD ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_CTL_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.ctl.card + } + } + } + type hw + card $CARD +} + +ctl.shm { + @args [ SOCKET CTL ] + @args.SOCKET { + type string + } + @args.CTL { + type string + } + type shm + server $SOCKET + ctl $CTL +} + +# +# RawMidi interface +# + +rawmidi.default { + type hw + card { + @func getenv + vars [ + ALSA_RAWMIDI_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.rawmidi.card + } + } + device { + @func igetenv + vars [ + ALSA_RAWMIDI_DEVICE + ] + default { + @func refer + name defaults.rawmidi.device + } + } +} + +rawmidi.hw { + @args [ CARD DEV SUBDEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_RAWMIDI_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.rawmidi.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_RAWMIDI_DEVICE + ] + default { + @func refer + name defaults.rawmidi.device + } + } + } + @args.SUBDEV { + type integer + default -1 + } + type hw + card $CARD + device $DEV + subdevice $SUBDEV + hint { + description "Direct rawmidi driver device" + device $DEV + } +} + +rawmidi.virtual { + @args [ MERGE ] + @args.MERGE { + type string + default 1 + } + type virtual + merge $MERGE +} + +# +# Sequencer interface +# + +seq.default { + type hw +} + +seq.hw { + type hw +} + +# +# HwDep interface +# + +hwdep.default { + type hw + card { + @func getenv + vars [ + ALSA_HWDEP_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.hwdep.card + } + } + device { + @func igetenv + vars [ + ALSA_HWDEP_DEVICE + ] + default { + @func refer + name defaults.hwdep.device + } + } +} + +hwdep.hw { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_HWDEP_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.hwdep.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_HWDEP_DEVICE + ] + default { + @func refer + name defaults.hwdep.device + } + } + } + type hw + card $CARD + device $DEV +} + +# +# Timer interface +# + +timer_query.default { + type hw +} + +timer_query.hw { + type hw +} + +timer.default { + type hw + class { + @func refer + name defaults.timer.class + } + sclass { + @func refer + name defaults.timer.sclass + } + card { + @func refer + name defaults.timer.card + } + device { + @func refer + name defaults.timer.device + } + subdevice { + @func refer + name defaults.timer.subdevice + } + hint.description "Default direct hardware timer device" +} + +timer.hw { + @args [ CLASS SCLASS CARD DEV SUBDEV ] + @args.CLASS { + type integer + default { + @func refer + name defaults.timer.class + } + } + @args.SCLASS { + type integer + default { + @func refer + name defaults.timer.sclass + } + } + @args.CARD { + type string + default { + @func refer + name defaults.timer.card + } + } + @args.DEV { + type integer + default { + @func refer + name defaults.timer.device + } + } + @args.SUBDEV { + type integer + default { + @func refer + name defaults.timer.subdevice + } + } + type hw + class $CLASS + sclass $SCLASS + card $CARD + device $DEV + subdevice $SUBDEV +} diff --git a/src/conf/cards/AACI.conf b/src/conf/cards/AACI.conf new file mode 100644 index 0000000..748586a --- /dev/null +++ b/src/conf/cards/AACI.conf @@ -0,0 +1,47 @@ +# +# ALSA library configuration for ARM AACI Primecell PL-041 +# + + + +AACI.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +AACI.pcm.surround40.0 "cards.AACI.pcm.front.0" + + + +AACI.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.AACI.pcm.front.0:CARD=" $CARD + ] + } + channels 6 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 0 channel 3 } + { slave 0 channel 4 } + { slave 0 channel 2 } + { slave 0 channel 5 } + ] +} diff --git a/src/conf/cards/ATIIXP-MODEM.conf b/src/conf/cards/ATIIXP-MODEM.conf new file mode 100644 index 0000000..6e52af0 --- /dev/null +++ b/src/conf/cards/ATIIXP-MODEM.conf @@ -0,0 +1,22 @@ +# +# Configuration for the ATI IXP 150/200/250 modem controllers +# + + + +ATIIXP-MODEM.pcm.modem.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + slave.pcm { + type hw + card $CARD + } + slave.channels 2 + slave.format S16_LE + ttable.0.1 1 + ttable.1.0 0 + hint.show off +} diff --git a/src/conf/cards/ATIIXP-SPDMA.conf b/src/conf/cards/ATIIXP-SPDMA.conf new file mode 100644 index 0000000..5c80815 --- /dev/null +++ b/src/conf/cards/ATIIXP-SPDMA.conf @@ -0,0 +1,165 @@ +# +# Configuration for the ATI IXP 150/200/250 chips +# + + + +ATIIXP-SPDMA.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +ATIIXP.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +ATIIXP-SPDMA.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + + + +ATIIXP-SPDMA.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + +ATIIXP-SPDMA.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type iec958 + slave { + pcm { + type hw + card $CARD + device 1 + } + format IEC958_SUBFRAME_LE + } + status [ $AES0 $AES1 $AES2 $AES3 ] +} diff --git a/src/conf/cards/ATIIXP.conf b/src/conf/cards/ATIIXP.conf new file mode 100644 index 0000000..38d8023 --- /dev/null +++ b/src/conf/cards/ATIIXP.conf @@ -0,0 +1,184 @@ +# +# Configuration for the ATI IXP 150/200/250 chips +# + + + +ATIIXP.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +ATIIXP.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +ATIIXP.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + + + +ATIIXP.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + +ATIIXP.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 3 + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/AU8810.conf b/src/conf/cards/AU8810.conf new file mode 100644 index 0000000..24d46c3 --- /dev/null +++ b/src/conf/cards/AU8810.conf @@ -0,0 +1,38 @@ +# +# Configuration for the AU8810 chip +# + + + +AU8810.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +AU8810.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hw + card $CARD + device 1 +} diff --git a/src/conf/cards/AU8820.conf b/src/conf/cards/AU8820.conf new file mode 100644 index 0000000..0789025 --- /dev/null +++ b/src/conf/cards/AU8820.conf @@ -0,0 +1,14 @@ +# +# Configuration for the AU8820 chip +# + + + +AU8820.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} diff --git a/src/conf/cards/AU8830.conf b/src/conf/cards/AU8830.conf new file mode 100644 index 0000000..39e66d5 --- /dev/null +++ b/src/conf/cards/AU8830.conf @@ -0,0 +1,42 @@ +# +# Configuration for the AU8830 chip +# + + + +AU8830.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +AU8830.pcm.surround40.0 "cards.AU8830.pcm.front.0" + + + +AU8830.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hw + card $CARD + device 1 +} diff --git a/src/conf/cards/Audigy.conf b/src/conf/cards/Audigy.conf new file mode 100644 index 0000000..ea1e53d --- /dev/null +++ b/src/conf/cards/Audigy.conf @@ -0,0 +1,318 @@ +# +# Configuration for the Audigy chip +# + + + +Audigy.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 ] + } + + ] + } +} + + + +Audigy.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 ] + } + ] + } +} + + + +Audigy.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 ] + } + ] + } +} + + + + + +Audigy.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Audigy.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +Audigy.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Audigy.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + + + +Audigy.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Optical Raw Playback Switch" + lock true + preserve true + value [ 1 1 ] + } + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 ] + } + { + name "Audigy Analog/Digital Output Jack" + lock true + preserve true + value 1 + } + ] + } +} diff --git a/src/conf/cards/Audigy2.conf b/src/conf/cards/Audigy2.conf new file mode 100644 index 0000000..0290f6f --- /dev/null +++ b/src/conf/cards/Audigy2.conf @@ -0,0 +1,425 @@ +# +# Configuration for the Audigy2 chip +# + + + +Audigy2.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 8 9 0 0 0 0 0 0 ] + } + + ] + } +} + + + +Audigy2.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 ] + } + ] + } +} + + + +Audigy2.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 6 7 0 0 0 0 0 0 ] + } + ] + } +} + + + +Audigy2.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 14 15 0 0 0 0 0 0 14 15 0 0 0 0 0 0 14 15 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 14 15 0 0 0 0 0 0 14 15 0 0 0 0 0 0 14 15 0 0 0 0 0 0 ] + } + ] + } +} + + + + + +Audigy2.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +Audigy2.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + + + +Audigy2.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Audigy2.pcm.side.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + { slave 3 channel 0 } + { slave 3 channel 1 } + ] +} + + + +Audigy2.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Optical Raw Playback Switch" + lock true + preserve true + value [ 1 1 ] + } + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 20 21 0 0 0 0 0 0 ] + } + { + name "Audigy Analog/Digital Output Jack" + lock true + preserve true + value 1 + } + ] + } +} diff --git a/src/conf/cards/Aureon51.conf b/src/conf/cards/Aureon51.conf new file mode 100644 index 0000000..24b4d94 --- /dev/null +++ b/src/conf/cards/Aureon51.conf @@ -0,0 +1,179 @@ +# +# Configuration for the Aureon51 (Envy24HT) chip +# + +# default with dmix & dsnoop +Aureon51.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] + } + } +} + + + +Aureon51.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +Aureon51.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + subdevice 1 +} + + + +Aureon51.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 +} + + + +Aureon51.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + subdevice 2 +} + + + +Aureon51.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 4 +} + + + + + +Aureon51.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 6 +} + + + +Aureon51.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type linear + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Output Switch" + lock true + preserve true + value true + } + { + interface PCM + name "IEC958 Playback Default" + device 1 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + slave.format S32_LE + } + capture.pcm { + type linear + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Capture Switch" + lock true + preserve true + value true + } + ] + } + } + slave.format S32_LE + } +} diff --git a/src/conf/cards/Aureon71.conf b/src/conf/cards/Aureon71.conf new file mode 100644 index 0000000..1479c25 --- /dev/null +++ b/src/conf/cards/Aureon71.conf @@ -0,0 +1,190 @@ +# +# Configuration for the Aureon71 (Envy24HT) chip +# + +# default with dmix & dsnoop +Aureon71.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] + } + } +} + + + +Aureon71.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +Aureon71.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 +} + + + +Aureon71.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + subdevice 1 +} + + + +Aureon71.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + subdevice 2 +} + + + +Aureon71.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 4 +} + + + + + +Aureon71.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 6 +} + + + +Aureon71.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +Aureon71.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type linear + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Output Switch" + lock true + preserve true + value true + } + { + interface PCM + name "IEC958 Playback Default" + device 1 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + slave.format S32_LE + } + capture.pcm { + type linear + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Capture Switch" + lock true + preserve true + value true + } + ] + } + } + slave.format S32_LE + } +} diff --git a/src/conf/cards/CA0106.conf b/src/conf/cards/CA0106.conf new file mode 100644 index 0000000..9d21770 --- /dev/null +++ b/src/conf/cards/CA0106.conf @@ -0,0 +1,280 @@ +# +# Configuration for the CA0106 chip +# + +# default with dmix & dsnoop +CA0106.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +CA0106.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +CA0106.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + + + +CA0106.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 +} + + + +CA0106.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 3 +} + + + +CA0106.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + + + + +CA0106.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + +CA0106.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CA0106.pcm.side.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + { slave 3 channel 0 } + { slave 3 channel 1 } + ] +} + + + + + + +CA0106.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Front Playback Volume" + index 0 + lock true + preserve true + value [ 207 207 ] # Puts 0x30303030 in the Volume register. 0xff - 0x30 = 0xcf = 207 + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value 1 + } + { + interface PCM + name "IEC958 Playback Default" + index 1 + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + index 1 + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/CMI8338-SWIEC.conf b/src/conf/cards/CMI8338-SWIEC.conf new file mode 100644 index 0000000..af3a579 --- /dev/null +++ b/src/conf/cards/CMI8338-SWIEC.conf @@ -0,0 +1,129 @@ +# +# Configuration for the CMI8338/8738 chip (w/o multi-channel support) +# using software IEC958 subframe conversion +# + + + +CMI8338-SWIEC.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +CMI8338-SWIEC.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +# 2nd DAC +# FIXME: we need a volume attenuator for rear channel. +CMI8338-SWIEC.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + + + +# for the old CM8738 with 2nd DAC for rear +CMI8338-SWIEC.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + master 1 + slaves [ + { + pcm { + @func concat + strings [ + "cards.CMI8338-SWIEC.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CMI8338-SWIEC.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +CMI8338-SWIEC.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type iec958 + slave.pcm { + type hw + card $CARD + device 2 + } + status [ $AES0 $AES1 $AES2 $AES3 ] + preamble.z 3 + preamble.y 5 + preamble.x 9 + } + capture.pcm { + type hw + card $CARD + device 2 + } +} diff --git a/src/conf/cards/CMI8338.conf b/src/conf/cards/CMI8338.conf new file mode 100644 index 0000000..144fc9b --- /dev/null +++ b/src/conf/cards/CMI8338.conf @@ -0,0 +1,143 @@ +# +# Configuration for the CMI8338/8738 chip (w/o multi-channel support) +# + + + +CMI8338.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +CMI8338.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +# 2nd DAC +# FIXME: we need a volume attenuator for rear channel. +CMI8338.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + + + +# for the old CM8738 with 2nd DAC for rear +CMI8338.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + master 1 + slaves [ + { + pcm { + @func concat + strings [ + "cards.CMI8338.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CMI8338.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +CMI8338.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + device 2 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Loop" + lock true + preserve true + value off + } + ] + } + } + capture.pcm { + type hw + card $CARD + device 2 + } +} diff --git a/src/conf/cards/CMI8738-MC6.conf b/src/conf/cards/CMI8738-MC6.conf new file mode 100644 index 0000000..171c772 --- /dev/null +++ b/src/conf/cards/CMI8738-MC6.conf @@ -0,0 +1,161 @@ +# +# Configuration for the CMI8738 chip with 4/6 multi-channel support +# + + + +CMI8738-MC6.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +CMI8738-MC6.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +# 2nd DAC +# FIXME: we need a volume attenuator for rear channel. +CMI8738-MC6.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + + + +CMI8738-MC6.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Four Channel Mode" + lock true + preserve true + value false + } + ] + } +} + + + + + +CMI8738-MC6.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Four Channel Mode" + lock true + preserve true + value false + } + ] + } +} + + + +CMI8738-MC6.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + device 2 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Loop" + lock true + preserve true + value off + } + ] + } + } + capture.pcm { + type hw + card $CARD + device 2 + } +} diff --git a/src/conf/cards/CMI8738-MC8.conf b/src/conf/cards/CMI8738-MC8.conf new file mode 100644 index 0000000..a5bf6cb --- /dev/null +++ b/src/conf/cards/CMI8738-MC8.conf @@ -0,0 +1,230 @@ +# +# Configuration for the CMI8768 chip with 8 multi-channel support +# + + + +CMI8738-MC8.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol & dsnoop +CMI8738-MC8.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +# 2nd DAC +CMI8738-MC8.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + device 1 + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +CMI8738-MC8.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Four Channel Mode" + lock true + preserve true + value false + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + + + + +CMI8738-MC8.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Four Channel Mode" + lock true + preserve true + value false + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +CMI8738-MC8.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 8 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Four Channel Mode" + lock true + preserve true + value false + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +CMI8738-MC8.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + device 2 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Loop" + lock true + preserve true + value off + } + ] + } + } + capture.pcm { + type hw + card $CARD + device 2 + } +} diff --git a/src/conf/cards/CMI8788.conf b/src/conf/cards/CMI8788.conf new file mode 100644 index 0000000..0ca71e9 --- /dev/null +++ b/src/conf/cards/CMI8788.conf @@ -0,0 +1,126 @@ +# +# Configuration for the CMI8788 chip +# + + + +CMI8788.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix & dsnoop +CMI8788.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] + } + } +} + + + +CMI8788.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 4 +} + + + + + + +CMI8788.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 6 +} + + + +CMI8788.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + channels 8 +} + + + +CMI8788.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + device 1 + name "IEC958 Playback PCM Stream" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + capture.pcm { + type hw + card $CARD + device 1 + } +} + +# vim: ft=alsaconf diff --git a/src/conf/cards/CS46xx.conf b/src/conf/cards/CS46xx.conf new file mode 100644 index 0000000..1983142 --- /dev/null +++ b/src/conf/cards/CS46xx.conf @@ -0,0 +1,218 @@ +# +# Configuration for the CS46xx chip +# + + + +CS46xx.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with plughw +# CS46xx supports multi-playback +CS46xx.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "hw:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "hw:" $CARD ] + } + } +} + + + +CS46xx.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Duplicate Front" + lock true + preserve true + value 0 + optional true + } + ] + } +} + + + +CS46xx.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 3 +} + + + +CS46xx.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.CS46xx.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CS46xx.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + + + +CS46xx.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.CS46xx.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CS46xx.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.CS46xx.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + + + +CS46xx.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Output Switch" + lock true + preserve true + value 1 + } + { + interface PCM + name "IEC958 Playback PCM Stream" + device 2 + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + interface PCM + name "IEC958 Playback PCM Stream" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/EMU10K1.conf b/src/conf/cards/EMU10K1.conf new file mode 100644 index 0000000..7a7ebf5 --- /dev/null +++ b/src/conf/cards/EMU10K1.conf @@ -0,0 +1,310 @@ +# +# Configuration for the EMU10K1 chip +# + + + +EMU10K1.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 255 0 0 0 0 255 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 255 0 0 0 0 255 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 8 9 0 0 8 9 0 0 8 9 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 8 9 0 0 8 9 0 0 8 9 0 0 ] + } + ] + } +} + + + +EMU10K1.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 0 0 255 255 0 0 255 0 0 0 0 255 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 0 0 255 255 0 0 255 0 0 0 0 255 ] + } + ] + } +} + + + +EMU10K1.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Headphone Center Playback Switch" + index 1 + preserve true + # lock true + value true + } + { + name "Headphone LFE Playback Switch" + index 1 + preserve true + # lock true + value true + } +# if you have a creative's digital receiver, you can get surround/center/lfe +# output through the digital jack. so, the following is commented out. +# pay attention in case of analog output from the shared center/digital +# jack! +# { +# name "SB Live Analog/Digital Output Jack" +# preserve true +# lock true +# value 0 +# } + { + interface PCM + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 255 0 0 0 0 255 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 255 255 0 0 255 0 0 0 0 255 0 0 ] + } + { + interface PCM + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 6 7 0 0 6 7 0 0 6 7 0 0 ] + } + { + # for compatibility with older drivers + name "EMU10K1 PCM Send Routing" + index { @func private_pcm_subdevice } + lock true + optional true + value [ 6 7 0 0 6 7 0 0 6 7 0 0 ] + } + ] + } +} + + + +EMU10K1.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.EMU10K1.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.EMU10K1.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + + + +EMU10K1.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.EMU10K1.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.EMU10K1.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.EMU10K1.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + + + +EMU10K1.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + device 2 + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Optical Raw Playback Switch" + lock true + preserve true + value [ 1 1 ] + } + { + name "SB Live Analog/Digital Output Jack" + lock true + preserve true + value 1 + } + ] + } +} diff --git a/src/conf/cards/EMU10K1X.conf b/src/conf/cards/EMU10K1X.conf new file mode 100644 index 0000000..b5fc708 --- /dev/null +++ b/src/conf/cards/EMU10K1X.conf @@ -0,0 +1,201 @@ +# +# Configuration for the EMU10K1X chip +# + +# default with dmix & dsnoop +EMU10K1X.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +EMU10K1X.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +EMU10K1X.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + + + +EMU10K1X.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 +} + + + +EMU10K1X.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.EMU10K1X.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.EMU10K1X.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + + + +EMU10K1X.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.EMU10K1X.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.EMU10K1X.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.EMU10K1X.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + + + +EMU10K1X.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Analog/Digital Output Jack" + lock true + preserve true + value 0 + } + { + interface PCM + name "IEC958 Playback Default" + index 0 + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + index 0 + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/ENS1370.conf b/src/conf/cards/ENS1370.conf new file mode 100644 index 0000000..32e4782 --- /dev/null +++ b/src/conf/cards/ENS1370.conf @@ -0,0 +1,107 @@ +# +# Configuration for the ENS1370 chip +# + + + +ENS1370.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + +# default with dmix/dsnoop +ENS1370.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +ENS1370.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface CARD + name "PCM 0 Output also on Line-In Jack" + preserve true + lock true + value true + } + { + name "PCM Switch" + preserve true + lock true + value [ false false ] + } + ] + } +} + + + +ENS1370.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + master 1 + slaves [ + { + pcm { + @func concat + strings [ + "cards.ENS1370.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.ENS1370.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} diff --git a/src/conf/cards/ENS1371.conf b/src/conf/cards/ENS1371.conf new file mode 100644 index 0000000..a6df425 --- /dev/null +++ b/src/conf/cards/ENS1371.conf @@ -0,0 +1,134 @@ +# +# Configuration for the ENS1370 chip +# + + + +ENS1371.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +ENS1371.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +ENS1371.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "AC97 2ch->4ch Copy Switch" + lock true + preserve true + value 0 + } + ] + } +} + + + +ENS1371.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ "cards.ENS1371.pcm.front.0:CARD=" $CARD ] + } + channels 2 + } + { + pcm { + @func concat + strings [ "cards.ENS1371.pcm.rear.0:CARD=" $CARD ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +ENS1371.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/ES1968.conf b/src/conf/cards/ES1968.conf new file mode 100644 index 0000000..a6ee119 --- /dev/null +++ b/src/conf/cards/ES1968.conf @@ -0,0 +1,12 @@ +# configuration for ESS Maestro2 + + + +ES1968.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} diff --git a/src/conf/cards/FM801.conf b/src/conf/cards/FM801.conf new file mode 100644 index 0000000..997b218 --- /dev/null +++ b/src/conf/cards/FM801.conf @@ -0,0 +1,87 @@ +# +# Configuration for the FM801 chip +# + + + +FM801.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +FM801.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +FM801.pcm.surround40.0 "cards.FM801.pcm.front.0" + + + + + +FM801.pcm.surround51.0 "cards.FM801.pcm.front.0" + + + +FM801.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + # { + # name "IEC958 Playback Default" + # value [ $AES0 $AES1 $AES2 $AES3 ] + # } + { + name "IEC958 Raw Data Playback Switch" + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/GUS.conf b/src/conf/cards/GUS.conf new file mode 100644 index 0000000..d744c54 --- /dev/null +++ b/src/conf/cards/GUS.conf @@ -0,0 +1,19 @@ +# +# Configuration for the GUS soundcards +# + + + +GUS.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + slave.pcm { + type hw + card $CARD + } +} diff --git a/src/conf/cards/HDA-Intel.conf b/src/conf/cards/HDA-Intel.conf new file mode 100644 index 0000000..f7eecb4 --- /dev/null +++ b/src/conf/cards/HDA-Intel.conf @@ -0,0 +1,295 @@ +# +# Configuration for the Intel HD audio (ICH6/ICH7) +# + + + +HDA-Intel.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol & dsnoop +HDA-Intel.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + control { + name "Digital Capture Volume" + card $CARD + } + min_dB -30.0 + max_dB 30.0 + resolution 121 + } + # to avoid possible phase inversions with digital mics + route_policy copy + } + hint.device 0 +} + + + + + + + +HDA-Intel.pcm.surround40.0 cards.HDA-Intel.pcm.front.0 +HDA-Intel.pcm.surround51.0 cards.HDA-Intel.pcm.front.0 +HDA-Intel.pcm.surround71.0 cards.HDA-Intel.pcm.front.0 + + + +HDA-Intel.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + value true + } + ] + } + } + capture.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Capture Switch" + lock true + preserve true + value true + } + ] + } + } + hint.device 1 +} + + + +HDA-Intel.pcm.hdmi.common { + @args [ CARD DEVICE CTLINDEX AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.DEVICE { + type integer + } + @args.CTLINDEX { + type integer + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device $DEVICE + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback Default" + index $CTLINDEX + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + index $CTLINDEX + value true + } + ] + } + hint.device $DEVICE +} + +HDA-Intel.pcm.hdmi.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + @func refer + name { + @func concat + strings [ + "cards.HDA-Intel.pcm.hdmi.common:" + "CARD=" $CARD "," + "DEVICE=3," + "CTLINDEX=0," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + +HDA-Intel.pcm.hdmi.1 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + @func refer + name { + @func concat + strings [ + "cards.HDA-Intel.pcm.hdmi.common:" + "CARD=" $CARD "," + "DEVICE=7," + "CTLINDEX=1," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + +HDA-Intel.pcm.hdmi.2 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + @func refer + name { + @func concat + strings [ + "cards.HDA-Intel.pcm.hdmi.common:" + "CARD=" $CARD "," + "DEVICE=8," + "CTLINDEX=2," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + +HDA-Intel.pcm.hdmi.3 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + @func refer + name { + @func concat + strings [ + "cards.HDA-Intel.pcm.hdmi.common:" + "CARD=" $CARD "," + "DEVICE=9," + "CTLINDEX=3," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + + + +HDA-Intel.pcm.modem.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 6 + hint.show off +} diff --git a/src/conf/cards/ICE1712.conf b/src/conf/cards/ICE1712.conf new file mode 100644 index 0000000..01e50d2 --- /dev/null +++ b/src/conf/cards/ICE1712.conf @@ -0,0 +1,141 @@ +# +# Configuration for the ICE1712 (Envy24) chip +# + +# default with dmix & dsnoop +ICE1712.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] + } + } +} + + + +ICE1712.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + slave.pcm { + type hw + card $CARD + } +} + + + +ICE1712.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.2 1 + ttable.3.3 1 + slave.pcm { + type hw + card $CARD + } +} + + + + + +ICE1712.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.2 1 + ttable.3.3 1 + ttable.4.4 1 + ttable.5.5 1 + slave.pcm { + type hw + card $CARD + } +} + + + +ICE1712.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type route + ttable.0.8 1 + ttable.1.9 1 + slave.pcm { + type hw + card $CARD + } + slave.format S32_LE + slave.channels 10 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + capture.pcm { + type route + ttable.0.8 1 + ttable.1.9 1 + slave.pcm { + type hw + card $CARD + } + slave.format S32_LE + slave.channels 12 + } +} diff --git a/src/conf/cards/ICE1724.conf b/src/conf/cards/ICE1724.conf new file mode 100644 index 0000000..e806b36 --- /dev/null +++ b/src/conf/cards/ICE1724.conf @@ -0,0 +1,224 @@ +# +# Configuration for the ICE1724 (Envy24HT) chip +# + +# default with dmix & dsnoop +ICE1724.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] + } + } +} + + + +ICE1724.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +ICE1724.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + subdevice 1 +} + + + +ICE1724.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 +} + + + +ICE1724.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + subdevice 2 +} + + + +ICE1724.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + slave { + channels 6 + pcm { + type hw + card $CARD + } + } +} + + + + + +ICE1724.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + slave { + channels 6 + pcm { + type hw + card $CARD + } + } +} + + + +ICE1724.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + ttable.6.6 1 + ttable.7.7 1 + slave { + channels 8 + pcm { + type hw + card $CARD + } + } +} + + + +ICE1724.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type linear + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Output Switch" + lock true + preserve true + value true + } + { + interface PCM + name "IEC958 Playback Default" + device 1 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + slave.format S32_LE + } + capture.pcm { + type linear + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Capture Switch" + lock true + preserve true + value true + } + ] + } + } + slave.format S32_LE + } +} diff --git a/src/conf/cards/ICH-MODEM.conf b/src/conf/cards/ICH-MODEM.conf new file mode 100644 index 0000000..b96b5aa --- /dev/null +++ b/src/conf/cards/ICH-MODEM.conf @@ -0,0 +1,15 @@ +# +# Configuration for the Intel/AMD modem controllers +# + + + +ICH-MODEM.pcm.modem.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + hint.show off +} diff --git a/src/conf/cards/ICH.conf b/src/conf/cards/ICH.conf new file mode 100644 index 0000000..47ffef9 --- /dev/null +++ b/src/conf/cards/ICH.conf @@ -0,0 +1,222 @@ +# +# Configuration for the Intel ICH/ICH2/ICH3 chips +# + + + +ICH.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol & dsnoop +ICH.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +ICH.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + + + +ICH.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + slave.channels 6 + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +ICH.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 0 + optional true + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/ICH4.conf b/src/conf/cards/ICH4.conf new file mode 100644 index 0000000..1bf5605 --- /dev/null +++ b/src/conf/cards/ICH4.conf @@ -0,0 +1,213 @@ +# +# Configuration for the Intel ICH4/ICH5/ICH6 chips +# + + + +ICH4.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol & dsnoop +ICH4.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +ICH4.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + + + +ICH4.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +ICH4.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 3 + optional true + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/Maestro3.conf b/src/conf/cards/Maestro3.conf new file mode 100644 index 0000000..9432322 --- /dev/null +++ b/src/conf/cards/Maestro3.conf @@ -0,0 +1,38 @@ +# configuration for ESS Maestro3 + + + +Maestro3.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +Maestro3.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + # we need to specify device and subdevice numbers + # for a device with multiple substreams + @func concat + strings [ "dmix:" $CARD ",0,0" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am new file mode 100644 index 0000000..9da78f0 --- /dev/null +++ b/src/conf/cards/Makefile.am @@ -0,0 +1,74 @@ +alsaconfigdir = @ALSA_CONFIG_DIR@ +alsadir = $(alsaconfigdir)/cards +cfg_files = aliases.conf \ + AACI.conf \ + ATIIXP.conf \ + ATIIXP-SPDMA.conf \ + ATIIXP-MODEM.conf \ + AU8810.conf \ + AU8820.conf \ + AU8830.conf \ + Audigy.conf \ + Audigy2.conf \ + Aureon51.conf \ + Aureon71.conf \ + CA0106.conf \ + CMI8338.conf \ + CMI8338-SWIEC.conf \ + CMI8738-MC6.conf \ + CMI8738-MC8.conf \ + CMI8788.conf \ + CS46xx.conf \ + EMU10K1.conf \ + EMU10K1X.conf \ + ENS1370.conf \ + ENS1371.conf \ + ES1968.conf \ + FM801.conf \ + GUS.conf \ + HDA-Intel.conf \ + ICE1712.conf \ + ICE1724.conf \ + ICH.conf \ + ICH4.conf \ + ICH-MODEM.conf \ + Maestro3.conf \ + NFORCE.conf \ + PC-Speaker.conf \ + PMac.conf \ + PMacToonie.conf \ + PS3.conf \ + RME9636.conf \ + RME9652.conf \ + SI7018.conf \ + SB-XFi.conf \ + TRID4DWAVENX.conf \ + USB-Audio.conf \ + YMF744.conf \ + VIA686A.conf \ + VIA8233.conf \ + VIA8233A.conf \ + VIA8237.conf \ + VX222.conf \ + VXPocket.conf \ + VXPocket440.conf + +if BUILD_ALISP +cfg_files += aliases.alisp +endif + +alsa_DATA = $(cfg_files) + +if BUILD_ALISP +SI7018dir = $(alsaconfigdir)/cards/SI7018 +SI7018_files = \ + SI7018/sndoc-mixer.alisp \ + SI7018/sndop-mixer.alisp +SI7018_DATA = $(SI7018_files) +else +SI7018_files= +endif + +EXTRA_DIST = \ + $(cfg_files) \ + $(SI7018_files) diff --git a/src/conf/cards/Makefile.in b/src/conf/cards/Makefile.in new file mode 100644 index 0000000..f3b9a37 --- /dev/null +++ b/src/conf/cards/Makefile.in @@ -0,0 +1,464 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_ALISP_TRUE@am__append_1 = aliases.alisp +subdir = src/conf/cards +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(SI7018dir)" "$(DESTDIR)$(alsadir)" +DATA = $(SI7018_DATA) $(alsa_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +alsaconfigdir = @ALSA_CONFIG_DIR@ +alsadir = $(alsaconfigdir)/cards +cfg_files = aliases.conf AACI.conf ATIIXP.conf ATIIXP-SPDMA.conf \ + ATIIXP-MODEM.conf AU8810.conf AU8820.conf AU8830.conf \ + Audigy.conf Audigy2.conf Aureon51.conf Aureon71.conf \ + CA0106.conf CMI8338.conf CMI8338-SWIEC.conf CMI8738-MC6.conf \ + CMI8738-MC8.conf CMI8788.conf CS46xx.conf EMU10K1.conf \ + EMU10K1X.conf ENS1370.conf ENS1371.conf ES1968.conf FM801.conf \ + GUS.conf HDA-Intel.conf ICE1712.conf ICE1724.conf ICH.conf \ + ICH4.conf ICH-MODEM.conf Maestro3.conf NFORCE.conf \ + PC-Speaker.conf PMac.conf PMacToonie.conf PS3.conf \ + RME9636.conf RME9652.conf SI7018.conf SB-XFi.conf \ + TRID4DWAVENX.conf USB-Audio.conf YMF744.conf VIA686A.conf \ + VIA8233.conf VIA8233A.conf VIA8237.conf VX222.conf \ + VXPocket.conf VXPocket440.conf $(am__append_1) +alsa_DATA = $(cfg_files) +@BUILD_ALISP_TRUE@SI7018dir = $(alsaconfigdir)/cards/SI7018 +@BUILD_ALISP_FALSE@SI7018_files = +@BUILD_ALISP_TRUE@SI7018_files = \ +@BUILD_ALISP_TRUE@ SI7018/sndoc-mixer.alisp \ +@BUILD_ALISP_TRUE@ SI7018/sndop-mixer.alisp + +@BUILD_ALISP_TRUE@SI7018_DATA = $(SI7018_files) +EXTRA_DIST = \ + $(cfg_files) \ + $(SI7018_files) + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/conf/cards/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/conf/cards/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-SI7018DATA: $(SI7018_DATA) + @$(NORMAL_INSTALL) + test -z "$(SI7018dir)" || $(MKDIR_P) "$(DESTDIR)$(SI7018dir)" + @list='$(SI7018_DATA)'; test -n "$(SI7018dir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(SI7018dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(SI7018dir)" || exit $$?; \ + done + +uninstall-SI7018DATA: + @$(NORMAL_UNINSTALL) + @list='$(SI7018_DATA)'; test -n "$(SI7018dir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(SI7018dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(SI7018dir)" && rm -f $$files +install-alsaDATA: $(alsa_DATA) + @$(NORMAL_INSTALL) + test -z "$(alsadir)" || $(MKDIR_P) "$(DESTDIR)$(alsadir)" + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(alsadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(alsadir)" || exit $$?; \ + done + +uninstall-alsaDATA: + @$(NORMAL_UNINSTALL) + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(alsadir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(alsadir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(SI7018dir)" "$(DESTDIR)$(alsadir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-SI7018DATA install-alsaDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-SI7018DATA uninstall-alsaDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-SI7018DATA \ + install-alsaDATA install-am install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am uninstall uninstall-SI7018DATA uninstall-alsaDATA \ + uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/conf/cards/NFORCE.conf b/src/conf/cards/NFORCE.conf new file mode 100644 index 0000000..6ebefe3 --- /dev/null +++ b/src/conf/cards/NFORCE.conf @@ -0,0 +1,295 @@ +# +# Configuration for the nVIDIA nForce/2/3 +# + + + +NFORCE.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol & dsnoop +NFORCE.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +NFORCE.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + + + +NFORCE.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + slave.channels 6 + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +NFORCE.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + ttable.6.6 1 + ttable.7.7 1 + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 0 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "8ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + slave.channels 8 + } + control { + name "PCM Playback Volume" + card $CARD + } +} + + + +NFORCE.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 0 + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/PC-Speaker.conf b/src/conf/cards/PC-Speaker.conf new file mode 100644 index 0000000..c82654d --- /dev/null +++ b/src/conf/cards/PC-Speaker.conf @@ -0,0 +1,52 @@ +# +# Configuration for PC-Speaker driver +# + + + +PC-Speaker.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "Master Playback Volume" + card $CARD + } + min_dB -10.0 + max_dB 20.0 +} + +# default with dmix & null +PC-Speaker.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + control { + name "Master Playback Volume" + card $CARD + } + min_dB -10.0 + max_dB 20.0 + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + } + capture.pcm { + type null + } +} + diff --git a/src/conf/cards/PMac.conf b/src/conf/cards/PMac.conf new file mode 100644 index 0000000..d1fdb17 --- /dev/null +++ b/src/conf/cards/PMac.conf @@ -0,0 +1,37 @@ +# +# Configuration for PMac +# + + + +PMac.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +PMac.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:CARD=" $CARD ",FORMAT=S16_BE" ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:CARD=" $CARD ",FORMAT=S16_BE" ] + } + } +} diff --git a/src/conf/cards/PMacToonie.conf b/src/conf/cards/PMacToonie.conf new file mode 100644 index 0000000..1e0eb59 --- /dev/null +++ b/src/conf/cards/PMacToonie.conf @@ -0,0 +1,51 @@ +# +# Configuration for PMac Toonie +# + + + +PMacToonie.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol & dsnoop +PMacToonie.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + strings [ "dmix:CARD=" $CARD ",FORMAT=S16_BE" ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:CARD=" $CARD ",FORMAT=S16_BE" ] + } + } +} diff --git a/src/conf/cards/PS3.conf b/src/conf/cards/PS3.conf new file mode 100644 index 0000000..b642f0d --- /dev/null +++ b/src/conf/cards/PS3.conf @@ -0,0 +1,85 @@ +# +# Configuration for PS3 +# + + + +PS3.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type softvol + slave.pcm { + type hw + card $CARD + device 0 + } + control { + name "PCM Playback Volume" + card $CARD + } +} + +# default with dmix+softvol +PS3.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + @func concat + #strings [ "dmix:CARD=" $CARD ] + strings [ "dmix:CARD=" $CARD ",FORMAT=S16" ] + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } +} + + + +PS3.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/RME9636.conf b/src/conf/cards/RME9636.conf new file mode 100644 index 0000000..e8dc5fa --- /dev/null +++ b/src/conf/cards/RME9636.conf @@ -0,0 +1,61 @@ +# +# Configuration for the RME9636 +# + + + +RME9636.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# FIXME: This configuration is not valid for double-speed rates. + + + +RME9636.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type route + slave { + pcm { + type hw + card $CARD + } + channels 18 + } + ttable.0.16 1 + ttable.1.17 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + lock true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/RME9652.conf b/src/conf/cards/RME9652.conf new file mode 100644 index 0000000..1147d81 --- /dev/null +++ b/src/conf/cards/RME9652.conf @@ -0,0 +1,61 @@ +# +# Configuration for the RME9652 +# + + + +RME9652.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# FIXME: This configuration is not valid for double-speed rates. + + + +RME9652.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type route + slave { + pcm { + type hw + card $CARD + } + channels 26 + } + ttable.0.24 1 + ttable.1.25 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + lock true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/SB-XFi.conf b/src/conf/cards/SB-XFi.conf new file mode 100644 index 0000000..38d0027 --- /dev/null +++ b/src/conf/cards/SB-XFi.conf @@ -0,0 +1,108 @@ +# +# Configuration for the SB X-Fi driver +# + + + +SB-XFi.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 0 +} + + + +SB-XFi.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 + hint.device 1 +} + + + +SB-XFi.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + hint.device 2 +} + + + +SB-XFi.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 3 + hint.device 3 +} + + + + + + + +SB-XFi.pcm.surround40.0 cards.SB-XFi.pcm.front.0 +SB-XFi.pcm.surround51.0 cards.SB-XFi.pcm.front.0 +SB-XFi.pcm.surround71.0 cards.SB-XFi.pcm.front.0 + + + +SB-XFi.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + device 4 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + hint.device 4 +} diff --git a/src/conf/cards/SI7018.conf b/src/conf/cards/SI7018.conf new file mode 100644 index 0000000..15972a4 --- /dev/null +++ b/src/conf/cards/SI7018.conf @@ -0,0 +1,166 @@ +# +# Configuration for the SI7018 chip +# +# This configuration does not reflect hardware. +# + + + +SI7018.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +SI7018.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "PCM Playback Volume" + preserve true + lock true + value [ 24 24 ] + } + ] + } +} + + + +SI7018.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.SI7018.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.SI7018.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + + + +SI7018.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.SI7018.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.SI7018.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.SI7018.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + { slave 2 channel 0 } + { slave 2 channel 1 } + ] +} + + + +SI7018.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + value [ $AES0 $AES1 $AES2 $AES3 ] + device 1 + lock true + preserve true + } + ] + } +} diff --git a/src/conf/cards/SI7018/sndoc-mixer.alisp b/src/conf/cards/SI7018/sndoc-mixer.alisp new file mode 100644 index 0000000..ade1ea3 --- /dev/null +++ b/src/conf/cards/SI7018/sndoc-mixer.alisp @@ -0,0 +1,11 @@ +; +; SiS SI7018 mixer abstract layer +; +; Copyright (c) 2003 Jaroslav Kysela +; License: GPL v2 (http://www.gnu.org/licenses/gpl.html) +; + +(defun sndoc_mixer_open (hctl pcm) + (princ "sndoc_mixer_open: hctl=" hctl " pcm=" pcm "\n") + 0 +) diff --git a/src/conf/cards/SI7018/sndop-mixer.alisp b/src/conf/cards/SI7018/sndop-mixer.alisp new file mode 100644 index 0000000..285e289 --- /dev/null +++ b/src/conf/cards/SI7018/sndop-mixer.alisp @@ -0,0 +1,11 @@ +; +; SiS SI7018 mixer abstract layer +; +; Copyright (c) 2003 Jaroslav Kysela +; License: GPL v2 (http://www.gnu.org/licenses/gpl.html) +; + +(defun sndop_mixer_open (hctl pcm) + (princ "sndop_mixer_open: hctl=" hctl " pcm=" pcm "\n") + 0 +) diff --git a/src/conf/cards/TRID4DWAVENX.conf b/src/conf/cards/TRID4DWAVENX.conf new file mode 100644 index 0000000..bbf6b7c --- /dev/null +++ b/src/conf/cards/TRID4DWAVENX.conf @@ -0,0 +1,129 @@ +# +# Configuration for the Trident 4D-Wave NX chip +# + + + +TRID4DWAVENX.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +TRID4DWAVENX.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Rear Path" + lock true + preserve true + value true + } + { + name "PCM Front Playback Volume" + index { @func private_pcm_subdevice } + lock true + preserve true + value 0 + } + { + name "PCM Reverb Playback Volume" + index { @func private_pcm_subdevice } + lock true + preserve true + value 127 + } + ] + } +} + + + +TRID4DWAVENX.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.TRID4DWAVENX.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.TRID4DWAVENX.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +TRID4DWAVENX.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 2 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + value [ $AES0 $AES1 $AES2 $AES3 ] + device 2 + lock true + preserve true + } + ] + } +} diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf new file mode 100644 index 0000000..0726c34 --- /dev/null +++ b/src/conf/cards/USB-Audio.conf @@ -0,0 +1,375 @@ +# +# USB-Audio.conf - configuration for USB Audio devices +# +# +# DO NO EDIT; this is an internal ALSA file. +# If you want to add your own definitions, put them into /etc/asound.conf or +# ~/.asoundrc, with "cards." before the "USB-Audio", e.g.: +# +# cards.USB-Audio.pcm.use_dmix."NoiseBlaster 3000" no +# +# If your device requires such a definition to work correctly, please report it +# to . + + +# If a device has sample formats not supported by dmix, dmix can be disabled +# here. +USB-Audio.pcm.use_dmix { + "AudioPhile" no # uses big-endian 24-bit samples + "Audiophile USB (tm)" no +} + +# If a device does not have a four-channel mode for the front/rear outputs, +# other modes can be selected here. +# six_channels - for devices that route the last two of the four channels +# to the center/LFE outputs +# two_stereo_devices - for devices that have two stereo audio interfaces +USB-Audio.pcm.surround40_type { + "AudioPhile" two_stereo_devices + "Audiophile USB (tm)" two_stereo_devices + "OmniStudio" two_stereo_devices + "Quattro" two_stereo_devices + "SB Audigy 2 NX" six_channels +} + +# If a device does not use the first PCM device for digital data, the device +# number for the iec958 device can be changed here. +USB-Audio.pcm.iec958_device { + # "NoiseBlaster 3000" 42 +} + + +# If a device requires non-standard definitions for front, surround40, +# surround51, surround71 or iec958, they can be defined here. + +# M-Audio AudioPhile USB: +# device 0: analog output, digital input +# device 1: digital output, analog input +USB-Audio."AudioPhile".pcm.default "cards.USB-Audio.Audiophile USB (tm).pcm.default" +USB-Audio."Audiophile USB (tm)".pcm.default { + @args [ CARD ] + @args.CARD { type string } + type asym + playback.pcm { + type plug + slave.pcm { + type hw + card $CARD + device 0 + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:DEVICE=1,CARD=" $CARD ] + } + } +} +USB-Audio."AudioPhile".pcm.iec958 "cards.USB-Audio.Audiophile USB (tm).pcm.iec958" +USB-Audio."Audiophile USB (tm)".pcm.iec958 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + type asym + playback.pcm { + type hw + card $CARD + device 1 + } + capture.pcm { + type hw + card $CARD + device 0 + } +} + + +################################################################################ + + + +USB-Audio.pcm.front.0 { + @args [ CARD ] + @args.CARD { type string } + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.front:CARD=" $CARD + ] + } + default { + # We could use softvol, but the driver might have guessed a + # wrong name for the real volume control. + type hw + card $CARD + device 0 + } +} + +USB-Audio.pcm.default { + @args [ CARD ] + @args.CARD { type string } + type asym + playback.pcm { + type plug + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.default_playback_dmix_" + { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.use_dmix." + { @func card_name card $CARD } + ] + } + default yes + } + ":CARD=" $CARD + ] + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + +USB-Audio.pcm.default_playback_dmix_yes { + @args [ CARD ] + @args.CARD { type string } + @func concat + strings [ "dmix:" $CARD ] +} + +USB-Audio.pcm.default_playback_dmix_no { + @args [ CARD ] + @args.CARD { type string } + type hw + card $CARD + device 0 +} + + + +USB-Audio.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { type string } + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.surround40:CARD=" $CARD + ] + } + default { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.surround40_" + { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.surround40_type." + { @func card_name card $CARD } + ] + } + default default + } + ":CARD=" $CARD + ] + } + } +} + +USB-Audio.pcm.surround40_default { + @args [ CARD ] + @args.CARD { type string } + type hw + card $CARD + device 0 +} + +USB-Audio.pcm.surround40_six_channels { + @args [ CARD ] + @args.CARD { type string } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + slave { + pcm { + type hw + card $CARD + device 0 + } + channels 6 + } +} + +USB-Audio.pcm.surround40_two_stereo_devices { + @args [ CARD ] + @args.CARD { type string } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.2 1 + ttable.3.3 1 + slave.pcm { + type multi + slaves { + a { + pcm { + type hw + card $CARD + device 0 + } + channels 2 + } + b { + pcm { + type hw + card $CARD + device 1 + } + channels 2 + } + } + bindings [ + { slave a channel 0 } + { slave a channel 1 } + { slave b channel 0 } + { slave b channel 1 } + ] + } +} + + + + + +USB-Audio.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { type string } + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.surround51:CARD=" $CARD + ] + } + default { + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + slave { + pcm { + type hw + card $CARD + device 0 + } + channels 6 + } + } +} + + + +USB-Audio.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { type string } + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.surround71:CARD=" $CARD + ] + } + default { + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + ttable.6.6 1 + ttable.7.7 1 + slave { + pcm { + type hw + card $CARD + device 0 + } + channels 8 + } + } +} + + + +USB-Audio.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.iec958:CARD=" $CARD + ",AES0=" $AES0 ",AES1=" $AES1 ",AES2=" $AES2 ",AES3=" $AES3 + ] + } + default { + # FIXME: we cannot set the AES parameters + type hw + card $CARD + device { + @func refer + name { + @func concat + strings [ + "cards.USB-Audio.pcm.iec958_device." + { @func card_name card $CARD } + ] + } + default 0 + } + } +} + +# vim: ft=alsaconf diff --git a/src/conf/cards/VIA686A.conf b/src/conf/cards/VIA686A.conf new file mode 100644 index 0000000..e4a06f2 --- /dev/null +++ b/src/conf/cards/VIA686A.conf @@ -0,0 +1,89 @@ +# +# Configuration for the VIA686A chip +# +# SPDIF support is not complete - it might not work, especially with AC3 +# passthru mode... +# + + + +VIA686A.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +VIA686A.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +VIA686A.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 0 + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/VIA8233.conf b/src/conf/cards/VIA8233.conf new file mode 100644 index 0000000..668bfd9 --- /dev/null +++ b/src/conf/cards/VIA8233.conf @@ -0,0 +1,200 @@ +# +# Configuration for the VIA8233/VIA8233C/VIA8235 chip with 4/6 multi-channel support +# + + + +VIA8233.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with softvol/dsnoop +# VIA8233 supports multi-playback +VIA8233.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +VIA8233.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + + + +VIA8233.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + +VIA8233.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + subdevice 3 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 3 + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + { + name "IEC958 Output Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/VIA8233A.conf b/src/conf/cards/VIA8233A.conf new file mode 100644 index 0000000..97d2a7d --- /dev/null +++ b/src/conf/cards/VIA8233A.conf @@ -0,0 +1,204 @@ +# +# Configuration for the VIA8233A chip with 4/6 multi-channel support +# + + + +VIA8233A.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix/dsnoop +VIA8233A.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +VIA8233A.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Swap Surround Slot" + lock true + preserve true + value false + optional true + } + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + + + +VIA8233A.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Swap Surround Slot" + lock true + preserve true + value true + optional true + } + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + # for old drivers + { + name "Line-In As Surround" + preserve true + value true + optional true + } + { + name "Mic As Center/LFE" + preserve true + value true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + +VIA8233A.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 3 + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + { + name "IEC958 Output Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/VIA8237.conf b/src/conf/cards/VIA8237.conf new file mode 100644 index 0000000..404e190 --- /dev/null +++ b/src/conf/cards/VIA8237.conf @@ -0,0 +1,190 @@ +# +# Configuration for the VIA8237 chip with 4/6 multi-channel support +# + + + +VIA8237.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with softvol/dsnoop +# VIA8237 supports multi-playback +VIA8237.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + type softvol + slave.pcm { + type hw + card $CARD + } + control { + name "PCM Playback Volume" + card $CARD + } + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:" $CARD ] + } + } +} + + + +VIA8237.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "4ch" + lock true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + ] + } +} + + + + + +VIA8237.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable.0.0 1 + ttable.1.1 1 + ttable.2.4 1 + ttable.3.5 1 + ttable.4.2 1 + ttable.5.3 1 + slave.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 1 + channels 6 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Channel Mode" + preserve true + value "6ch" + lock true + optional true + } + { + name "Surround Down Mix" + preserve true + value off + lock true + optional true + } + { + name "Center/LFE Down Mix" + preserve true + value off + lock true + optional true + } + ] + } + } + slave.channels 6 +} + + + +VIA8237.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + subdevice 3 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback AC97-SPSA" + lock true + preserve true + value 3 + } + { + name "IEC958 Playback Default" + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value true + } + { + name "IEC958 Output Switch" + lock true + preserve true + value true + } + ] + } +} diff --git a/src/conf/cards/VX222.conf b/src/conf/cards/VX222.conf new file mode 100644 index 0000000..3385f25 --- /dev/null +++ b/src/conf/cards/VX222.conf @@ -0,0 +1,61 @@ +# +# Configuration for Digigram VX222 +# + + + +VX222.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +VX222.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/VXPocket.conf b/src/conf/cards/VXPocket.conf new file mode 100644 index 0000000..fe44ff5 --- /dev/null +++ b/src/conf/cards/VXPocket.conf @@ -0,0 +1,61 @@ +# +# Configuration for Digigram VXpocket +# + + + +VXPocket.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +VXPocket.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/VXPocket440.conf b/src/conf/cards/VXPocket440.conf new file mode 100644 index 0000000..197c2d6 --- /dev/null +++ b/src/conf/cards/VXPocket440.conf @@ -0,0 +1,110 @@ +# +# Configuration for Digigram VXpocket440 +# + + + +VXPocket440.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +VXPocket440.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 +} + + + +VXPocket440.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + master 1 + slaves [ + { + pcm { + @func concat + strings [ + "cards.VXPocket440.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.VXPocket440.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +VXPocket440.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + # for compatibility with older drivers + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/YMF744.conf b/src/conf/cards/YMF744.conf new file mode 100644 index 0000000..84dbcbe --- /dev/null +++ b/src/conf/cards/YMF744.conf @@ -0,0 +1,108 @@ +# +# Configuration for the YMF744 chip +# + + + +YMF744.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + +YMF744.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 +} + + + +YMF744.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.YMF744.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.YMF744.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + + +YMF744.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "IEC958 Playback Switch" + lock true + preserve true + value 1 + } + { + interface PCM + name "IEC958 Playback PCM Stream" + device 1 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/aliases.alisp b/src/conf/cards/aliases.alisp new file mode 100644 index 0000000..1661caa --- /dev/null +++ b/src/conf/cards/aliases.alisp @@ -0,0 +1,29 @@ +(setq snd_card_aliases_array + ( + ("YMF724" . "YMF744") + ("YMF724F" . "YMF744") + ("YMF740" . "YMF744") + ("YMF740C" . "YMF744") + ("YMF754" . "YMF744") + ("CMIPCI" . "CMI8338") + ("CMI8738" . "CMI8338") + ("CMI8738-MC4" . "CMI8738-MC6") + ("E-mu APS" . "EMU10K1") + ("GUS Max" . "GUS") + ("GUS ACE" . "GUS") + ("GUS Extreme" . "GUS") + ("AMD InterWave" . "GUS") + ("Dynasonic 3-D" . "GUS") + ("InterWave STB" . "GUS") + ) +) + +(defun snd_card_alias (cardname) + (setq r (assq cardname snd_card_aliases_array)) + (setq r (if (null r) cardname r)) + (unsetq r) +) + +(defun snd_card_alias_unset () + (unsetq snd_card_aliases_array snd_card_alias) +) diff --git a/src/conf/cards/aliases.conf b/src/conf/cards/aliases.conf new file mode 100644 index 0000000..4a92fb2 --- /dev/null +++ b/src/conf/cards/aliases.conf @@ -0,0 +1,61 @@ +# +# Define aliases for various drivers +# + +YMF724 cards.YMF744 +YMF724F cards.YMF744 +YMF740 cards.YMF744 +YMF740C cards.YMF744 +YMF754 cards.YMF744 +CMIPCI cards.CMI8338 +CMI8738 cards.CMI8338 +CMI8738-SWIEC cards.CMI8338-SWIEC +CMI8738-MC4 cards.CMI8738-MC6 +'E-mu APS' cards.EMU10K1 +'GUS MAX' cards.GUS +'GUS ACE' cards.GUS +'GUS Extreme' cards.GUS +'AMD InterWave' cards.GUS +'Dynasonic 3-D' cards.GUS +'InterWave STB' cards.GUS +au8810 cards.AU8810 +au8820 cards.AU8820 +au8830 cards.AU8830 +Prodigy71 cards.Aureon71 +Prodigy71LT cards.Aureon71 +Prodigy71HIFI cards.Aureon71 +Aureon71Univ cards.Aureon71 +VIA82XX-MODEM cards.ICH-MODEM +'MPU-401 UART' cards.MPU-401 +'VX222/Old' cards.VX222 +'VX222/v2' cards.VX222 +'VX222/Mic' cards.VX222 +'CMI8330/C3D' cards.CMI8330 +'SB AWE' cards.SBAWE +'SB Pro' cards.SBPro +'PMac Burgundy' cards.PMac +'PMac DACA' cards.PMac +'PMac Tumbler' cards.PMac +'PMac Snapper' cards.PMac +'PMac Screamer' cards.PMac +'PMac AWACS' cards.PMac +'PMac Toonie' cards.PMacToonie +AppleOnbdAudio cards.PMacToonie +'USB US-X2Y' cards.US-X2Y +'Serial MIDI' cards.SerialMIDI +'Prodif Plus' cards.ProdifPlus +ESM1 cards.ES1968 +ES1978 cards.ES1968 +Allegro cards.Maestro3 +Canyon3D-2 cards.Maestro3 +Azalia cards.HDA-Intel +aaci-pl041 cards.AACI +AV66 cards.CMI8788 +AV100 cards.CMI8788 +AV200 cards.CMI8788 +CMI8786 cards.CMI8788 +CMI8787 cards.CMI8788 + + + + diff --git a/src/conf/pcm/Makefile.am b/src/conf/pcm/Makefile.am new file mode 100644 index 0000000..cc3286e --- /dev/null +++ b/src/conf/pcm/Makefile.am @@ -0,0 +1,12 @@ +cfg_files = default.conf front.conf rear.conf center_lfe.conf side.conf\ + surround40.conf surround41.conf \ + surround50.conf surround51.conf \ + surround71.conf iec958.conf hdmi.conf modem.conf \ + dmix.conf dsnoop.conf \ + dpl.conf + +EXTRA_DIST = $(cfg_files) + +alsaconfigdir = @ALSA_CONFIG_DIR@ +alsadir = $(alsaconfigdir)/pcm +alsa_DATA = $(cfg_files) diff --git a/src/conf/pcm/Makefile.in b/src/conf/pcm/Makefile.in new file mode 100644 index 0000000..efa47e9 --- /dev/null +++ b/src/conf/pcm/Makefile.in @@ -0,0 +1,426 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/conf/pcm +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(alsadir)" +DATA = $(alsa_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +cfg_files = default.conf front.conf rear.conf center_lfe.conf side.conf\ + surround40.conf surround41.conf \ + surround50.conf surround51.conf \ + surround71.conf iec958.conf hdmi.conf modem.conf \ + dmix.conf dsnoop.conf \ + dpl.conf + +EXTRA_DIST = $(cfg_files) +alsaconfigdir = @ALSA_CONFIG_DIR@ +alsadir = $(alsaconfigdir)/pcm +alsa_DATA = $(cfg_files) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/conf/pcm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/conf/pcm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-alsaDATA: $(alsa_DATA) + @$(NORMAL_INSTALL) + test -z "$(alsadir)" || $(MKDIR_P) "$(DESTDIR)$(alsadir)" + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(alsadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(alsadir)" || exit $$?; \ + done + +uninstall-alsaDATA: + @$(NORMAL_UNINSTALL) + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(alsadir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(alsadir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(alsadir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-alsaDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-alsaDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-alsaDATA \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-alsaDATA uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/conf/pcm/center_lfe.conf b/src/conf/pcm/center_lfe.conf new file mode 100644 index 0000000..4ef6f49 --- /dev/null +++ b/src/conf/pcm/center_lfe.conf @@ -0,0 +1,58 @@ +# +# Hardware output from center & lfe speakers +# + +pcm.!center_lfe { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_CENTER_LFE_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.center_lfe.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_CENTER_LFE_DEVICE + ] + default { + @func refer + name defaults.pcm.center_lfe.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.center_lfe." $DEV ":CARD=" $CARD + ] + } + } + hint { + show { + @func refer + name defaults.namehint.basic + } + description "Center and Subwoofer speakers" + device $DEV + } +} diff --git a/src/conf/pcm/default.conf b/src/conf/pcm/default.conf new file mode 100644 index 0000000..864a903 --- /dev/null +++ b/src/conf/pcm/default.conf @@ -0,0 +1,57 @@ +# +# Default output +# + +pcm.!default { + @args [ CARD ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.card + } + } + } + type empty + slave.pcm { + # use card-specific definition if exists + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.default:CARD=" $CARD + ] + } + default { + # use plughw as default + type plug + slave.pcm { + type hw + card $CARD + } + hint.device 0 + } + } + hint { + description "Default Audio Device" + device_output { + @func refer + name defaults.pcm.dmix.device + } + device_input { + @func refer + name defaults.pcm.dsnoop.device + } + } +} diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf new file mode 100644 index 0000000..e62cb29 --- /dev/null +++ b/src/conf/pcm/dmix.conf @@ -0,0 +1,115 @@ +# +# dmix output +# + +pcm.!dmix { + @args [ CARD DEV SUBDEV FORMAT RATE ] + @args.CARD { + type string + default { + @func refer + name defaults.pcm.dmix.card + } + } + @args.DEV { + type integer + default { + @func refer + name defaults.pcm.dmix.device + } + } + @args.SUBDEV { + type integer + default 0 + } + @args.FORMAT { + type string + default { + @func refer + name defaults.pcm.dmix.format + } + } + @args.RATE { + type integer + default { + @func refer + name defaults.pcm.dmix.rate + } + } + type dmix + ipc_key { + @func refer + name defaults.pcm.ipc_key + } + ipc_gid { + @func refer + name defaults.pcm.ipc_gid + } + ipc_perm { + @func refer + name defaults.pcm.ipc_perm + } + slave { + pcm { + type hw + card $CARD + device $DEV + subdevice $SUBDEV + } + format $FORMAT + rate $RATE + period_size { + @func refer + name { + @func concat + strings [ + "defaults.dmix." + { + @func card_driver + card $CARD + } + ".period_size" + ] + } + default 1024 + } + period_time { + @func refer + name { + @func concat + strings [ + "defaults.dmix." + { + @func card_driver + card $CARD + } + ".period_time" + ] + } + default -1 + } + periods { + @func refer + name { + @func concat + strings [ + "defaults.dmix." + { + @func card_driver + card $CARD + } + ".periods" + ] + } + default 16 + } + } + hint { + show { + @func refer + name defaults.namehint.extended + } + description "Direct sample mixing device" + device $DEV + } +} diff --git a/src/conf/pcm/dpl.conf b/src/conf/pcm/dpl.conf new file mode 100644 index 0000000..1009bb3 --- /dev/null +++ b/src/conf/pcm/dpl.conf @@ -0,0 +1,43 @@ +pcm.!dpl { + @args [ SLAVE ] + @args.SLAVE { + type string + } + type route + slave.pcm $SLAVE + slave.channels 2 + # input: FL/FR/SL/SR/C/LFE + # S=SL+SR, LFE not used + ttable.0.0 1 + ttable.1.1 1 + ttable.2.0 0.707 + ttable.2.1 -0.707 + ttable.3.0 0.707 + ttable.3.1 -0.707 + ttable.4.0 0.707 + ttable.4.1 0.707 + ttable.5.0 0 + ttable.5.1 0 +} + +pcm.!dpl2 { + @args [SLAVE] + @args.SLAVE { + type string + } + type route + slave.pcm $SLAVE + slave.channels 2 + # input: FL/FR/SL/SR/C/LFE + # LFE not used + ttable.0.0 1 + ttable.1.1 1 + ttable.2.0 0.866 + ttable.2.1 -0.5 + ttable.3.0 0.5 + ttable.3.1 -0.866 + ttable.4.0 0.707 + ttable.4.1 0.707 + ttable.5.0 0 + ttable.5.1 0 +} diff --git a/src/conf/pcm/dsnoop.conf b/src/conf/pcm/dsnoop.conf new file mode 100644 index 0000000..49cfca9 --- /dev/null +++ b/src/conf/pcm/dsnoop.conf @@ -0,0 +1,115 @@ +# +# dsnoop +# + +pcm.!dsnoop { + @args [ CARD DEV SUBDEV FORMAT RATE ] + @args.CARD { + type string + default { + @func refer + name defaults.pcm.dsnoop.card + } + } + @args.DEV { + type integer + default { + @func refer + name defaults.pcm.dsnoop.device + } + } + @args.SUBDEV { + type integer + default 0 + } + @args.FORMAT { + type string + default { + @func refer + name defaults.pcm.dmix.format + } + } + @args.RATE { + type integer + default { + @func refer + name defaults.pcm.dmix.rate + } + } + type dsnoop + ipc_key { + @func refer + name defaults.pcm.ipc_key + } + ipc_gid { + @func refer + name defaults.pcm.ipc_gid + } + ipc_perm { + @func refer + name defaults.pcm.ipc_perm + } + slave { + pcm { + type hw + card $CARD + device $DEV + subdevice $SUBDEV + } + format $FORMAT + rate $RATE + period_size { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.dsnoop.period_size" + ] + } + default 1024 + } + period_time { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.dsnoop.period_time" + ] + } + default -1 + } + periods { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.dsnoop.periods" + ] + } + default 16 + } + } + hint { + show { + @func refer + name defaults.namehint.extended + } + description "Direct sample snooping device" + device $DEV + } +} diff --git a/src/conf/pcm/front.conf b/src/conf/pcm/front.conf new file mode 100644 index 0000000..7aff0cb --- /dev/null +++ b/src/conf/pcm/front.conf @@ -0,0 +1,58 @@ +# +# Hardware output from front speakers +# + +pcm.!front { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_FRONT_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.front.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_FRONT_DEVICE + ] + default { + @func refer + name defaults.pcm.front.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.front." $DEV ":CARD=" $CARD + ] + } + } + hint { + show { + @func refer + name defaults.namehint.basic + } + description "Front speakers" + device $DEV + } +} diff --git a/src/conf/pcm/hdmi.conf b/src/conf/pcm/hdmi.conf new file mode 100644 index 0000000..aad7065 --- /dev/null +++ b/src/conf/pcm/hdmi.conf @@ -0,0 +1,83 @@ +# +# Hardware output from HDMI +# + +pcm.!hdmi { + @args [ CARD DEV AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_IEC958_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.iec958.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_IEC958_DEVICE + ] + default { + @func refer + name defaults.pcm.iec958.device + } + } + } + @args.AES0 { + type integer + # consumer, not-copyright, emphasis-none, mode=0 + default 0x04 + } + @args.AES1 { + type integer + # original, PCM coder + default 0x82 + } + @args.AES2 { + type integer + # source and channel + default 0x00 + } + @args.AES3 { + type integer + # fs=48000Hz, clock accuracy=1000ppm + default 0x02 + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.hdmi." $DEV ":" + "CARD=" $CARD "," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } + } + hint { + show { + @func refer + name defaults.namehint.basic + } + description "HDMI Audio Output" + device $DEV + } +} diff --git a/src/conf/pcm/iec958.conf b/src/conf/pcm/iec958.conf new file mode 100644 index 0000000..ac139b5 --- /dev/null +++ b/src/conf/pcm/iec958.conf @@ -0,0 +1,83 @@ +# +# Hardware output from iec958 +# + +pcm.!iec958 { + @args [ CARD DEV AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_IEC958_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.iec958.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_IEC958_DEVICE + ] + default { + @func refer + name defaults.pcm.iec958.device + } + } + } + @args.AES0 { + type integer + # consumer, not-copyright, emphasis-none, mode=0 + default 0x04 + } + @args.AES1 { + type integer + # original, PCM coder + default 0x82 + } + @args.AES2 { + type integer + # source and channel + default 0x00 + } + @args.AES3 { + type integer + # fs=48000Hz, clock accuracy=1000ppm + default 0x02 + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.iec958." $DEV ":" + "CARD=" $CARD "," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } + } + hint { + show { + @func refer + name defaults.namehint.basic + } + description "IEC958 (S/PDIF) Digital Audio Output" + device $DEV + } +} diff --git a/src/conf/pcm/modem.conf b/src/conf/pcm/modem.conf new file mode 100644 index 0000000..0af0e72 --- /dev/null +++ b/src/conf/pcm/modem.conf @@ -0,0 +1,106 @@ +# +# "raw" modem - phoneline +# + +pcm.!phoneline { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_MODEM_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.modem.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_MODEM_DEVICE + ] + default { + @func refer + name defaults.pcm.modem.device + } + } + } + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.modem." $DEV ":CARD=" $CARD + ] + } + hint.show off +} + +# +# "autohooked" modem +# + +pcm.!modem { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_MODEM_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.modem.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_MODEM_DEVICE + ] + default { + @func refer + name defaults.pcm.modem.device + } + } + } + type hooks + slave { + pcm { + @func concat + strings [ + "cards.pcm.phoneline:CARD=" $CARD ",DEV=" $DEV + ] + } + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Off-hook Switch" + preserve true + value "on" + lock false + optional true + } + ] + } + hint.show off +} diff --git a/src/conf/pcm/rear.conf b/src/conf/pcm/rear.conf new file mode 100644 index 0000000..85c70aa --- /dev/null +++ b/src/conf/pcm/rear.conf @@ -0,0 +1,58 @@ +# +# Hardware output from rear speakers +# + +pcm.!rear { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_REAR_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.rear.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_REAR_DEVICE + ] + default { + @func refer + name defaults.pcm.rear.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.rear." $DEV ":CARD=" $CARD + ] + } + } + hint { + show { + @func refer + name defaults.namehint.basic + } + description "Rear speakers" + device $DEV + } +} diff --git a/src/conf/pcm/side.conf b/src/conf/pcm/side.conf new file mode 100644 index 0000000..4a81af0 --- /dev/null +++ b/src/conf/pcm/side.conf @@ -0,0 +1,58 @@ +# +# Hardware output from side speakers +# + +pcm.!side { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SIDE_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.side.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SIDE_DEVICE + ] + default { + @func refer + name defaults.pcm.side.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.side." $DEV ":CARD=" $CARD + ] + } + } + hint { + show { + @func refer + name defaults.namehint.basic + } + description "Side speakers" + device $DEV + } +} diff --git a/src/conf/pcm/surround40.conf b/src/conf/pcm/surround40.conf new file mode 100644 index 0000000..361ccaa --- /dev/null +++ b/src/conf/pcm/surround40.conf @@ -0,0 +1,59 @@ +# +# Hardware output from 4.0 speakers. +# Samples must be positioned: +# chn0 - front left +# chn1 - front right +# chn2 - rear left +# chn3 - rear right +# + +pcm.!surround40 { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SURROUND40_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.surround40.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SURROUND40_DEVICE + ] + default { + @func refer + name defaults.pcm.surround40.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.surround40." $DEV ":CARD=" $CARD + ] + } + } + hint { + description "4.0 Surround output to Front and Rear speakers" + device $DEV + } +} diff --git a/src/conf/pcm/surround41.conf b/src/conf/pcm/surround41.conf new file mode 100644 index 0000000..10e486e --- /dev/null +++ b/src/conf/pcm/surround41.conf @@ -0,0 +1,66 @@ +# +# Hardware output from 4.1 speakers. +# Samples must be positioned: +# chn0 - front left +# chn1 - front right +# chn2 - rear left +# chn3 - rear right +# chn4 - LFE +# + +pcm.!surround41 { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SURROUND41_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.surround41.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SURROUND41_DEVICE + ] + default { + @func refer + name defaults.pcm.surround41.device + } + } + } + type route + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.surround51." $DEV ":CARD=" $CARD + ] + } + } + slave.channels 6 + ttable.0.0 1 + ttable.1.1 1 + ttable.2.2 1 + ttable.3.3 1 + ttable.4.5 1 + hint { + description "4.1 Surround output to Front, Rear and Subwoofer speakers" + device $DEV + } +} diff --git a/src/conf/pcm/surround50.conf b/src/conf/pcm/surround50.conf new file mode 100644 index 0000000..7b7b17e --- /dev/null +++ b/src/conf/pcm/surround50.conf @@ -0,0 +1,66 @@ +# +# Hardware output from 5.0 speakers. +# Samples must be positioned: +# chn0 - front left +# chn1 - front right +# chn2 - rear left +# chn3 - rear right +# chn4 - center +# + +pcm.!surround50 { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SURROUND50_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.surround50.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SURROUND50_DEVICE + ] + default { + @func refer + name defaults.pcm.surround50.device + } + } + } + type route + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.surround51." $DEV ":CARD=" $CARD + ] + } + } + slave.channels 6 + ttable.0.0 1 + ttable.1.1 1 + ttable.2.2 1 + ttable.3.3 1 + ttable.4.4 1 + hint { + description "5.0 Surround output to Front, Center and Rear speakers" + device $DEV + } +} diff --git a/src/conf/pcm/surround51.conf b/src/conf/pcm/surround51.conf new file mode 100644 index 0000000..3a7543f --- /dev/null +++ b/src/conf/pcm/surround51.conf @@ -0,0 +1,61 @@ +# +# Hardware output from 5.1 speakers +# Samples must be positioned: +# chn0 - front left +# chn1 - front right +# chn2 - rear left +# chn3 - rear right +# chn4 - center +# chn5 - lfe +# + +pcm.!surround51 { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SURROUND51_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.surround51.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SURROUND51_DEVICE + ] + default { + @func refer + name defaults.pcm.surround51.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.surround51." $DEV ":CARD=" $CARD + ] + } + } + hint { + description "5.1 Surround output to Front, Center, Rear and Subwoofer speakers" + device $DEV + } +} diff --git a/src/conf/pcm/surround71.conf b/src/conf/pcm/surround71.conf new file mode 100644 index 0000000..eb2360b --- /dev/null +++ b/src/conf/pcm/surround71.conf @@ -0,0 +1,63 @@ +# +# Hardware output from 7.1 speakers +# Samples must be positioned: +# chn0 - front left +# chn1 - front right +# chn2 - rear left +# chn3 - rear right +# chn4 - center +# chn5 - lfe +# chn7 - side left +# chn8 - side right +# + +pcm.!surround71 { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SURROUND71_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.surround71.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SURROUND71_DEVICE + ] + default { + @func refer + name defaults.pcm.surround71.device + } + } + } + type empty + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.surround71." $DEV ":CARD=" $CARD + ] + } + } + hint { + description "7.1 Surround output to Front, Center, Side, Rear and Woofer speakers" + device $DEV + } +} diff --git a/src/conf/smixer.conf b/src/conf/smixer.conf new file mode 100644 index 0000000..f215661 --- /dev/null +++ b/src/conf/smixer.conf @@ -0,0 +1,13 @@ +_full smixer-python.so +usb { + searchl "USB" + lib smixer-usb.so +} +ac97 { + searchl "AC97a:" + lib smixer-ac97.so +} +hda { + searchl "HDA:" + lib smixer-hda.so +} diff --git a/src/conf/sndo-mixer.alisp b/src/conf/sndo-mixer.alisp new file mode 100644 index 0000000..c8b03f0 --- /dev/null +++ b/src/conf/sndo-mixer.alisp @@ -0,0 +1,115 @@ +; +; Toplevel configuration for the ALSA Ordinary Mixer Interface +; +; Copyright (c) 2003 Jaroslav Kysela +; License: GPL v2 (http://www.gnu.org/licenses/gpl.html) +; + +(defun sndo_include (hctl stream) + (setq info (Acall "ctl_card_info" (Acall "hctl_ctl" hctl))) + (if (= (Aerror info) 0) + (progn + (setq info (Aresult info)) + (setq driver (cdr (assq "driver" (unsetq info)))) + (setq file (concat (path "data") "/alsa/cards/" (snd_card_alias driver) "/sndo" stream "-mixer.alisp")) + (setq r (include file)) + (when (= r -2) (Asyserr "unable to find file " file)) + ) + (setq r (Aerror info)) + ) + (unsetq info driver file r) +) + +(defun sndo_mixer_open_fcn (hctl stream pcm) + (setq fcn (concat "sndo" stream "_mixer_open")) + (setq r (if (exfun fcn) (funcall fcn hctl pcm) 0)) + (when (= r 0) + (setq hctls (if hctls (cons hctls (cons hctl)) hctl)) + ) + (unsetq fcn r) +) + +(defun sndo_mixer_open_hctl (name stream pcm) + (setq hctl (Acall "hctl_open" name nil)) + (setq r (Aerror hctl)) + (when (= r 0) + (setq hctl (Aresult hctl)) + (setq r (sndo_include hctl stream)) + (if (= r 0) + (setq r (sndo_mixer_open_fcn hctl stream pcm)) + (Acall "hctl_close" hctl) + ) + ) + (unsetq hctl r) +) + +(defun sndo_mixer_open_virtual (name stream pcm) + (setq file (concat (path "data") "/alsa/virtual/" name "/sndo" stream "-mixer.alisp")) + (setq r (include file)) + (when (= r -2) (Asyserr "unable to find file " file)) + (when (= r 0) (setq r (sndo_mixer_open_fcn nil stream pcm))) + (unsetq file r) +) + +(defun sndo_mixer_open1 (name stream) + (if (compare-strings name 0 2 "hw:" 0 2) + (sndo_mixer_open_hctl name stream nil) + (sndo_mixer_open_virtual name stream nil) + ) +) + +(defun sndo_mixer_open (pname cname) + (setq r (sndo_mixer_open1 pname "p")) + (when (= r 0) (setq r (sndo_mixer_open1 cname "c"))) + (when (!= r 0) (sndo_mixer_close)) + (unsetq sndo_mixer_open + sndo_mixer_open_pcm sndo_mixer_open_pcm1 + sndo_mixer_open_virtual sndo_mixer_open_fcn + sndo_include r) +) + +(defun sndo_mixer_open_pcm1 (pcm stream) + (setq info (Acall "pcm_info" pcm)) + (setq r (Aerror info)) + (when (= r 0) + (setq info (Aresult info)) + (setq card (cdr (assq "card" info))) + (setq r + (if (< card 0) + (sndo_mixer_open_virtual (Acall "pcm_name" pcm) stream pcm) + (sndo_mixer_open_hctl (format "hw:%i" card) stream pcm) + ) + ) + ) + (unsetq info card r) +) + +(defun sndo_mixer_open_pcm (ppcm cpcm) + (setq r (sndo_mixer_open_pcm1 ppcm "p")) + (when (= r 0) (setq r (sndo_mixer_open_pcm1 cpcm "c"))) + (when (!= r 0) (sndo_mixer_close)) + (unsetq sndo_mixer_open + sndo_mixer_open_pcm sndo_mixer_open_pcm1 + sndo_mixer_open_virtual sndo_mixer_open_fcn + sndo_include r) +) + +(defun sndo_mixer_close1 (hctl stream) + (when hctl + (progn + (setq fcn (concat "sndo" stream "_mixer_close")) + (when (exfun fcn) (funcall fcn hctl)) + (unsetq fcn) + (Acall "hctl_close" hctl) + ) + ) +) + +(defun sndo_mixer_close nil + (sndo_mixer_close1 (nth 1 hctls) "c") + (sndo_mixer_close1 (nth 0 hctls) "p") + (snd_card_alias_unset) + (unsetq hctls) +) + +(include (concat (path "data") "/alsa/cards/aliases.alisp")) diff --git a/src/confmisc.c b/src/confmisc.c new file mode 100644 index 0000000..80b0027 --- /dev/null +++ b/src/confmisc.c @@ -0,0 +1,1304 @@ +/** + * \file confmisc.c + * \ingroup Configuration + * \brief Configuration helper functions + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2000-2001 + * + * Configuration helper functions. + * + * See the \ref conffunc page for more details. + */ +/* + * Miscellaneous configuration helper functions + * Copyright (c) 2000 by Abramo Bagnara , + * Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page conffunc + +\section conffunc_ref Function reference + +
    +
  • The getenv function - snd_func_getenv() - obtains + an environment value. The result is a string. +
  • The igetenv function - snd_func_igetenv() - obtains + an environment value. The result is an integer. +
  • The concat function - snd_func_concat() - merges all specified + strings. The result is a string. +
  • The iadd function - snd_func_iadd() - sum all specified integers. + The result is an integer. +
  • The imul function - snd_func_imul() - multiply all specified integers. + The result is an integer. +
  • The datadir function - snd_func_datadir() - returns the + ALSA data directory. The result is a string. +
  • The refer function - snd_func_refer() - copies the referred + configuration. The result has the same type as the referred node. +
  • The card_inum function - snd_func_card_inum() - returns + a card number (integers). +
  • The card_driver function - snd_func_card_driver() - returns + a driver identification. The result is a string. +
  • The card_id function - snd_func_card_id() - returns + a card identification. The result is a string. +
  • The card_name function - snd_func_card_name() - returns + a card's name. The result is a string. +
  • The pcm_id function - snd_func_pcm_id() - returns + a pcm identification. The result is a string. +
  • The private_string function - snd_func_private_string() - returns the + string from the private_data node. +
  • The private_card_driver function - snd_func_private_card_driver() - + returns the driver identification from the private_data node. + The result is a string. +
  • The private_pcm_subdevice function - snd_func_private_pcm_subdevice() - + returns the PCM subdevice number from the private_data node. + The result is a string. +
+ +*/ + + +#include +#include +#include +#include +#include "local.h" + +/** + * \brief Gets the boolean value from the given ASCII string. + * \param ascii The string to be parsed. + * \return 0 or 1 if successful, otherwise a negative error code. + */ +int snd_config_get_bool_ascii(const char *ascii) +{ + unsigned int k; + static const struct { + const char str[8]; + int val; + } b[] = { + { "0", 0 }, + { "1", 1 }, + { "false", 0 }, + { "true", 1 }, + { "no", 0 }, + { "yes", 1 }, + { "off", 0 }, + { "on", 1 }, + }; + for (k = 0; k < sizeof(b) / sizeof(*b); k++) { + if (strcasecmp(b[k].str, ascii) == 0) + return b[k].val; + } + return -EINVAL; +} + +/** + * \brief Gets the boolean value from a configuration node. + * \param conf Handle to the configuration node to be parsed. + * \return 0 or 1 if successful, otherwise a negative error code. + */ +int snd_config_get_bool(const snd_config_t *conf) +{ + long v; + const char *str, *id; + int err; + + err = snd_config_get_id(conf, &id); + if (err < 0) + return err; + err = snd_config_get_integer(conf, &v); + if (err >= 0) { + if (v < 0 || v > 1) { + _invalid_value: + SNDERR("Invalid value for %s", id); + return -EINVAL; + } + return v; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + err = snd_config_get_bool_ascii(str); + if (err < 0) + goto _invalid_value; + return err; +} + +/** + * \brief Gets the control interface index from the given ASCII string. + * \param ascii The string to be parsed. + * \return The control interface index if successful, otherwise a negative error code. + */ +int snd_config_get_ctl_iface_ascii(const char *ascii) +{ + long v; + snd_ctl_elem_iface_t idx; + if (isdigit(ascii[0])) { + if (safe_strtol(ascii, &v) >= 0) { + if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST) + return -EINVAL; + return v; + } + } + for (idx = 0; idx <= SND_CTL_ELEM_IFACE_LAST; idx++) { + if (strcasecmp(snd_ctl_elem_iface_name(idx), ascii) == 0) + return idx; + } + return -EINVAL; +} + +/** + * \brief Gets the control interface index from a configuration node. + * \param conf Handle to the configuration node to be parsed. + * \return The control interface index if successful, otherwise a negative error code. + */ +int snd_config_get_ctl_iface(const snd_config_t *conf) +{ + long v; + const char *str, *id; + int err; + + err = snd_config_get_id(conf, &id); + if (err < 0) + return err; + err = snd_config_get_integer(conf, &v); + if (err >= 0) { + if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST) { + _invalid_value: + SNDERR("Invalid value for %s", id); + return -EINVAL; + } + return v; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + err = snd_config_get_ctl_iface_ascii(str); + if (err < 0) + goto _invalid_value; + return err; +} + +/* + * Helper functions for the configuration file + */ + +/** + * \brief Returns an environment value. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with definitions for \c vars and + * \c default. + * \param private_data Handle to the \c private_data node. + * \return Zero if successful, otherwise a negative error code. + * + * Example: +\code + { + @func getenv + vars [ MY_CARD CARD C ] + default 0 + } +\endcode + */ +int snd_func_getenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_config_t *n, *d; + snd_config_iterator_t i, next; + const char *res, *id; + char *def = NULL; + int idx = 0, err, hit; + + err = snd_config_search(src, "vars", &n); + if (err < 0) { + SNDERR("field vars not found"); + goto __error; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating vars"); + goto __error; + } + err = snd_config_search(src, "default", &d); + if (err < 0) { + SNDERR("field default not found"); + goto __error; + } + err = snd_config_evaluate(d, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating default"); + goto __error; + } + err = snd_config_get_ascii(d, &def); + if (err < 0) { + SNDERR("error getting field default"); + goto __error; + } + do { + hit = 0; + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *ptr; + long i; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { + SNDERR("field %s is not a string", id); + err = -EINVAL; + goto __error; + } + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not an integer", id); + err = -EINVAL; + goto __error; + } + if (i == idx) { + idx++; + err = snd_config_get_string(n, &ptr); + if (err < 0) { + SNDERR("invalid string for id %s", id); + err = -EINVAL; + goto __error; + } + res = getenv(ptr); + if (res != NULL && *res != '\0') + goto __ok; + hit = 1; + } + } + } while (hit); + res = def; + __ok: + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, res); + __error: + free(def); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_getenv, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns an integer environment value. + * \param dst The function puts the handle to the result configuration node + * (with type integer) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with definitions for \c vars and + * \c default. + * \param private_data Handle to the \c private_data node. + * \return Zero if successful, otherwise a negative error code. + * + * Example: +\code + { + @func igetenv + vars [ MY_DEVICE DEVICE D ] + default 0 + } +\endcode + */ +int snd_func_igetenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_config_t *d; + const char *str, *id; + int err; + long v; + + err = snd_func_getenv(&d, root, src, private_data); + if (err < 0) + return err; + err = snd_config_get_string(d, &str); + if (err < 0) { + snd_config_delete(d); + return err; + } + err = safe_strtol(str, &v); + if (err < 0) { + snd_config_delete(d); + return err; + } + snd_config_delete(d); + err = snd_config_get_id(src, &id); + if (err < 0) + return err; + err = snd_config_imake_integer(dst, id, v); + if (err < 0) + return err; + return 0; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_igetenv, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Merges the given strings. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a definition for \c strings. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example (result is "a1b2c3"): +\code + { + @func concat + strings [ "a1" "b2" "c3" ] + } +\endcode + */ +int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_config_t *n; + snd_config_iterator_t i, next; + const char *id; + char *res = NULL, *tmp; + int idx = 0, len = 0, len1, err, hit; + + err = snd_config_search(src, "strings", &n); + if (err < 0) { + SNDERR("field strings not found"); + goto __error; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating strings"); + goto __error; + } + do { + hit = 0; + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + char *ptr; + const char *id; + long i; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not an integer", id); + err = -EINVAL; + goto __error; + } + if (i == idx) { + idx++; + err = snd_config_get_ascii(n, &ptr); + if (err < 0) { + SNDERR("invalid ascii string for id %s", id); + err = -EINVAL; + goto __error; + } + len1 = strlen(ptr); + tmp = realloc(res, len + len1 + 1); + if (tmp == NULL) { + free(ptr); + free(res); + err = -ENOMEM; + goto __error; + } + memcpy(tmp + len, ptr, len1); + free(ptr); + len += len1; + tmp[len] = '\0'; + res = tmp; + hit = 1; + } + } + } while (hit); + if (res == NULL) { + SNDERR("empty string is not accepted"); + err = -EINVAL; + goto __error; + } + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, res); + free(res); + __error: + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_concat, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + + +static int snd_func_iops(snd_config_t **dst, + snd_config_t *root, + snd_config_t *src, + snd_config_t *private_data, + int op) +{ + snd_config_t *n; + snd_config_iterator_t i, next; + const char *id; + char *res = NULL; + long result = 0, val; + int idx = 0, err, hit; + + err = snd_config_search(src, "integers", &n); + if (err < 0) { + SNDERR("field integers not found"); + goto __error; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating integers"); + goto __error; + } + do { + hit = 0; + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long i; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not an integer", id); + err = -EINVAL; + goto __error; + } + if (i == idx) { + idx++; + err = snd_config_get_integer(n, &val); + if (err < 0) { + SNDERR("invalid integer for id %s", id); + err = -EINVAL; + goto __error; + } + switch (op) { + case 0: result += val; break; + case 1: result *= val; break; + } + hit = 1; + } + } + } while (hit); + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_integer(dst, id, result); + free(res); + __error: + return err; +} + + +/** + * \brief Sum the given integers. + * \param dst The function puts the handle to the result configuration node + * (with type integer) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a definition for \c integers. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example (result is 10): +\code + { + @func iadd + integers [ 2 3 5 ] + } +\endcode + */ +int snd_func_iadd(snd_config_t **dst, snd_config_t *root, + snd_config_t *src, snd_config_t *private_data) +{ + return snd_func_iops(dst, root, src, private_data, 0); +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_iadd, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Multiply the given integers. + * \param dst The function puts the handle to the result configuration node + * (with type integer) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a definition for \c integers. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example (result is 12): +\code + { + @func imul + integers [ 2 3 2 ] + } +\endcode + */ +int snd_func_imul(snd_config_t **dst, snd_config_t *root, + snd_config_t *src, snd_config_t *private_data) +{ + return snd_func_iops(dst, root, src, private_data, 1); +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_imul, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns the ALSA data directory. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node. + * \param private_data Handle to the \c private_data node. Not used. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example (result is "/usr/share/alsa" using the default paths): +\code + { + @func datadir + } +\endcode + */ +int snd_func_datadir(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *src, snd_config_t *private_data ATTRIBUTE_UNUSED) +{ + int err; + const char *id; + + err = snd_config_get_id(src, &id); + if (err < 0) + return err; + return snd_config_imake_string(dst, id, ALSA_CONFIG_DIR); +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_datadir, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +static int open_ctl(long card, snd_ctl_t **ctl) +{ + char name[16]; + snprintf(name, sizeof(name), "hw:%li", card); + name[sizeof(name)-1] = '\0'; + return snd_ctl_open(ctl, name, 0); +} + +#if 0 +static int string_from_integer(char **dst, long v) +{ + char str[32]; + char *res; + sprintf(str, "%li", v); + res = strdup(str); + if (res == NULL) + return -ENOMEM; + *dst = res; + return 0; +} +#endif + +/** + * \brief Returns the string from \c private_data. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node. + * \param private_data Handle to the \c private_data node (type string, + * id "string"). + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func private_string + } +\endcode + */ +int snd_func_private_string(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *src, snd_config_t *private_data) +{ + int err; + const char *str, *id; + + if (private_data == NULL) + return snd_config_copy(dst, src); + err = snd_config_test_id(private_data, "string"); + if (err) { + SNDERR("field string not found"); + return -EINVAL; + } + err = snd_config_get_string(private_data, &str); + if (err < 0) { + SNDERR("field string is not a string"); + return err; + } + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, str); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_private_string, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +#ifndef DOC_HIDDEN +int snd_determine_driver(int card, char **driver) +{ + snd_ctl_t *ctl = NULL; + snd_ctl_card_info_t *info; + char *res = NULL; + int err; + + assert(card >= 0 && card <= 32); + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %i", card); + goto __error; + } + snd_ctl_card_info_alloca(&info); + err = snd_ctl_card_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_card_info error: %s", snd_strerror(err)); + goto __error; + } + res = strdup(snd_ctl_card_info_get_driver(info)); + if (res == NULL) + err = -ENOMEM; + else { + *driver = res; + err = 0; + } + __error: + if (ctl) + snd_ctl_close(ctl); + return err; +} +#endif + +/** + * \brief Returns the driver identification from \c private_data. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node. + * \param private_data Handle to the \c private_data node (type integer, + * id "card"). + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func private_card_driver + } +\endcode + */ +int snd_func_private_card_driver(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src, + snd_config_t *private_data) +{ + char *driver; + const char *id; + int err; + long card; + + err = snd_config_test_id(private_data, "card"); + if (err) { + SNDERR("field card not found"); + return -EINVAL; + } + err = snd_config_get_integer(private_data, &card); + if (err < 0) { + SNDERR("field card is not an integer"); + return err; + } + if ((err = snd_determine_driver(card, &driver)) < 0) + return err; + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, driver); + free(driver); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_private_card_driver, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +static int parse_card(snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_config_t *n; + char *str; + int card, err; + + err = snd_config_search(src, "card", &n); + if (err < 0) { + SNDERR("field card not found"); + return err; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating card"); + return err; + } + err = snd_config_get_ascii(n, &str); + if (err < 0) { + SNDERR("field card is not an integer or a string"); + return err; + } + card = snd_card_get_index(str); + if (card < 0) + SNDERR("cannot find card '%s'", str); + free(str); + return card; +} + +/** + * \brief Returns the card number as integer. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a \c card definition. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func card_inum + card '0' + } +\endcode + */ +int snd_func_card_inum(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + const char *id; + int card, err; + + card = parse_card(root, src, private_data); + if (card < 0) + return card; + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_integer(dst, id, card); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_card_inum, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns the driver identification for a card. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a \c card definition. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func card_driver + card 0 + } +\endcode + */ +int snd_func_card_driver(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_config_t *val; + int card, err; + + card = parse_card(root, src, private_data); + if (card < 0) + return card; + err = snd_config_imake_integer(&val, "card", card); + if (err < 0) + return err; + err = snd_func_private_card_driver(dst, root, src, val); + snd_config_delete(val); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_card_driver, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns the identification of a card. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a \c card definition. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func card_id + card 0 + } +\endcode + */ +int snd_func_card_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_ctl_t *ctl = NULL; + snd_ctl_card_info_t *info; + const char *id; + int card, err; + + card = parse_card(root, src, private_data); + if (card < 0) + return card; + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %i", card); + goto __error; + } + snd_ctl_card_info_alloca(&info); + err = snd_ctl_card_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_card_info error: %s", snd_strerror(err)); + goto __error; + } + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, + snd_ctl_card_info_get_id(info)); + __error: + if (ctl) + snd_ctl_close(ctl); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_card_id, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns the name of a card. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with a \c card definition. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func card_name + card 0 + } +\endcode + */ +int snd_func_card_name(snd_config_t **dst, snd_config_t *root, + snd_config_t *src, snd_config_t *private_data) +{ + snd_ctl_t *ctl = NULL; + snd_ctl_card_info_t *info; + const char *id; + int card, err; + + card = parse_card(root, src, private_data); + if (card < 0) + return card; + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %i", card); + goto __error; + } + snd_ctl_card_info_alloca(&info); + err = snd_ctl_card_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_card_info error: %s", snd_strerror(err)); + goto __error; + } + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, + snd_ctl_card_info_get_name(info)); + __error: + if (ctl) + snd_ctl_close(ctl); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_card_name, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +#ifdef BUILD_PCM + +/** + * \brief Returns the pcm identification of a device. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with definitions for \c card, + * \c device and (optionally) \c subdevice. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func pcm_id + card 0 + device 0 + subdevice 0 # optional + } +\endcode + */ +int snd_func_pcm_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data) +{ + snd_config_t *n; + snd_ctl_t *ctl = NULL; + snd_pcm_info_t *info; + const char *id; + long card, device, subdevice = 0; + int err; + + card = parse_card(root, src, private_data); + if (card < 0) + return card; + err = snd_config_search(src, "device", &n); + if (err < 0) { + SNDERR("field device not found"); + goto __error; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating device"); + goto __error; + } + err = snd_config_get_integer(n, &device); + if (err < 0) { + SNDERR("field device is not an integer"); + goto __error; + } + if (snd_config_search(src, "subdevice", &n) >= 0) { + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating subdevice"); + goto __error; + } + err = snd_config_get_integer(n, &subdevice); + if (err < 0) { + SNDERR("field subdevice is not an integer"); + goto __error; + } + } + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %li", card); + goto __error; + } + snd_pcm_info_alloca(&info); + snd_pcm_info_set_device(info, device); + snd_pcm_info_set_subdevice(info, subdevice); + err = snd_ctl_pcm_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err)); + goto __error; + } + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, snd_pcm_info_get_id(info)); + __error: + if (ctl) + snd_ctl_close(ctl); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_pcm_id, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns the pcm card and device arguments (in form CARD=N,DEV=M) + * for pcm specified by class and index. + * \param dst The function puts the handle to the result configuration node + * (with type string) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with definitions for \c class + * and \c index. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func pcm_args_by_class + class 0 + index 0 + } +\endcode + */ +int snd_func_pcm_args_by_class(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data) +{ + snd_config_t *n; + snd_ctl_t *ctl = NULL; + snd_pcm_info_t *info; + const char *id; + int card = -1, dev; + long class, index; + int idx = 0; + int err; + + err = snd_config_search(src, "class", &n); + if (err < 0) { + SNDERR("field class not found"); + goto __out; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating class"); + goto __out; + } + err = snd_config_get_integer(n, &class); + if (err < 0) { + SNDERR("field class is not an integer"); + goto __out; + } + err = snd_config_search(src, "index", &n); + if (err < 0) { + SNDERR("field index not found"); + goto __out; + } + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating index"); + goto __out; + } + err = snd_config_get_integer(n, &index); + if (err < 0) { + SNDERR("field index is not an integer"); + goto __out; + } + + snd_pcm_info_alloca(&info); + while(1) { + err = snd_card_next(&card); + if (err < 0) { + SNDERR("could not get next card"); + goto __out; + } + if (card < 0) + break; + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %i", card); + goto __out; + } + dev = -1; + memset(info, 0, snd_pcm_info_sizeof()); + while(1) { + err = snd_ctl_pcm_next_device(ctl, &dev); + if (err < 0) { + SNDERR("could not get next pcm for card %i", card); + goto __out; + } + if (dev < 0) + break; + snd_pcm_info_set_device(info, dev); + err = snd_ctl_pcm_info(ctl, info); + if (err < 0) + continue; + if (snd_pcm_info_get_class(info) == (snd_pcm_class_t)class && + index == idx++) + goto __out; + } + snd_ctl_close(ctl); + ctl = NULL; + } + err = -ENODEV; + + __out: + if (ctl) + snd_ctl_close(ctl); + if (err < 0) + return err; + if((err = snd_config_get_id(src, &id)) >= 0) { + char name[32]; + snprintf(name, sizeof(name), "CARD=%i,DEV=%i", card, dev); + err = snd_config_imake_string(dst, id, name); + } + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_pcm_args_by_class, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +/** + * \brief Returns the PCM subdevice from \c private_data. + * \param dst The function puts the handle to the result configuration node + * (with type integer) at the address specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node. + * \param private_data Handle to the \c private_data node (type pointer, + * id "pcm_handle"). + * \return A non-negative value if successful, otherwise a negative error code. + * + * Example: +\code + { + @func private_pcm_subdevice + } +\endcode + */ +int snd_func_private_pcm_subdevice(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *src, snd_config_t *private_data) +{ + snd_pcm_info_t *info; + const char *id; + const void *data; + snd_pcm_t *pcm; + int err; + + if (private_data == NULL) + return snd_config_copy(dst, src); + err = snd_config_test_id(private_data, "pcm_handle"); + if (err) { + SNDERR("field pcm_handle not found"); + return -EINVAL; + } + err = snd_config_get_pointer(private_data, &data); + pcm = (snd_pcm_t *)data; + if (err < 0) { + SNDERR("field pcm_handle is not a pointer"); + return err; + } + snd_pcm_info_alloca(&info); + err = snd_pcm_info(pcm, info); + if (err < 0) { + SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err)); + return err; + } + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_integer(dst, id, snd_pcm_info_get_subdevice(info)); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_private_pcm_subdevice, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif + +#endif /* BUILD_PCM */ + +/** + * \brief Copies the specified configuration node. + * \param dst The function puts the handle to the result configuration node + * (with the same type as the specified node) at the address + * specified by \p dst. + * \param root Handle to the root source node. + * \param src Handle to the source node, with definitions for \c name and + * (optionally) \c file. + * \param private_data Handle to the \c private_data node. + * \return A non-negative value if successful, otherwise a negative error code. + * \note The root source node can be modified! + * + * Example: +\code + { + @func refer + file "/etc/myconf.conf" # optional + name "id1.id2.id3" + } +\endcode + */ +int snd_func_refer(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + snd_config_t *private_data) +{ + snd_config_t *n; + const char *file = NULL, *name = NULL; + int err; + + err = snd_config_search(src, "file", &n); + if (err >= 0) { + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating file"); + goto _end; + } + err = snd_config_get_string(n, &file); + if (err < 0) { + SNDERR("file is not a string"); + goto _end; + } + } + err = snd_config_search(src, "name", &n); + if (err >= 0) { + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) { + SNDERR("error evaluating name"); + goto _end; + } + err = snd_config_get_string(n, &name); + if (err < 0) { + SNDERR("name is not a string"); + goto _end; + } + } + if (!name) { + err = -EINVAL; + SNDERR("name is not specified"); + goto _end; + } + if (file) { + snd_input_t *input; + err = snd_input_stdio_open(&input, file, "r"); + if (err < 0) { + SNDERR("Unable to open file %s: %s", file, snd_strerror(err)); + goto _end; + } + err = snd_config_load(root, input); + snd_input_close(input); + if (err < 0) + goto _end; + } + err = snd_config_search_definition(root, NULL, name, dst); + if (err >= 0) { + const char *id; + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_set_id(*dst, id); + } else { + err = snd_config_search(src, "default", &n); + if (err < 0) + SNDERR("Unable to find definition '%s'", name); + else { + const char *id; + err = snd_config_evaluate(n, root, private_data, NULL); + if (err < 0) + return err; + if ((err = snd_config_copy(dst, n)) >= 0) { + if ((err = snd_config_get_id(src, &id)) < 0 || + (err = snd_config_set_id(*dst, id)) < 0) + snd_config_delete(*dst); + } + } + } + _end: + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(snd_func_refer, SND_CONFIG_DLSYM_VERSION_EVALUATE); +#endif diff --git a/src/control/Makefile.am b/src/control/Makefile.am new file mode 100644 index 0000000..8076c73 --- /dev/null +++ b/src/control/Makefile.am @@ -0,0 +1,18 @@ +EXTRA_LTLIBRARIES = libcontrol.la + +libcontrol_la_SOURCES = cards.c tlv.c namehint.c hcontrol.c \ + control.c control_hw.c setup.c ctlparse.c \ + control_symbols.c +if BUILD_CTL_PLUGIN_SHM +libcontrol_la_SOURCES += control_shm.c +endif +if BUILD_CTL_PLUGIN_EXT +libcontrol_la_SOURCES += control_ext.c +endif + +noinst_HEADERS = control_local.h + +all: libcontrol.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/control/Makefile.in b/src/control/Makefile.in new file mode 100644 index 0000000..523fbea --- /dev/null +++ b/src/control/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_CTL_PLUGIN_SHM_TRUE@am__append_1 = control_shm.c +@BUILD_CTL_PLUGIN_EXT_TRUE@am__append_2 = control_ext.c +subdir = src/control +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libcontrol_la_LIBADD = +am__libcontrol_la_SOURCES_DIST = cards.c tlv.c namehint.c hcontrol.c \ + control.c control_hw.c setup.c ctlparse.c control_symbols.c \ + control_shm.c control_ext.c +@BUILD_CTL_PLUGIN_SHM_TRUE@am__objects_1 = control_shm.lo +@BUILD_CTL_PLUGIN_EXT_TRUE@am__objects_2 = control_ext.lo +am_libcontrol_la_OBJECTS = cards.lo tlv.lo namehint.lo hcontrol.lo \ + control.lo control_hw.lo setup.lo ctlparse.lo \ + control_symbols.lo $(am__objects_1) $(am__objects_2) +libcontrol_la_OBJECTS = $(am_libcontrol_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libcontrol_la_SOURCES) +DIST_SOURCES = $(am__libcontrol_la_SOURCES_DIST) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libcontrol.la +libcontrol_la_SOURCES = cards.c tlv.c namehint.c hcontrol.c control.c \ + control_hw.c setup.c ctlparse.c control_symbols.c \ + $(am__append_1) $(am__append_2) +noinst_HEADERS = control_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/control/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/control/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libcontrol.la: $(libcontrol_la_OBJECTS) $(libcontrol_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libcontrol_la_OBJECTS) $(libcontrol_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cards.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_ext.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_shm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_symbols.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctlparse.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hcontrol.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namehint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setup.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlv.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +all: libcontrol.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/control/cards.c b/src/control/cards.c new file mode 100644 index 0000000..0bb8f86 --- /dev/null +++ b/src/control/cards.c @@ -0,0 +1,216 @@ +/** + * \file control/cards.c + * \brief Basic Soundcard Operations + * \author Jaroslav Kysela + * \date 1998-2001 + */ +/* + * Soundcard Operations - main file + * Copyright (c) 1998 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "control_local.h" + +#ifndef DOC_HIDDEN +#define SND_FILE_CONTROL ALSA_DEVICE_DIRECTORY "controlC%i" +#define SND_FILE_LOAD ALOAD_DEVICE_DIRECTORY "aloadC%i" +#endif + +static int snd_card_load2(const char *control) +{ + int open_dev; + snd_ctl_card_info_t info; + + open_dev = snd_open_device(control, O_RDONLY); + if (open_dev >= 0) { + if (ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO, &info) < 0) { + int err = -errno; + close(open_dev); + return err; + } + close(open_dev); + return info.card; + } else { + return -errno; + } +} + +static int snd_card_load1(int card) +{ + int res; + char control[sizeof(SND_FILE_CONTROL) + 10]; + + sprintf(control, SND_FILE_CONTROL, card); + res = snd_card_load2(control); +#ifdef SUPPORT_ALOAD + if (res < 0) { + char aload[sizeof(SND_FILE_LOAD) + 10]; + sprintf(aload, SND_FILE_LOAD, card); + res = snd_card_load2(aload); + } +#endif + return res; +} + +/** + * \brief Try to load the driver for a card. + * \param card Card number. + * \return 1 if driver is present, zero if driver is not present + */ +int snd_card_load(int card) +{ + return !!(snd_card_load1(card) >= 0); +} + +/** + * \brief Try to determine the next card. + * \param rcard pointer to card number + * \result zero if success, otherwise a negative error code + * + * Tries to determine the next card from given card number. + * If card number is -1, then the first available card is + * returned. If the result card number is -1, no more cards + * are available. + */ +int snd_card_next(int *rcard) +{ + int card; + + if (rcard == NULL) + return -EINVAL; + card = *rcard; + card = card < 0 ? 0 : card + 1; + for (; card < 32; card++) { + if (snd_card_load(card)) { + *rcard = card; + return 0; + } + } + *rcard = -1; + return 0; +} + +/** + * \brief Convert card string to an integer value. + * \param string String containing card identifier + * \return zero if success, otherwise a negative error code + * + * The accepted format is an integer value in ASCII representation + * or the card identifier (the id parameter for sound-card drivers). + * The control device name like /dev/snd/controlC0 is accepted, too. + */ +int snd_card_get_index(const char *string) +{ + int card, err; + snd_ctl_t *handle; + snd_ctl_card_info_t info; + + if (!string || *string == '\0') + return -EINVAL; + if ((isdigit(*string) && *(string + 1) == 0) || + (isdigit(*string) && isdigit(*(string + 1)) && *(string + 2) == 0)) { + if (sscanf(string, "%i", &card) != 1) + return -EINVAL; + if (card < 0 || card > 31) + return -EINVAL; + err = snd_card_load1(card); + if (err >= 0) + return card; + return err; + } + if (string[0] == '/') /* device name */ + return snd_card_load2(string); + for (card = 0; card < 32; card++) { +#ifdef SUPPORT_ALOAD + if (! snd_card_load(card)) + continue; +#endif + if (snd_ctl_hw_open(&handle, NULL, card, 0) < 0) + continue; + if (snd_ctl_card_info(handle, &info) < 0) { + snd_ctl_close(handle); + continue; + } + snd_ctl_close(handle); + if (!strcmp((const char *)info.id, string)) + return card; + } + return -ENODEV; +} + +/** + * \brief Obtain the card name. + * \param card Card number + * \param name Result - card name corresponding to card number + * \result zero if success, otherwise a negative error code + */ +int snd_card_get_name(int card, char **name) +{ + snd_ctl_t *handle; + snd_ctl_card_info_t info; + int err; + + if (name == NULL) + return -EINVAL; + if ((err = snd_ctl_hw_open(&handle, NULL, card, 0)) < 0) + return err; + if ((err = snd_ctl_card_info(handle, &info)) < 0) { + snd_ctl_close(handle); + return err; + } + snd_ctl_close(handle); + *name = strdup((const char *)info.name); + if (*name == NULL) + return -ENOMEM; + return 0; +} + +/** + * \brief Obtain the card long name. + * \param card Card number + * \param name Result - card long name corresponding to card number + * \result zero if success, otherwise a negative error code + */ +int snd_card_get_longname(int card, char **name) +{ + snd_ctl_t *handle; + snd_ctl_card_info_t info; + int err; + + if (name == NULL) + return -EINVAL; + if ((err = snd_ctl_hw_open(&handle, NULL, card, 0)) < 0) + return err; + if ((err = snd_ctl_card_info(handle, &info)) < 0) { + snd_ctl_close(handle); + return err; + } + snd_ctl_close(handle); + *name = strdup((const char *)info.longname); + if (*name == NULL) + return -ENOMEM; + return 0; +} diff --git a/src/control/control.c b/src/control/control.c new file mode 100644 index 0000000..19e9389 --- /dev/null +++ b/src/control/control.c @@ -0,0 +1,2570 @@ +/** + * \file control/control.c + * \brief CTL interface - primitive controls + * \author Abramo Bagnara + * \date 2000 + * + * CTL interface is designed to access primitive controls. + * See \ref control page for more details. + */ +/* + * Control Interface - main file + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page control Control interface + +

Control interface is designed to access primitive controls. There is +also interface notifying about control and structure changes. + +\section control_general_overview General overview + +The primitive controls can be integer, boolean, enumerators, bytes +and IEC958 structure. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "control_local.h" + +/** + * \brief get identifier of CTL handle + * \param ctl CTL handle + * \return ascii identifier of CTL handle + * + * Returns the ASCII identifier of given CTL handle. It's the same + * identifier specified in snd_ctl_open(). + */ +const char *snd_ctl_name(snd_ctl_t *ctl) +{ + assert(ctl); + return ctl->name; +} + +/** + * \brief get type of CTL handle + * \param ctl CTL handle + * \return type of CTL handle + * + * Returns the type #snd_ctl_type_t of given CTL handle. + */ +snd_ctl_type_t snd_ctl_type(snd_ctl_t *ctl) +{ + assert(ctl); + return ctl->type; +} + +/** + * \brief close CTL handle + * \param ctl CTL handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified CTL handle and frees all associated + * resources. + */ +int snd_ctl_close(snd_ctl_t *ctl) +{ + int err; + while (!list_empty(&ctl->async_handlers)) { + snd_async_handler_t *h = list_entry(&ctl->async_handlers.next, snd_async_handler_t, hlist); + snd_async_del_handler(h); + } + err = ctl->ops->close(ctl); + free(ctl->name); + snd_dlobj_cache_put(ctl->open_func); + free(ctl); + return err; +} + +/** + * \brief set nonblock mode + * \param ctl CTL handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock) +{ + int err; + assert(ctl); + err = ctl->ops->nonblock(ctl, nonblock); + if (err < 0) + return err; + ctl->nonblock = nonblock; + return 0; +} + +#ifndef DOC_HIDDEN +int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name) +{ + snd_ctl_t *ctl; + ctl = calloc(1, sizeof(*ctl)); + if (!ctl) + return -ENOMEM; + ctl->type = type; + if (name) + ctl->name = strdup(name); + INIT_LIST_HEAD(&ctl->async_handlers); + *ctlp = ctl; + return 0; +} + + +/** + * \brief set async mode + * \param ctl CTL handle + * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) + * \param pid Process ID to signal: 0 current + * \return 0 on success otherwise a negative error code + * + * A signal is raised when a change happens. + */ +int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid) +{ + assert(ctl); + if (sig == 0) + sig = SIGIO; + if (pid == 0) + pid = getpid(); + return ctl->ops->async(ctl, sig, pid); +} +#endif + +/** + * \brief get count of poll descriptors for CTL handle + * \param ctl CTL handle + * \return count of poll descriptors + */ +int snd_ctl_poll_descriptors_count(snd_ctl_t *ctl) +{ + assert(ctl); + if (ctl->ops->poll_descriptors_count) + return ctl->ops->poll_descriptors_count(ctl); + if (ctl->poll_fd < 0) + return 0; + return 1; +} + +/** + * \brief get poll descriptors + * \param ctl CTL handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int space) +{ + assert(ctl && pfds); + if (ctl->ops->poll_descriptors) + return ctl->ops->poll_descriptors(ctl, pfds, space); + if (ctl->poll_fd < 0) + return 0; + if (space > 0) { + pfds->fd = ctl->poll_fd; + pfds->events = POLLIN|POLLERR|POLLNVAL; + return 1; + } + return 0; +} + +/** + * \brief get returned events from poll descriptors + * \param ctl CTL handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(ctl && pfds && revents); + if (ctl->ops->poll_revents) + return ctl->ops->poll_revents(ctl, pfds, nfds, revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +/** + * \brief Ask to be informed about events (poll, #snd_async_add_ctl_handler, #snd_ctl_read) + * \param ctl CTL handle + * \param subscribe 0 = unsubscribe, 1 = subscribe + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe) +{ + assert(ctl); + return ctl->ops->subscribe_events(ctl, subscribe); +} + + +/** + * \brief Get card related information + * \param ctl CTL handle + * \param info Card info pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) +{ + assert(ctl && info); + return ctl->ops->card_info(ctl, info); +} + +/** + * \brief Get a list of element identifiers + * \param ctl CTL handle + * \param list CTL element identifiers list pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list) +{ + assert(ctl && list); + assert(list->space == 0 || list->pids); + return ctl->ops->element_list(ctl, list); +} + +/** + * \brief Get CTL element information + * \param ctl CTL handle + * \param info CTL element id/information pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) +{ + assert(ctl && info && (info->id.name[0] || info->id.numid)); + return ctl->ops->element_info(ctl, info); +} + +/** + * \brief Create and add an user INTEGER CTL element + * \param ctl CTL handle + * \param id CTL element id to add + * \param count number of elements + * \param min minimum value + * \param max maximum value + * \param step value step + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int count, long min, long max, long step) +{ + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *val; + unsigned int i; + int err; + + assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); + info->id = *id; + info->type = SND_CTL_ELEM_TYPE_INTEGER; + info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE; + info->count = count; + info->value.integer.min = min; + info->value.integer.max = max; + info->value.integer.step = step; + err = ctl->ops->element_add(ctl, info); + if (err < 0) + return err; + snd_ctl_elem_value_alloca(&val); + val->id = *id; + for (i = 0; i < count; i++) + val->value.integer.value[i] = min; + err = ctl->ops->element_write(ctl, val); + return err; +} + +/** + * \brief Create and add an user INTEGER64 CTL element + * \param ctl CTL handle + * \param id CTL element id to add + * \param count number of elements + * \param min minimum value + * \param max maximum value + * \param step value step + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int count, long long min, long long max, + long long step) +{ + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *val; + unsigned int i; + int err; + + assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); + info->id = *id; + info->type = SND_CTL_ELEM_TYPE_INTEGER64; + info->count = count; + info->value.integer64.min = min; + info->value.integer64.max = max; + info->value.integer64.step = step; + err = ctl->ops->element_add(ctl, info); + if (err < 0) + return err; + snd_ctl_elem_value_alloca(&val); + val->id = *id; + for (i = 0; i < count; i++) + val->value.integer64.value[i] = min; + err = ctl->ops->element_write(ctl, val); + return err; +} + +/** + * \brief Create and add an user BOOLEAN CTL element + * \param ctl CTL handle + * \param id CTL element id to add + * \param count number of elements + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int count) +{ + snd_ctl_elem_info_t *info; + + assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); + info->id = *id; + info->type = SND_CTL_ELEM_TYPE_BOOLEAN; + info->count = count; + info->value.integer.min = 0; + info->value.integer.max = 1; + return ctl->ops->element_add(ctl, info); +} + +/** + * \brief Create and add an user IEC958 CTL element + * \param ctl CTL handle + * \param id CTL element info to add + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id) +{ + snd_ctl_elem_info_t *info; + + assert(ctl && id && id->name[0]); + snd_ctl_elem_info_alloca(&info); + info->id = *id; + info->type = SND_CTL_ELEM_TYPE_IEC958; + info->count = 1; + return ctl->ops->element_add(ctl, info); +} + +/** + * \brief Remove an user CTL element + * \param ctl CTL handle + * \param id CTL element identification + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) +{ + assert(ctl && id && (id->name[0] || id->numid)); + return ctl->ops->element_remove(ctl, id); +} + +/** + * \brief Get CTL element value + * \param ctl CTL handle + * \param control CTL element id/value pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control) +{ + assert(ctl && control && (control->id.name[0] || control->id.numid)); + return ctl->ops->element_read(ctl, control); +} + +/** + * \brief Set CTL element value + * \param ctl CTL handle + * \param control CTL element id/value pointer + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code + */ +int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control) +{ + assert(ctl && control && (control->id.name[0] || control->id.numid)); + return ctl->ops->element_write(ctl, control); +} + +static int snd_ctl_tlv_do(snd_ctl_t *ctl, int op_flag, + const snd_ctl_elem_id_t *id, + unsigned int *tlv, unsigned int tlv_size) +{ + snd_ctl_elem_info_t *info = NULL; + int err; + + if (id->numid == 0) { + info = calloc(1, sizeof(*info)); + if (info == NULL) + return -ENOMEM; + info->id = *id; + id = &info->id; + err = snd_ctl_elem_info(ctl, info); + if (err < 0) + goto __err; + if (id->numid == 0) { + err = -ENOENT; + goto __err; + } + } + err = ctl->ops->element_tlv(ctl, op_flag, id->numid, tlv, tlv_size); + __err: + if (info) + free(info); + return err; +} + + + +/** + * \brief Get CTL element TLV value + * \param ctl CTL handle + * \param id CTL element id pointer + * \param tlv TLV array pointer to store + * \param tlv_size TLV array size in bytes + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int *tlv, unsigned int tlv_size) +{ + int err; + assert(ctl && id && (id->name[0] || id->numid) && tlv); + if (tlv_size < 2 * sizeof(int)) + return -EINVAL; + /* 1.0.12 driver doesn't return the error even if the user TLV + * is empty. So, initialize TLV here with an invalid type + * and compare the returned value after ioctl for checking + * the validity of TLV. + */ + tlv[0] = -1; + tlv[1] = 0; + err = snd_ctl_tlv_do(ctl, 0, id, tlv, tlv_size); + if (err >= 0 && tlv[0] == (unsigned int)-1) + err = -ENXIO; + return err; +} + +/** + * \brief Set CTL element TLV value + * \param ctl CTL handle + * \param id CTL element id pointer + * \param tlv TLV array pointer to store + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code + */ +int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + const unsigned int *tlv) +{ + assert(ctl && id && (id->name[0] || id->numid) && tlv); + return snd_ctl_tlv_do(ctl, 1, id, (unsigned int *)tlv, tlv[1] + 2 * sizeof(unsigned int)); +} + +/** + * \brief Process CTL element TLV command + * \param ctl CTL handle + * \param id CTL element id pointer + * \param tlv TLV array pointer to process + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code + */ +int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + const unsigned int *tlv) +{ + assert(ctl && id && (id->name[0] || id->numid) && tlv); + return snd_ctl_tlv_do(ctl, -1, id, (unsigned int *)tlv, tlv[1] + 2 * sizeof(unsigned int)); +} + +/** + * \brief Lock CTL element + * \param ctl CTL handle + * \param id CTL element id pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) +{ + assert(ctl && id); + return ctl->ops->element_lock(ctl, id); +} + +/** + * \brief Unlock CTL element + * \param ctl CTL handle + * \param id CTL element id pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) +{ + assert(ctl && id); + return ctl->ops->element_unlock(ctl, id); +} + +/** + * \brief Get next hardware dependent device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_hwdep_next_device(snd_ctl_t *ctl, int *device) +{ + assert(ctl && device); + return ctl->ops->hwdep_next_device(ctl, device); +} + +/** + * \brief Get info about a hardware dependent device + * \param ctl CTL handle + * \param info Hardware dependent device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info) +{ + assert(ctl && info); + return ctl->ops->hwdep_info(ctl, info); +} + +/** + * \brief Get next PCM device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_pcm_next_device(snd_ctl_t *ctl, int * device) +{ + assert(ctl && device); + return ctl->ops->pcm_next_device(ctl, device); +} + +/** + * \brief Get info about a PCM device + * \param ctl CTL handle + * \param info PCM device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info) +{ + assert(ctl && info); + return ctl->ops->pcm_info(ctl, info); +} + +/** + * \brief Set preferred PCM subdevice number of successive PCM open + * \param ctl CTL handle + * \param subdev Preferred PCM subdevice number + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev) +{ + assert(ctl); + return ctl->ops->pcm_prefer_subdevice(ctl, subdev); +} + +/** + * \brief Get next RawMidi device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_rawmidi_next_device(snd_ctl_t *ctl, int * device) +{ + assert(ctl && device); + return ctl->ops->rawmidi_next_device(ctl, device); +} + +/** + * \brief Get info about a RawMidi device + * \param ctl CTL handle + * \param info RawMidi device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info) +{ + assert(ctl && info); + return ctl->ops->rawmidi_info(ctl, info); +} + +/** + * \brief Set preferred RawMidi subdevice number of successive RawMidi open + * \param ctl CTL handle + * \param subdev Preferred RawMidi subdevice number + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev) +{ + assert(ctl); + return ctl->ops->rawmidi_prefer_subdevice(ctl, subdev); +} + +/** + * \brief Set Power State to given SND_CTL_POWER_* value and do the power management + * \param ctl CTL handle + * \param state Desired Power State + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_set_power_state(snd_ctl_t *ctl, unsigned int state) +{ + assert(ctl); + if (ctl->ops->set_power_state) + return ctl->ops->set_power_state(ctl, state); + return -ENXIO; +} + +/** + * \brief Get actual Power State + * \param ctl CTL handle + * \param state Destination value + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_get_power_state(snd_ctl_t *ctl, unsigned int *state) +{ + assert(ctl); + if (ctl->ops->get_power_state) + return ctl->ops->get_power_state(ctl, state); + return -ENXIO; +} + +/** + * \brief Read an event + * \param ctl CTL handle + * \param event Event pointer + * \return number of events read otherwise a negative error code on failure + */ +int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_event_t *event) +{ + assert(ctl && event); + return (ctl->ops->read)(ctl, event); +} + +/** + * \brief Wait for a CTL to become ready (i.e. at least one event pending) + * \param ctl CTL handle + * \param timeout maximum time in milliseconds to wait + * \return 0 otherwise a negative error code on failure + */ +int snd_ctl_wait(snd_ctl_t *ctl, int timeout) +{ + struct pollfd *pfd; + unsigned short revents; + int npfds, err, err_poll; + + npfds = snd_ctl_poll_descriptors_count(ctl); + if (npfds <= 0 || npfds >= 16) { + SNDERR("Invalid poll_fds %d\n", npfds); + return -EIO; + } + pfd = alloca(sizeof(*pfd) * npfds); + err = snd_ctl_poll_descriptors(ctl, pfd, npfds); + if (err < 0) + return err; + if (err != npfds) { + SNDMSG("invalid poll descriptors %d\n", err); + return -EIO; + } + for (;;) { + err_poll = poll(pfd, npfds, timeout); + if (err_poll < 0) + return -errno; + if (! err_poll) + return 0; + err = snd_ctl_poll_descriptors_revents(ctl, pfd, npfds, &revents); + if (err < 0) + return err; + if (revents & (POLLERR | POLLNVAL)) + return -EIO; + if (revents & (POLLIN | POLLOUT)) + return 1; + } +} + +/** + * \brief Add an async handler for a CTL + * \param handler Returned handler handle + * \param ctl CTL handle + * \param callback Callback function + * \param private_data Callback private data + * \return 0 otherwise a negative error code on failure + */ +int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl, + snd_async_callback_t callback, void *private_data) +{ + int err; + int was_empty; + snd_async_handler_t *h; + err = snd_async_add_handler(&h, _snd_ctl_async_descriptor(ctl), + callback, private_data); + if (err < 0) + return err; + h->type = SND_ASYNC_HANDLER_CTL; + h->u.ctl = ctl; + was_empty = list_empty(&ctl->async_handlers); + list_add_tail(&h->hlist, &ctl->async_handlers); + if (was_empty) { + err = snd_ctl_async(ctl, snd_async_handler_get_signo(h), getpid()); + if (err < 0) { + snd_async_del_handler(h); + return err; + } + } + *handler = h; + return 0; +} + +/** + * \brief Return CTL handle related to an async handler + * \param handler Async handler handle + * \return CTL handle + */ +snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler) +{ + assert(handler->type == SND_ASYNC_HANDLER_CTL); + return handler->u.ctl; +} + +static const char *const build_in_ctls[] = { + "hw", "shm", NULL +}; + +static int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name, + snd_config_t *ctl_root, snd_config_t *ctl_conf, int mode) +{ + const char *str; + char *buf = NULL, *buf1 = NULL; + int err; + snd_config_t *conf, *type_conf = NULL; + snd_config_iterator_t i, next; + const char *lib = NULL, *open_name = NULL; + const char *id; + int (*open_func)(snd_ctl_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL; +#ifndef PIC + extern void *snd_control_open_symbols(void); +#endif + if (snd_config_get_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND) { + if (name) + SNDERR("Invalid type for CTL %s definition", name); + else + SNDERR("Invalid type for CTL definition"); + return -EINVAL; + } + err = snd_config_search(ctl_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(ctl_root, "ctl_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for CTL type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + buf = malloc(strlen(str) + 32); + if (buf == NULL) { + err = -ENOMEM; + goto _err; + } + open_name = buf; + sprintf(buf, "_snd_ctl_%s_open", str); + } + if (!lib) { + const char *const *build_in = build_in_ctls; + while (*build_in) { + if (!strcmp(*build_in, str)) + break; + build_in++; + } + if (*build_in == NULL) { + buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32); + if (buf1 == NULL) { + err = -ENOMEM; + goto _err; + } + lib = buf1; + sprintf(buf1, "%s/libasound_module_ctl_%s.so", ALSA_PLUGIN_DIR, str); + } + } +#ifndef PIC + snd_control_open_symbols(); +#endif + open_func = snd_dlobj_cache_get(lib, open_name, + SND_DLSYM_VERSION(SND_CONTROL_DLSYM_VERSION), 1); + if (open_func) { + err = open_func(ctlp, name, ctl_root, ctl_conf, mode); + if (err >= 0) { + (*ctlp)->open_func = open_func; + err = 0; + } else { + snd_dlobj_cache_put(open_func); + } + } else { + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + free(buf); + free(buf1); + return err; +} + +static int snd_ctl_open_noupdate(snd_ctl_t **ctlp, snd_config_t *root, const char *name, int mode) +{ + int err; + snd_config_t *ctl_conf; + err = snd_config_search_definition(root, "ctl", name, &ctl_conf); + if (err < 0) { + SNDERR("Invalid CTL %s", name); + return err; + } + err = snd_ctl_open_conf(ctlp, name, root, ctl_conf, mode); + snd_config_delete(ctl_conf); + return err; +} + +/** + * \brief Opens a CTL + * \param ctlp Returned CTL handle + * \param name ASCII identifier of the CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode) +{ + int err; + assert(ctlp && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_ctl_open_noupdate(ctlp, snd_config, name, mode); +} + +/** + * \brief Opens a CTL using local configuration + * \param ctlp Returned CTL handle + * \param name ASCII identifier of the CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \param lconf Local configuration + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_open_lconf(snd_ctl_t **ctlp, const char *name, + int mode, snd_config_t *lconf) +{ + assert(ctlp && name && lconf); + return snd_ctl_open_noupdate(ctlp, lconf, name, mode); +} + +#ifndef DOC_HIDDEN +#define TYPE(v) [SND_CTL_ELEM_TYPE_##v] = #v +#define IFACE(v) [SND_CTL_ELEM_IFACE_##v] = #v +#define IFACE1(v, n) [SND_CTL_ELEM_IFACE_##v] = #n +#define EVENT(v) [SND_CTL_EVENT_##v] = #v + +static const char *const snd_ctl_elem_type_names[] = { + TYPE(NONE), + TYPE(BOOLEAN), + TYPE(INTEGER), + TYPE(ENUMERATED), + TYPE(BYTES), + TYPE(IEC958), + TYPE(INTEGER64), +}; + +static const char *const snd_ctl_elem_iface_names[] = { + IFACE(CARD), + IFACE(HWDEP), + IFACE(MIXER), + IFACE(PCM), + IFACE(RAWMIDI), + IFACE(TIMER), + IFACE(SEQUENCER), +}; + +static const char *const snd_ctl_event_type_names[] = { + EVENT(ELEM), +}; +#endif + +/** + * \brief get name of a CTL element type + * \param type CTL element type + * \return ascii name of CTL element type + */ +const char *snd_ctl_elem_type_name(snd_ctl_elem_type_t type) +{ + assert(type <= SND_CTL_ELEM_TYPE_LAST); + return snd_ctl_elem_type_names[type]; +} + +/** + * \brief get name of a CTL element related interface + * \param iface CTL element related interface + * \return ascii name of CTL element related interface + */ +const char *snd_ctl_elem_iface_name(snd_ctl_elem_iface_t iface) +{ + assert(iface <= SND_CTL_ELEM_IFACE_LAST); + return snd_ctl_elem_iface_names[iface]; +} + +/** + * \brief get name of a CTL event type + * \param type CTL event type + * \return ascii name of CTL event type + */ +const char *snd_ctl_event_type_name(snd_ctl_event_type_t type) +{ + assert(type <= SND_CTL_EVENT_LAST); + return snd_ctl_event_type_names[type]; +} + +/** + * \brief allocate space for CTL element identifiers list + * \param obj CTL element identifiers list + * \param entries Entries to allocate + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries) +{ + free(obj->pids); + obj->pids = calloc(entries, sizeof(*obj->pids)); + if (!obj->pids) { + obj->space = 0; + return -ENOMEM; + } + obj->space = entries; + return 0; +} + +/** + * \brief free previously allocated space for CTL element identifiers list + * \param obj CTL element identifiers list + */ +void snd_ctl_elem_list_free_space(snd_ctl_elem_list_t *obj) +{ + free(obj->pids); + obj->pids = NULL; + obj->space = 0; +} + +/** + * \brief Get event mask for an element related event + * \param obj CTL event + * \return event mask for element related event + */ +unsigned int snd_ctl_event_elem_get_mask(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return obj->data.elem.mask; +} + +/** + * \brief Get CTL element identifier for an element related event + * \param obj CTL event + * \param ptr Pointer to returned CTL element identifier + */ +void snd_ctl_event_elem_get_id(const snd_ctl_event_t *obj, snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + assert(obj->type == SND_CTL_EVENT_ELEM); + *ptr = obj->data.elem.id; +} + +/** + * \brief Get element numeric identifier for an element related event + * \param obj CTL event + * \return element numeric identifier + */ +unsigned int snd_ctl_event_elem_get_numid(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return obj->data.elem.id.numid; +} + +/** + * \brief Get interface part of CTL element identifier for an element related event + * \param obj CTL event + * \return interface part of element identifier + */ +snd_ctl_elem_iface_t snd_ctl_event_elem_get_interface(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return obj->data.elem.id.iface; +} + +/** + * \brief Get device part of CTL element identifier for an element related event + * \param obj CTL event + * \return device part of element identifier + */ +unsigned int snd_ctl_event_elem_get_device(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return obj->data.elem.id.device; +} + +/** + * \brief Get subdevice part of CTL element identifier for an element related event + * \param obj CTL event + * \return subdevice part of element identifier + */ +unsigned int snd_ctl_event_elem_get_subdevice(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return obj->data.elem.id.subdevice; +} + +/** + * \brief Get name part of CTL element identifier for an element related event + * \param obj CTL event + * \return name part of element identifier + */ +const char *snd_ctl_event_elem_get_name(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return (const char *)obj->data.elem.id.name; +} + +/** + * \brief Get index part of CTL element identifier for an element related event + * \param obj CTL event + * \return index part of element identifier + */ +unsigned int snd_ctl_event_elem_get_index(const snd_ctl_event_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_EVENT_ELEM); + return obj->data.elem.id.index; +} + +#ifndef DOC_HIDDEN +int _snd_ctl_poll_descriptor(snd_ctl_t *ctl) +{ + assert(ctl); + return ctl->poll_fd; +} +#endif + +/** + * \brief get size of #snd_ctl_elem_id_t + * \return size in bytes + */ +size_t snd_ctl_elem_id_sizeof() +{ + return sizeof(snd_ctl_elem_id_t); +} + +/** + * \brief allocate an invalid #snd_ctl_elem_id_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_ctl_elem_id_malloc(snd_ctl_elem_id_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_ctl_elem_id_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_ctl_elem_id_t + * \param obj pointer to object to free + */ +void snd_ctl_elem_id_free(snd_ctl_elem_id_t *obj) +{ + free(obj); +} + +/** + * \brief clear given #snd_ctl_elem_id_t object + * \param obj pointer to object to clear + */ +void snd_ctl_elem_id_clear(snd_ctl_elem_id_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_elem_id_t)); +} + +/** + * \brief copy one #snd_ctl_elem_id_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_ctl_elem_id_copy(snd_ctl_elem_id_t *dst, const snd_ctl_elem_id_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get numeric identifier from a CTL element identifier + * \param obj CTL element identifier + * \return CTL element numeric identifier + */ +unsigned int snd_ctl_elem_id_get_numid(const snd_ctl_elem_id_t *obj) +{ + assert(obj); + return obj->numid; +} + +/** + * \brief Get interface part of a CTL element identifier + * \param obj CTL element identifier + * \return CTL element related interface + */ +snd_ctl_elem_iface_t snd_ctl_elem_id_get_interface(const snd_ctl_elem_id_t *obj) +{ + assert(obj); + return obj->iface; +} + +/** + * \brief Get device part of a CTL element identifier + * \param obj CTL element identifier + * \return CTL element related device + */ +unsigned int snd_ctl_elem_id_get_device(const snd_ctl_elem_id_t *obj) +{ + assert(obj); + return obj->device; +} + +/** + * \brief Get subdevice part of a CTL element identifier + * \param obj CTL element identifier + * \return CTL element related subdevice + */ +unsigned int snd_ctl_elem_id_get_subdevice(const snd_ctl_elem_id_t *obj) +{ + assert(obj); + return obj->subdevice; +} + +/** + * \brief Get name part of a CTL element identifier + * \param obj CTL element identifier + * \return CTL element name + */ +const char *snd_ctl_elem_id_get_name(const snd_ctl_elem_id_t *obj) +{ + assert(obj); + return (const char *)obj->name; +} + +/** + * \brief Get index part of a CTL element identifier + * \param obj CTL element identifier + * \return CTL element index + */ +unsigned int snd_ctl_elem_id_get_index(const snd_ctl_elem_id_t *obj) +{ + assert(obj); + return obj->index; +} + +/** + * \brief Set numeric identifier for a CTL element identifier + * \param obj CTL element identifier + * \param val CTL element numeric identifier + */ +void snd_ctl_elem_id_set_numid(snd_ctl_elem_id_t *obj, unsigned int val) +{ + assert(obj); + obj->numid = val; +} + +/** + * \brief Set interface part for a CTL element identifier + * \param obj CTL element identifier + * \param val CTL element related interface + */ +void snd_ctl_elem_id_set_interface(snd_ctl_elem_id_t *obj, snd_ctl_elem_iface_t val) +{ + assert(obj); + obj->iface = val; +} + +/** + * \brief Set device part for a CTL element identifier + * \param obj CTL element identifier + * \param val CTL element related device + */ +void snd_ctl_elem_id_set_device(snd_ctl_elem_id_t *obj, unsigned int val) +{ + assert(obj); + obj->device = val; +} + +/** + * \brief Set subdevice part for a CTL element identifier + * \param obj CTL element identifier + * \param val CTL element related subdevice + */ +void snd_ctl_elem_id_set_subdevice(snd_ctl_elem_id_t *obj, unsigned int val) +{ + assert(obj); + obj->subdevice = val; +} + +/** + * \brief Set name part for a CTL element identifier + * \param obj CTL element identifier + * \param val CTL element name + */ +void snd_ctl_elem_id_set_name(snd_ctl_elem_id_t *obj, const char *val) +{ + assert(obj); + strncpy((char *)obj->name, val, sizeof(obj->name)); +} + +/** + * \brief Set index part for a CTL element identifier + * \param obj CTL element identifier + * \param val CTL element index + */ +void snd_ctl_elem_id_set_index(snd_ctl_elem_id_t *obj, unsigned int val) +{ + assert(obj); + obj->index = val; +} + +/** + * \brief get size of #snd_ctl_card_info_t + * \return size in bytes + */ +size_t snd_ctl_card_info_sizeof() +{ + return sizeof(snd_ctl_card_info_t); +} + +/** + * \brief allocate an invalid #snd_ctl_card_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_ctl_card_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_ctl_card_info_t + * \param obj pointer to object to free + */ +void snd_ctl_card_info_free(snd_ctl_card_info_t *obj) +{ + free(obj); +} + +/** + * \brief clear given #snd_ctl_card_info_t object + * \param obj pointer to object to clear + */ +void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_card_info_t)); +} + +/** + * \brief copy one #snd_ctl_card_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_ctl_card_info_copy(snd_ctl_card_info_t *dst, const snd_ctl_card_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get card number from a CTL card info + * \param obj CTL card info + * \return card number + */ +int snd_ctl_card_info_get_card(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return obj->card; +} + +/** + * \brief Get card identifier from a CTL card info + * \param obj CTL card info + * \return card identifier + */ +const char *snd_ctl_card_info_get_id(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return (const char *)obj->id; +} + +/** + * \brief Get card driver name from a CTL card info + * \param obj CTL card info + * \return card driver name + */ +const char *snd_ctl_card_info_get_driver(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return (const char *)obj->driver; +} + +/** + * \brief Get card name from a CTL card info + * \param obj CTL card info + * \return card name + */ +const char *snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return (const char *)obj->name; +} + +/** + * \brief Get card long name from a CTL card info + * \param obj CTL card info + * \return card long name + */ +const char *snd_ctl_card_info_get_longname(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return (const char *)obj->longname; +} + +/** + * \brief Get card mixer name from a CTL card info + * \param obj CTL card info + * \return card mixer name + */ +const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return (const char *)obj->mixername; +} + +/** + * \brief Get card component list from a CTL card info + * \param obj CTL card info + * \return card mixer identifier + */ +const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj) +{ + assert(obj); + return (const char *)obj->components; +} + +/** + * \brief get size of #snd_ctl_event_t + * \return size in bytes + */ +size_t snd_ctl_event_sizeof() +{ + return sizeof(snd_ctl_event_t); +} + +/** + * \brief allocate an invalid #snd_ctl_event_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_ctl_event_malloc(snd_ctl_event_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_ctl_event_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_ctl_event_t + * \param obj pointer to object to free + */ +void snd_ctl_event_free(snd_ctl_event_t *obj) +{ + free(obj); +} + +/** + * \brief clear given #snd_ctl_event_t object + * \param obj pointer to object to clear + */ +void snd_ctl_event_clear(snd_ctl_event_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_event_t)); +} + +/** + * \brief copy one #snd_ctl_event_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_ctl_event_copy(snd_ctl_event_t *dst, const snd_ctl_event_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get type of a CTL event + * \param obj CTL event + * \return CTL event type + */ +snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj) +{ + assert(obj); + return obj->type; +} + +/** + * \brief get size of #snd_ctl_elem_list_t + * \return size in bytes + */ +size_t snd_ctl_elem_list_sizeof() +{ + return sizeof(snd_ctl_elem_list_t); +} + +/** + * \brief allocate an invalid #snd_ctl_elem_list_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_ctl_elem_list_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_ctl_elem_list_t + * \param obj pointer to object to free + */ +void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj) +{ + free(obj); +} + +/** + * \brief clear given #snd_ctl_elem_list_t object + * \param obj pointer to object to clear + */ +void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_elem_list_t)); +} + +/** + * \brief copy one #snd_ctl_elem_list_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_ctl_elem_list_copy(snd_ctl_elem_list_t *dst, const snd_ctl_elem_list_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Set index of first wanted CTL element identifier in a CTL element identifiers list + * \param obj CTL element identifiers list + * \param val index of CTL element to put at position 0 of list + */ +void snd_ctl_elem_list_set_offset(snd_ctl_elem_list_t *obj, unsigned int val) +{ + assert(obj); + obj->offset = val; +} + +/** + * \brief Get number of used entries in CTL element identifiers list + * \param obj CTL element identifier list + * \return number of used entries + */ +unsigned int snd_ctl_elem_list_get_used(const snd_ctl_elem_list_t *obj) +{ + assert(obj); + return obj->used; +} + +/** + * \brief Get total count of elements present in CTL device (information present in every filled CTL element identifiers list) + * \param obj CTL element identifier list + * \return total number of elements + */ +unsigned int snd_ctl_elem_list_get_count(const snd_ctl_elem_list_t *obj) +{ + assert(obj); + return obj->count; +} + +/** + * \brief Get CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \param ptr Pointer to returned CTL element identifier + */ +void snd_ctl_elem_list_get_id(const snd_ctl_elem_list_t *obj, unsigned int idx, snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + assert(idx < obj->used); + *ptr = obj->pids[idx]; +} + +/** + * \brief Get CTL element numeric identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element numeric identifier + */ +unsigned int snd_ctl_elem_list_get_numid(const snd_ctl_elem_list_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < obj->used); + return obj->pids[idx].numid; +} + +/** + * \brief Get interface part of CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element related interface + */ +snd_ctl_elem_iface_t snd_ctl_elem_list_get_interface(const snd_ctl_elem_list_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < obj->used); + return obj->pids[idx].iface; +} + +/** + * \brief Get device part of CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element related device + */ +unsigned int snd_ctl_elem_list_get_device(const snd_ctl_elem_list_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < obj->used); + return obj->pids[idx].device; +} + +/** + * \brief Get subdevice part of CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element related subdevice + */ +unsigned int snd_ctl_elem_list_get_subdevice(const snd_ctl_elem_list_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < obj->used); + return obj->pids[idx].subdevice; +} + +/** + * \brief Get name part of CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element name + */ +const char *snd_ctl_elem_list_get_name(const snd_ctl_elem_list_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < obj->used); + return (const char *)obj->pids[idx].name; +} + +/** + * \brief Get index part of CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element index + */ +unsigned int snd_ctl_elem_list_get_index(const snd_ctl_elem_list_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < obj->used); + return obj->pids[idx].index; +} + +/** + * \brief get size of #snd_ctl_elem_info_t + * \return size in bytes + */ +size_t snd_ctl_elem_info_sizeof() +{ + return sizeof(snd_ctl_elem_info_t); +} + +/** + * \brief allocate an invalid #snd_ctl_elem_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_ctl_elem_info_malloc(snd_ctl_elem_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_ctl_elem_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_ctl_elem_info_t + * \param obj pointer to object to free + */ +void snd_ctl_elem_info_free(snd_ctl_elem_info_t *obj) +{ + free(obj); +} + +/** + * \brief clear given #snd_ctl_elem_info_t object + * \param obj pointer to object to clear + */ +void snd_ctl_elem_info_clear(snd_ctl_elem_info_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_elem_info_t)); +} + +/** + * \brief copy one #snd_ctl_elem_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_ctl_elem_info_copy(snd_ctl_elem_info_t *dst, const snd_ctl_elem_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get type from a CTL element id/info + * \param obj CTL element id/info + * \return CTL element content type + */ +snd_ctl_elem_type_t snd_ctl_elem_info_get_type(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->type; +} + +/** + * \brief Get info about readability from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if element is not readable, 1 if element is readable + */ +int snd_ctl_elem_info_is_readable(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_READ); +} + +/** + * \brief Get info about writability from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if element is not writable, 1 if element is not writable + */ +int snd_ctl_elem_info_is_writable(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_WRITE); +} + +/** + * \brief Get info about notification feasibility from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if all element value changes are notified to subscribed applications, 1 otherwise + */ +int snd_ctl_elem_info_is_volatile(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE); +} + +/** + * \brief Get info about status from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if element value is not active, 1 if is active + */ +int snd_ctl_elem_info_is_inactive(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE); +} + +/** + * \brief Get info whether an element is locked + * \param obj CTL element id/info + * \return 0 if element value is currently changeable, 1 if it's locked by another application + */ +int snd_ctl_elem_info_is_locked(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_LOCK); +} + +/** + * \brief Get info if I own an element + * \param obj CTL element id/info + * \return 0 if element value is currently changeable, 1 if it's locked by another application + */ +int snd_ctl_elem_info_is_owner(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_OWNER); +} + +/** + * \brief Get info if it's a user element + * \param obj CTL element id/info + * \return 0 if element value is a system element, 1 if it's a user-created element + */ +int snd_ctl_elem_info_is_user(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_USER); +} + +/** + * \brief Get info about TLV readability from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if element's TLV is not readable, 1 if element's TLV is readable + */ +int snd_ctl_elem_info_is_tlv_readable(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ); +} + +/** + * \brief Get info about TLV writeability from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if element's TLV is not writable, 1 if element's TLV is writable + */ +int snd_ctl_elem_info_is_tlv_writable(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE); +} + +/** + * \brief Get info about TLV command possibility from a CTL element id/info + * \param obj CTL element id/info + * \return 0 if element's TLV command is not possible, 1 if element's TLV command is supported + */ +int snd_ctl_elem_info_is_tlv_commandable(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND); +} + +/** + * \brief (DEPRECATED) Get info about values passing policy from a CTL element value + * \param obj CTL element id/info + * \return 0 if element value need to be passed by contents, 1 if need to be passed with a pointer + */ +int snd_ctl_elem_info_is_indirect(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return 0; +} +link_warning(snd_ctl_elem_info_is_indirect, "Warning: snd_ctl_elem_info_is_indirect is deprecated, do not use it"); + +/** + * \brief Get owner of a locked element + * \param obj CTL element id/info + * \return value entries count + */ +pid_t snd_ctl_elem_info_get_owner(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->owner; +} + +/** + * \brief Get number of value entries from a CTL element id/info + * \param obj CTL element id/info + * \return value entries count + */ +unsigned int snd_ctl_elem_info_get_count(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->count; +} + +/** + * \brief Get minimum value from a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/info + * \param obj CTL element id/info + * \return Minimum value + */ +long snd_ctl_elem_info_get_min(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_INTEGER); + return obj->value.integer.min; +} + +/** + * \brief Get maximum value from a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/info + * \param obj CTL element id/info + * \return Maximum value + */ +long snd_ctl_elem_info_get_max(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_INTEGER); + return obj->value.integer.max; +} + +/** + * \brief Get value step from a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/info + * \param obj CTL element id/info + * \return Step + */ +long snd_ctl_elem_info_get_step(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_INTEGER); + return obj->value.integer.step; +} + +/** + * \brief Get minimum value from a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/info + * \param obj CTL element id/info + * \return Minimum value + */ +long long snd_ctl_elem_info_get_min64(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_INTEGER64); + return obj->value.integer64.min; +} + +/** + * \brief Get maximum value from a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/info + * \param obj CTL element id/info + * \return Maximum value + */ +long long snd_ctl_elem_info_get_max64(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_INTEGER64); + return obj->value.integer64.max; +} + +/** + * \brief Get value step from a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/info + * \param obj CTL element id/info + * \return Step + */ +long long snd_ctl_elem_info_get_step64(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_INTEGER64); + return obj->value.integer64.step; +} + +/** + * \brief Get number of items available from a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/info + * \param obj CTL element id/info + * \return items count + */ +unsigned int snd_ctl_elem_info_get_items(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_ENUMERATED); + return obj->value.enumerated.items; +} + +/** + * \brief Select item in a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/info + * \param obj CTL element id/info + * \param val item number + */ +void snd_ctl_elem_info_set_item(snd_ctl_elem_info_t *obj, unsigned int val) +{ + assert(obj); + obj->value.enumerated.item = val; +} + +/** + * \brief Get name for selected item in a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/info + * \param obj CTL element id/info + * \return name of chosen item + */ +const char *snd_ctl_elem_info_get_item_name(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + assert(obj->type == SND_CTL_ELEM_TYPE_ENUMERATED); + return obj->value.enumerated.name; +} + +/** + * \brief Get count of dimensions for given element + * \param obj CTL element id/info + * \return zero value if no dimensions are defined, otherwise positive value with count of dimensions + */ +#ifndef DOXYGEN +int INTERNAL(snd_ctl_elem_info_get_dimensions)(const snd_ctl_elem_info_t *obj) +#else +int snd_ctl_elem_info_get_dimensions(const snd_ctl_elem_info_t *obj) +#endif +{ + int i; + + assert(obj); + for (i = 3; i >= 0; i--) + if (obj->dimen.d[i]) + break; + return i + 1; +} +use_default_symbol_version(__snd_ctl_elem_info_get_dimensions, snd_ctl_elem_info_get_dimensions, ALSA_0.9.3); + +/** + * \brief Get specified of dimension width for given element + * \param obj CTL element id/info + * \param idx The dimension index + * \return zero value if no dimension width is defined, otherwise positive value with with of specified dimension + */ +#ifndef DOXYGEN +int INTERNAL(snd_ctl_elem_info_get_dimension)(const snd_ctl_elem_info_t *obj, unsigned int idx) +#else +int snd_ctl_elem_info_get_dimension(const snd_ctl_elem_info_t *obj, unsigned int idx) +#endif +{ + assert(obj); + if (idx >= 3) + return 0; + return obj->dimen.d[idx]; +} +use_default_symbol_version(__snd_ctl_elem_info_get_dimension, snd_ctl_elem_info_get_dimension, ALSA_0.9.3); + +/** + * \brief Get CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param ptr Pointer to returned CTL element identifier + */ +void snd_ctl_elem_info_get_id(const snd_ctl_elem_info_t *obj, snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + *ptr = obj->id; +} + +/** + * \brief Get element numeric identifier of a CTL element id/info + * \param obj CTL element id/info + * \return element numeric identifier + */ +unsigned int snd_ctl_elem_info_get_numid(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->id.numid; +} + +/** + * \brief Get interface part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \return interface part of element identifier + */ +snd_ctl_elem_iface_t snd_ctl_elem_info_get_interface(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->id.iface; +} + +/** + * \brief Get device part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \return device part of element identifier + */ +unsigned int snd_ctl_elem_info_get_device(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->id.device; +} + +/** + * \brief Get subdevice part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \return subdevice part of element identifier + */ +unsigned int snd_ctl_elem_info_get_subdevice(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->id.subdevice; +} + +/** + * \brief Get name part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \return name part of element identifier + */ +const char *snd_ctl_elem_info_get_name(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return (const char *)obj->id.name; +} + +/** + * \brief Get index part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \return index part of element identifier + */ +unsigned int snd_ctl_elem_info_get_index(const snd_ctl_elem_info_t *obj) +{ + assert(obj); + return obj->id.index; +} + +/** + * \brief Set CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param ptr CTL element identifier + */ +void snd_ctl_elem_info_set_id(snd_ctl_elem_info_t *obj, const snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + obj->id = *ptr; +} + +/** + * \brief Set element numeric identifier of a CTL element id/info + * \param obj CTL element id/info + * \param val element numeric identifier + */ +void snd_ctl_elem_info_set_numid(snd_ctl_elem_info_t *obj, unsigned int val) +{ + assert(obj); + obj->id.numid = val; +} + +/** + * \brief Set interface part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param val interface part of element identifier + */ +void snd_ctl_elem_info_set_interface(snd_ctl_elem_info_t *obj, snd_ctl_elem_iface_t val) +{ + assert(obj); + obj->id.iface = val; +} + +/** + * \brief Set device part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param val device part of element identifier + */ +void snd_ctl_elem_info_set_device(snd_ctl_elem_info_t *obj, unsigned int val) +{ + assert(obj); + obj->id.device = val; +} + +/** + * \brief Set subdevice part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param val subdevice part of element identifier + */ +void snd_ctl_elem_info_set_subdevice(snd_ctl_elem_info_t *obj, unsigned int val) +{ + assert(obj); + obj->id.subdevice = val; +} + +/** + * \brief Set name part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param val name part of element identifier + */ +void snd_ctl_elem_info_set_name(snd_ctl_elem_info_t *obj, const char *val) +{ + assert(obj); + strncpy((char *)obj->id.name, val, sizeof(obj->id.name)); +} + +/** + * \brief Set index part of CTL element identifier of a CTL element id/info + * \param obj CTL element id/info + * \param val index part of element identifier + */ +void snd_ctl_elem_info_set_index(snd_ctl_elem_info_t *obj, unsigned int val) +{ + assert(obj); + obj->id.index = val; +} + +/** + * \brief get size of #snd_ctl_elem_value_t + * \return size in bytes + */ +size_t snd_ctl_elem_value_sizeof() +{ + return sizeof(snd_ctl_elem_value_t); +} + +/** + * \brief allocate an invalid #snd_ctl_elem_value_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_ctl_elem_value_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_ctl_elem_value_t + * \param obj pointer to object to free + */ +void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj) +{ + free(obj); +} + +/** + * \brief clear given #snd_ctl_elem_value_t object + * \param obj pointer to object to clear + */ +void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_elem_value_t)); +} + +/** + * \brief copy one #snd_ctl_elem_value_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_ctl_elem_value_copy(snd_ctl_elem_value_t *dst, const snd_ctl_elem_value_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief compare one #snd_ctl_elem_value_t to another + * \param dst pointer to destination + * \param src pointer to source + * \return 0 on match, less than or greater than otherwise, see memcmp + */ +int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, const snd_ctl_elem_value_t *right) +{ + assert(left && right); + return memcmp(left, right, sizeof(*left)); +} + +/** + * \brief Get CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param ptr Pointer to returned CTL element identifier + */ +void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + *ptr = obj->id; +} + +/** + * \brief Get element numeric identifier of a CTL element id/value + * \param obj CTL element id/value + * \return element numeric identifier + */ +unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return obj->id.numid; +} + +/** + * \brief Get interface part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return interface part of element identifier + */ +snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return obj->id.iface; +} + +/** + * \brief Get device part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return device part of element identifier + */ +unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return obj->id.device; +} + +/** + * \brief Get subdevice part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return subdevice part of element identifier + */ +unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return obj->id.subdevice; +} + +/** + * \brief Get name part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return name part of element identifier + */ +const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return (const char *)obj->id.name; +} + +/** + * \brief Get index part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return index part of element identifier + */ +unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return obj->id.index; +} + +/** + * \brief Set CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param ptr CTL element identifier + */ +void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + obj->id = *ptr; +} + +/** + * \brief Set element numeric identifier of a CTL element id/value + * \param obj CTL element id/value + * \param val element numeric identifier + */ +void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val) +{ + assert(obj); + obj->id.numid = val; +} + +/** + * \brief Set interface part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param val interface part of element identifier + */ +void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_iface_t val) +{ + assert(obj); + obj->id.iface = val; +} + +/** + * \brief Set device part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param val device part of element identifier + */ +void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val) +{ + assert(obj); + obj->id.device = val; +} + +/** + * \brief Set subdevice part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param val subdevice part of element identifier + */ +void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int val) +{ + assert(obj); + obj->id.subdevice = val; +} + +/** + * \brief Set name part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param val name part of element identifier + */ +void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val) +{ + assert(obj); + strncpy((char *)obj->id.name, val, sizeof(obj->id.name)); +} + +/** + * \brief Set index part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param val index part of element identifier + */ +void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) +{ + assert(obj); + obj->id.index = val; +} + +/** + * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_BOOLEAN CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \return value for the entry + */ +int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < sizeof(obj->value.integer.value) / sizeof(obj->value.integer.value[0])); + return obj->value.integer.value[idx]; +} + +/** + * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \return value for the entry + */ +long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < sizeof(obj->value.integer.value) / sizeof(obj->value.integer.value[0])); + return obj->value.integer.value[idx]; +} + +/** + * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \return value for the entry + */ +long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < sizeof(obj->value.integer64.value) / sizeof(obj->value.integer64.value[0])); + return obj->value.integer64.value[idx]; +} + +/** + * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \return value for the entry + */ +unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < sizeof(obj->value.enumerated.item) / sizeof(obj->value.enumerated.item[0])); + return obj->value.enumerated.item[idx]; +} + +/** + * \brief Get value for an entry of a #SND_CTL_ELEM_TYPE_BYTES CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \return value for the entry + */ +unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < sizeof(obj->value.bytes.data)); + return obj->value.bytes.data[idx]; +} + +/** + * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_BOOLEAN CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \param val value for the entry + */ +void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val) +{ + assert(obj); + obj->value.integer.value[idx] = val; +} + +/** + * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \param val value for the entry + */ +void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val) +{ + assert(obj); + obj->value.integer.value[idx] = val; +} + +/** + * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_INTEGER64 CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \param val value for the entry + */ +void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val) +{ + assert(obj); + obj->value.integer64.value[idx] = val; +} + +/** + * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_ENUMERATED CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \param val value for the entry + */ +void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val) +{ + assert(obj); + obj->value.enumerated.item[idx] = val; +} + +/** + * \brief Set value for an entry of a #SND_CTL_ELEM_TYPE_BYTES CTL element id/value + * \param obj CTL element id/value + * \param idx Entry index + * \param val value for the entry + */ +void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val) +{ + assert(obj); + obj->value.bytes.data[idx] = val; +} + +/** + * \brief Set CTL element #SND_CTL_ELEM_TYPE_BYTES value + * \param obj CTL handle + * \param data Bytes value + * \param size Size in bytes + */ +void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) +{ + assert(obj); + if (size >= sizeof(obj->value.bytes.data)) { + assert(0); + return; + } + memcpy(obj->value.bytes.data, data, size); +} + +/** + * \brief Get value for a #SND_CTL_ELEM_TYPE_BYTES CTL element id/value + * \param obj CTL element id/value + * \return Pointer to CTL element value + */ +const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) +{ + assert(obj); + return obj->value.bytes.data; +} + +/** + * \brief Get value for a #SND_CTL_ELEM_TYPE_IEC958 CTL element id/value + * \param obj CTL element id/value + * \param ptr Pointer to returned CTL element value + */ +void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr) +{ + assert(obj && ptr); + memcpy(ptr, &obj->value.iec958, sizeof(*ptr)); +} + +/** + * \brief Set value for a #SND_CTL_ELEM_TYPE_IEC958 CTL element id/value + * \param obj CTL element id/value + * \param ptr Pointer to CTL element value + */ +void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr) +{ + assert(obj && ptr); + memcpy(&obj->value.iec958, ptr, sizeof(obj->value.iec958)); +} + diff --git a/src/control/control_ext.c b/src/control/control_ext.c new file mode 100644 index 0000000..e20d4f3 --- /dev/null +++ b/src/control/control_ext.c @@ -0,0 +1,691 @@ +/** + * \file control/control_ext.c + * \ingroup CtlPlugin_SDK + * \brief External Control Plugin SDK + * \author Takashi Iwai + * \date 2005 + */ +/* + * Control Interface - External Control Plugin SDK + * + * Copyright (c) 2005 Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "control_local.h" +#include "control_external.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_control_ext = ""; +#endif + +static int snd_ctl_ext_close(snd_ctl_t *handle) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->close) + ext->callback->close(ext); + return 0; +} + +static int snd_ctl_ext_nonblock(snd_ctl_t *handle, int nonblock) +{ + snd_ctl_ext_t *ext = handle->private_data; + + ext->nonblock = nonblock; + return 0; +} + +static int snd_ctl_ext_async(snd_ctl_t *ctl ATTRIBUTE_UNUSED, + int sig ATTRIBUTE_UNUSED, + pid_t pid ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +static int snd_ctl_ext_subscribe_events(snd_ctl_t *handle, int subscribe) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (subscribe < 0) + return ext->subscribed; + ext->subscribed = !!subscribe; + if (ext->callback->subscribe_events) + ext->callback->subscribe_events(ext, subscribe); + return 0; +} + +static int snd_ctl_ext_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info) +{ + snd_ctl_ext_t *ext = handle->private_data; + + memset(info, 0, sizeof(*info)); + info->card = ext->card_idx; + memcpy(info->id, ext->id, sizeof(info->id)); + memcpy(info->driver, ext->driver, sizeof(info->driver)); + memcpy(info->name, ext->name, sizeof(info->name)); + memcpy(info->longname, ext->longname, sizeof(info->longname)); + memcpy(info->mixername, ext->mixername, sizeof(info->mixername)); + return 0; +} + +static int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) +{ + snd_ctl_ext_t *ext = handle->private_data; + int ret; + unsigned int i, offset; + snd_ctl_elem_id_t *ids; + + list->count = ext->callback->elem_count(ext); + list->used = 0; + ids = list->pids; + offset = list->offset; + for (i = 0; i < list->space; i++) { + if (offset >= list->count) + break; + snd_ctl_elem_id_clear(ids); + ret = ext->callback->elem_list(ext, offset, ids); + if (ret < 0) + return ret; + ids->numid = offset + 1; /* fake number */ + list->used++; + offset++; + ids++; + } + return 0; +} + +static snd_ctl_ext_key_t get_elem(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id) +{ + int numid = id->numid; + if (numid > 0) { + ext->callback->elem_list(ext, numid - 1, id); + id->numid = numid; + } else + id->numid = 0; + return ext->callback->find_elem(ext, id); +} + +static int snd_ctl_ext_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + + key = get_elem(ext, &info->id); + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &info->access, &info->count); + if (ret < 0) + goto err; + info->type = type; + ret = -EINVAL; + switch (info->type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + info->value.integer.min = 0; + info->value.integer.max = 1; + ret = 0; + break; + case SND_CTL_ELEM_TYPE_INTEGER: + if (! ext->callback->get_integer_info) + goto err; + ret = ext->callback->get_integer_info(ext, key, &info->value.integer.min, + &info->value.integer.max, + &info->value.integer.step); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + if (! ext->callback->get_integer64_info) + goto err; + { + int64_t xmin, xmax, xstep; + ret = ext->callback->get_integer64_info(ext, key, + &xmin, + &xmax, + &xstep); + info->value.integer64.min = xmin; + info->value.integer64.max = xmax; + info->value.integer64.step = xstep; + } + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + if (! ext->callback->get_enumerated_info) + goto err; + ret = ext->callback->get_enumerated_info(ext, key, &info->value.enumerated.items); + ext->callback->get_enumerated_name(ext, key, info->value.enumerated.item, + info->value.enumerated.name, + sizeof(info->value.enumerated.name)); + break; + default: + ret = 0; + break; + } + + err: + if (ext->callback->free_key) + ext->callback->free_key(ext, key); + + return ret; +} + +static int snd_ctl_ext_elem_add(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_replace(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_remove(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + unsigned int access, count; + + key = get_elem(ext, &control->id); + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &access, &count); + if (ret < 0) + goto err; + ret = -EINVAL; + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + case SND_CTL_ELEM_TYPE_INTEGER: + if (! ext->callback->read_integer) + goto err; + ret = ext->callback->read_integer(ext, key, control->value.integer.value); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + if (! ext->callback->read_integer64) + goto err; + ret = ext->callback->read_integer64(ext, key, + (int64_t*)control->value.integer64.value); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + if (! ext->callback->read_enumerated) + goto err; + ret = ext->callback->read_enumerated(ext, key, control->value.enumerated.item); + break; + case SND_CTL_ELEM_TYPE_BYTES: + if (! ext->callback->read_bytes) + goto err; + ret = ext->callback->read_bytes(ext, key, control->value.bytes.data, + sizeof(control->value.bytes.data)); + break; + case SND_CTL_ELEM_TYPE_IEC958: + if (! ext->callback->read_iec958) + goto err; + ret = ext->callback->read_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958); + break; + default: + break; + } + + err: + if (ext->callback->free_key) + ext->callback->free_key(ext, key); + + return ret; +} + +static int snd_ctl_ext_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + unsigned int access, count; + + key = get_elem(ext, &control->id); + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &access, &count); + if (ret < 0) + goto err; + ret = -EINVAL; + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + case SND_CTL_ELEM_TYPE_INTEGER: + if (! ext->callback->write_integer) + goto err; + ret = ext->callback->write_integer(ext, key, control->value.integer.value); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + if (! ext->callback->write_integer64) + goto err; + ret = ext->callback->write_integer64(ext, key, (int64_t *)control->value.integer64.value); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + if (! ext->callback->write_enumerated) + goto err; + ret = ext->callback->write_enumerated(ext, key, control->value.enumerated.item); + break; + case SND_CTL_ELEM_TYPE_BYTES: + if (! ext->callback->write_bytes) + goto err; + ret = ext->callback->write_bytes(ext, key, control->value.bytes.data, + sizeof(control->value.bytes.data)); + break; + case SND_CTL_ELEM_TYPE_IEC958: + if (! ext->callback->write_iec958) + goto err; + ret = ext->callback->write_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958); + break; + default: + break; + } + + err: + if (ext->callback->free_key) + ext->callback->free_key(ext, key); + + return ret; +} + +static int snd_ctl_ext_elem_lock(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_unlock(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_next_device(snd_ctl_t *handle ATTRIBUTE_UNUSED, + int *device ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_prefer_subdevice(snd_ctl_t *handle ATTRIBUTE_UNUSED, + int subdev ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_hwdep_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_hwdep_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_pcm_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_pcm_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_rawmidi_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_rawmidi_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_set_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED, + unsigned int state ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_ctl_ext_get_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED, + unsigned int *state ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event) +{ + snd_ctl_ext_t *ext = handle->private_data; + + memset(event, 0, sizeof(*event)); + return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); +} + +static int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->poll_descriptors_count) + return ext->callback->poll_descriptors_count(ext); + if (ext->poll_fd >= 0) + return 1; + return 0; +} + +static int snd_ctl_ext_poll_descriptors(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->poll_descriptors) + return ext->callback->poll_descriptors(ext, pfds, space); + if (ext->poll_fd < 0) + return 0; + if (space > 0) { + pfds->fd = ext->poll_fd; + pfds->events = POLLIN|POLLERR|POLLNVAL; + return 1; + } + return 0; +} + +static int snd_ctl_ext_poll_revents(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->poll_revents) + return ext->callback->poll_revents(ext, pfds, nfds, revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +static const snd_ctl_ops_t snd_ctl_ext_ops = { + .close = snd_ctl_ext_close, + .nonblock = snd_ctl_ext_nonblock, + .async = snd_ctl_ext_async, + .subscribe_events = snd_ctl_ext_subscribe_events, + .card_info = snd_ctl_ext_card_info, + .element_list = snd_ctl_ext_elem_list, + .element_info = snd_ctl_ext_elem_info, + .element_add = snd_ctl_ext_elem_add, + .element_replace = snd_ctl_ext_elem_replace, + .element_remove = snd_ctl_ext_elem_remove, + .element_read = snd_ctl_ext_elem_read, + .element_write = snd_ctl_ext_elem_write, + .element_lock = snd_ctl_ext_elem_lock, + .element_unlock = snd_ctl_ext_elem_unlock, + .hwdep_next_device = snd_ctl_ext_next_device, + .hwdep_info = snd_ctl_ext_hwdep_info, + .pcm_next_device = snd_ctl_ext_next_device, + .pcm_info = snd_ctl_ext_pcm_info, + .pcm_prefer_subdevice = snd_ctl_ext_prefer_subdevice, + .rawmidi_next_device = snd_ctl_rawmidi_next_device, + .rawmidi_info = snd_ctl_ext_rawmidi_info, + .rawmidi_prefer_subdevice = snd_ctl_ext_prefer_subdevice, + .set_power_state = snd_ctl_ext_set_power_state, + .get_power_state = snd_ctl_ext_get_power_state, + .read = snd_ctl_ext_read, + .poll_descriptors_count = snd_ctl_ext_poll_descriptors_count, + .poll_descriptors = snd_ctl_ext_poll_descriptors, + .poll_revents = snd_ctl_ext_poll_revents, +}; + +/* + * Exported functions + */ + +/*! \page ctl_external_plugins External Control Plugin SDK + +\section ctl_externals External Control Plugins + +The external plugins are implemented in a shared object file located +at /usr/lib/alsa-lib (the exact location depends on the build option +and asoundrc configuration). It has to be the file like +libasound_module_ctl_MYPLUGIN.so, where MYPLUGIN corresponds to your +own plugin name. + +The entry point of the plugin is defined via +#SND_CTL_PLUGIN_DEFINE_FUNC() macro. This macro defines the function +with a proper name to be referred from alsa-lib. The function takes +the following 5 arguments: +\code +int (snd_ctl_t **phandle, const char *name, snd_config_t *root, + snd_config_t *conf, int mode) +\endcode +The first argument, phandle, is the pointer to store the resultant control +handle. The arguments name, root and mode are the parameters +to be passed to the plugin constructor. The conf is the configuration +tree for the plugin. The arguments above are defined in the macro +itself, so don't use variables with the same names to shadow +parameters. + +After parsing the configuration parameters in the given conf tree, +usually you will call the external plugin API function +#snd_ctl_ext_create(). +The control handle must be filled *phandle in return. +Then this function must return either a value 0 when succeeded, or a +negative value as the error code. + +Finally, add #SND_CTL_PLUGIN_SYMBOL() with the name of your +plugin as the argument at the end. This defines the proper versioned +symbol as the reference. + +The typical code would look like below: +\code +struct myctl_info { + snd_ctl_ext_t ext; + int my_own_data; + ... +}; + +SND_CTL_PLUGIN_DEFINE_FUNC(myctl) +{ + snd_config_iterator_t i, next; + struct myctl_info *myctl; + int err; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) + continue; + if (strcmp(id, "my_own_parameter") == 0) { + .... + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + + myctl = calloc(1, sizeof(*myctl)); + if (myctl == NULL) + return -ENOMEM; + + myctl->ext.version = SND_CTL_EXT_VERSION; + myctl->ext.card_idx = 0; + strcpy(myctl->ext.id, "Myctl"); + strcpy(myctl->ext.name, "My Control"); + strcpy(myctl->ext.longname, "My External Control for Foobar"); + strcpy(myctl->ext.mixername, "My Control"); + myctl->ext.callback = &my_own_callback; + myctl->ext.private_data = myctl; + .... + + err = snd_pcm_extplug_create(&myctl->ext, name, mode); + if (err < 0) { + myctl_free(myctl); + return err; + } + + *phandle = myctl->ext.handle; + return 0; +} + +SND_CTL_PLUGIN_SYMBOL(myctl); +\endcode + +Read the codes in alsa-plugins package for the real examples. + + +\section ctl_ext_impl Implementation of External Control Plugins + +The following fields have to be filled in external control record before calling +#snd_ctl_ext_create() : version, card_idx, id, name, longname, mixername, poll_fd and callback. +Otherfields are optional and should be initialized with zero. + +The constant #SND_CTL_EXT_VERSION must be passed to the version +field for the version check in alsa-lib. The card_idx field specifies the card +index of this control. [FIXME: solve confliction of card index in alsa-lib?] + +The id, name, longname and mixername fields are the strings shown in the card_info +inqurirys. They are the char arrays, so you have to copy strings to these +fields. + +The callback field contains the table of callback functions for this plugin (defined as +#snd_ctl_ext_callback_t). +The poll_fd can be used to specify the poll file descriptor for this control. +Set -1 if not available. Alternatively, you can define poll_descriptors_count and +poll_descriptors callbacks in the callback table for handling the poll descriptor(s) +dynamically after the creation of plugin instance. + +The driver can set an arbitrary value (pointer) to private_data +field to refer its own data in the callbacks. + +The rest fields are filled by #snd_ctl_ext_create(). The handle field +is the resultant PCM handle. The others are the current status of the +PCM. + +\section ctl_ext_impl Callback Functions of External Control Plugins + +The callback functions in #snd_ctl_ext_callback_t define the real +behavior of the driver. There are many callbacks but many of them are optional. + +The close callback is called when the PCM is closed. If the plugin +allocates private resources, this is the place to release them +again. This callback is optional. + +The elem_count and elem_list callbacks are mandatory. The elem_count returns the +total number of control elements. The elem_list returns the control element ID +of the corresponding element offset (the offset is from 0 to elem_count - 1). +The id field is initialized to all zero in prior to elem_list callback. The callback +has to fill the necessary field (typically iface, name and index) in return via the +standard control API functions like #snd_ctl_elem_id_set_interface, +#snd_ctl_elem_id_set_name and #snd_ctl_elem_id_set_index, etc. The callbacks should +return 0 if successful, or a negative error code. + +The find_elem callback is used to convert the given control element ID to the +certain key value for the faster access to get, read and write callbacks. +The key type is alias of unsigned long, so you can assign some static number +(e.g. index of the array) to this value of the corresponding element, or +assign the pointer (cast to #snd_ctl_ext_key_t). When no key is defined or found, +return #SND_CTL_EXT_KEY_NOT_FOUND. This callback is (very likely) required +if you use get, read and write callbacks as follows. +If you need to create a record dynamically (e.g. via malloc) at each find_elem call, +the allocated record can be released with the optional free_key callback. + +The get_attribute is a mandatory callback, which returns the attribute of the +control element given via a key value (converted with find_elem callback). +It must fill the control element type (#snd_ctl_elem_type_t), the access type +(#snd_ctl_ext_access_t), and the count (element array size). The callback returns +0 if successful, or a negative error code, as usual. + +The get_integer_info, get_integetr64_info and get_enumerated_info callbacks are called +to return the information of the given control element for each element type. +For integer and integer64 types, the callbacks need to fill the minimal (imin), +maximal (imax) and the step (istep) values of the control. For the enumerated type, +the number of enum items must be filled. Additionally, the enum control has to define +get_enumerated_name callback to store the name of the enumerated item of the given control +element. All functions return 0 if successful, or a negative error code. + +For reading the current values of a control element, read_integer, read_integer64, +read_enumerated, read_bytes and read_iec958 callbacks are called depending on the +element type. These callbacks have to fill the current values of the element in return. +Note that a control element can be an array. If it contains more than one values +(i.e. the count value in get_attribute callback is more than 1), all values +must be filled on the given value pointer as an array. Also, note that the boolean type +is handled as integer here (although boolean type doesn't need to define the corresponding +info callback since it's obvious). These callbacks return 0 if successful, or +a negative error code. + +For writing the current values, write_integer, write_integer64, write_bytes, and +write_iec958 callbacks are called as well as for read. The callbacks should check the +current values and compare with the given values. If they are identical, the callbacks +should do nothing and return 0. If they differ, update the current values and return 1, +instead. For any errors, return a negative error code. + +The subscribe_events callback is called when the application subscribes or cancels +the event notifications (e.g. through mixer API). The current value of event +subscription is kept in the subscribed field. +The read_event callback is called for reading a pending notification event. +The callback needs to fill the event_mask value, a bit-field defined as SND_CTL_EVENT_MASK_XXX. +If no event is pending, return -EAGAIN. These two callbacks are optional. + +The poll_descriptors_count and poll_descriptors callbacks are used to return +the poll descriptor(s) via callbacks. As already mentioned, if the callback cannot +set the static poll_fd, you can define these callbacks to return dynamically. +Also, when multiple poll descriptors are required, use these callbacks. +The poll_revents callback is used for handle poll revents. + +*/ + +/** + * \brief Create an external control plugin instance + * \param ext the plugin handle + * \param name name of control + * \param mode control open mode + * \return 0 if successful, or a negative error code + * + * Creates the external control instance. + * + */ +int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode) +{ + snd_ctl_t *ctl; + int err; + + if (ext->version != SND_CTL_EXT_VERSION) { + SNDERR("ctl_ext: Plugin version mismatch\n"); + return -ENXIO; + } + + err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name); + if (err < 0) + return err; + + ext->handle = ctl; + + ctl->ops = &snd_ctl_ext_ops; + ctl->private_data = ext; + ctl->poll_fd = ext->poll_fd; + if (mode & SND_CTL_NONBLOCK) + ext->nonblock = 1; + + return 0; +} + +/** + * \brief Delete the external control plugin + * \param ext the plugin handle + * \return 0 if successful, or a negative error code + */ +int snd_ctl_ext_delete(snd_ctl_ext_t *ext) +{ + return snd_ctl_close(ext->handle); +} diff --git a/src/control/control_hw.c b/src/control/control_hw.c new file mode 100644 index 0000000..cf258b4 --- /dev/null +++ b/src/control/control_hw.c @@ -0,0 +1,458 @@ +/* + * Control Interface - Hardware + * Copyright (c) 1998,1999,2000 by Jaroslav Kysela + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "control_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_control_hw = ""; +#endif + +#ifndef F_SETSIG +#define F_SETSIG 10 +#endif + +#ifndef DOC_HIDDEN +#define SNDRV_FILE_CONTROL ALSA_DEVICE_DIRECTORY "controlC%i" +#define SNDRV_CTL_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 4) + +typedef struct { + int card; + int fd; + unsigned int protocol; +} snd_ctl_hw_t; +#endif /* DOC_HIDDEN */ + +static int snd_ctl_hw_close(snd_ctl_t *handle) +{ + snd_ctl_hw_t *hw = handle->private_data; + int res; + res = close(hw->fd) < 0 ? -errno : 0; + free(hw); + return res; +} + +static int snd_ctl_hw_nonblock(snd_ctl_t *handle, int nonblock) +{ + snd_ctl_hw_t *hw = handle->private_data; + long flags; + int fd = hw->fd; + if ((flags = fcntl(fd, F_GETFL)) < 0) { + SYSERR("F_GETFL failed"); + return -errno; + } + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) < 0) { + SYSERR("F_SETFL for O_NONBLOCK failed"); + return -errno; + } + return 0; +} + +static int snd_ctl_hw_async(snd_ctl_t *ctl, int sig, pid_t pid) +{ + long flags; + snd_ctl_hw_t *hw = ctl->private_data; + int fd = hw->fd; + + if ((flags = fcntl(fd, F_GETFL)) < 0) { + SYSERR("F_GETFL failed"); + return -errno; + } + if (sig >= 0) + flags |= O_ASYNC; + else + flags &= ~O_ASYNC; + if (fcntl(fd, F_SETFL, flags) < 0) { + SYSERR("F_SETFL for O_ASYNC failed"); + return -errno; + } + if (sig < 0) + return 0; + if (fcntl(fd, F_SETSIG, (long)sig) < 0) { + SYSERR("F_SETSIG failed"); + return -errno; + } + if (fcntl(fd, F_SETOWN, (long)pid) < 0) { + SYSERR("F_SETOWN failed"); + return -errno; + } + return 0; +} + +static int snd_ctl_hw_subscribe_events(snd_ctl_t *handle, int subscribe) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, &subscribe) < 0) { + SYSERR("SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS failed"); + return -errno; + } + return 0; +} + +static int snd_ctl_hw_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_CARD_INFO, info) < 0) { + SYSERR("SNDRV_CTL_IOCTL_CARD_INFO failed"); + return -errno; + } + return 0; +} + +static int snd_ctl_hw_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_LIST, list) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_INFO, info) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_add(snd_ctl_t *handle, snd_ctl_elem_info_t *info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_ADD, info) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_replace(snd_ctl_t *handle, snd_ctl_elem_info_t *info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_REPLACE, info) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_remove(snd_ctl_t *handle, snd_ctl_elem_id_t *id) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_REMOVE, id) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_READ, control) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, control) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_lock(snd_ctl_t *handle, snd_ctl_elem_id_t *id) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_LOCK, id) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_unlock(snd_ctl_t *handle, snd_ctl_elem_id_t *id) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_UNLOCK, id) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_elem_tlv(snd_ctl_t *handle, int op_flag, + unsigned int numid, + unsigned int *tlv, unsigned int tlv_size) +{ + int inum; + snd_ctl_hw_t *hw = handle->private_data; + struct sndrv_ctl_tlv *xtlv; + + /* we don't support TLV on protocol ver 2.0.3 or earlier */ + if (hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 4)) + return -ENXIO; + + switch (op_flag) { + case -1: inum = SNDRV_CTL_IOCTL_TLV_COMMAND; break; + case 0: inum = SNDRV_CTL_IOCTL_TLV_READ; break; + case 1: inum = SNDRV_CTL_IOCTL_TLV_WRITE; break; + default: return -EINVAL; + } + xtlv = malloc(sizeof(struct sndrv_ctl_tlv) + tlv_size); + if (xtlv == NULL) + return -ENOMEM; + xtlv->numid = numid; + xtlv->length = tlv_size; + memcpy(xtlv->tlv, tlv, tlv_size); + if (ioctl(hw->fd, inum, xtlv) < 0) { + free(xtlv); + return -errno; + } + if (op_flag == 0) { + if (xtlv->tlv[1] + 2 * sizeof(unsigned int) > tlv_size) + return -EFAULT; + memcpy(tlv, xtlv->tlv, xtlv->tlv[1] + 2 * sizeof(unsigned int)); + } + free(xtlv); + return 0; +} + +static int snd_ctl_hw_hwdep_next_device(snd_ctl_t *handle, int * device) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, device) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_hwdep_info(snd_ctl_t *handle, snd_hwdep_info_t * info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_HWDEP_INFO, info) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_pcm_next_device(snd_ctl_t *handle, int * device) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, device) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_pcm_info(snd_ctl_t *handle, snd_pcm_info_t * info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_PCM_INFO, info) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_pcm_prefer_subdevice(snd_ctl_t *handle, int subdev) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, &subdev) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_rawmidi_next_device(snd_ctl_t *handle, int * device) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE, device) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_RAWMIDI_INFO, info) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_rawmidi_prefer_subdevice(snd_ctl_t *handle, int subdev) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE, &subdev) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_set_power_state(snd_ctl_t *handle, unsigned int state) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_POWER, &state) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_get_power_state(snd_ctl_t *handle, unsigned int *state) +{ + snd_ctl_hw_t *hw = handle->private_data; + if (ioctl(hw->fd, SNDRV_CTL_IOCTL_POWER_STATE, state) < 0) + return -errno; + return 0; +} + +static int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event) +{ + snd_ctl_hw_t *hw = handle->private_data; + ssize_t res = read(hw->fd, event, sizeof(*event)); + if (res <= 0) + return -errno; + if (CHECK_SANITY(res != sizeof(*event))) { + SNDMSG("snd_ctl_hw_read: read size error (req:%d, got:%d)\n", + sizeof(*event), res); + return -EINVAL; + } + return 1; +} + +static const snd_ctl_ops_t snd_ctl_hw_ops = { + .close = snd_ctl_hw_close, + .nonblock = snd_ctl_hw_nonblock, + .async = snd_ctl_hw_async, + .subscribe_events = snd_ctl_hw_subscribe_events, + .card_info = snd_ctl_hw_card_info, + .element_list = snd_ctl_hw_elem_list, + .element_info = snd_ctl_hw_elem_info, + .element_add = snd_ctl_hw_elem_add, + .element_replace = snd_ctl_hw_elem_replace, + .element_remove = snd_ctl_hw_elem_remove, + .element_read = snd_ctl_hw_elem_read, + .element_write = snd_ctl_hw_elem_write, + .element_lock = snd_ctl_hw_elem_lock, + .element_unlock = snd_ctl_hw_elem_unlock, + .element_tlv = snd_ctl_hw_elem_tlv, + .hwdep_next_device = snd_ctl_hw_hwdep_next_device, + .hwdep_info = snd_ctl_hw_hwdep_info, + .pcm_next_device = snd_ctl_hw_pcm_next_device, + .pcm_info = snd_ctl_hw_pcm_info, + .pcm_prefer_subdevice = snd_ctl_hw_pcm_prefer_subdevice, + .rawmidi_next_device = snd_ctl_hw_rawmidi_next_device, + .rawmidi_info = snd_ctl_hw_rawmidi_info, + .rawmidi_prefer_subdevice = snd_ctl_hw_rawmidi_prefer_subdevice, + .set_power_state = snd_ctl_hw_set_power_state, + .get_power_state = snd_ctl_hw_get_power_state, + .read = snd_ctl_hw_read, +}; + +int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) +{ + int fd, ver; + char filename[sizeof(SNDRV_FILE_CONTROL) + 10]; + int fmode; + snd_ctl_t *ctl; + snd_ctl_hw_t *hw; + int err; + + *handle = NULL; + + if (CHECK_SANITY(card < 0 || card >= 32)) { + SNDMSG("Invalid card index %d", card); + return -EINVAL; + } + sprintf(filename, SNDRV_FILE_CONTROL, card); + if (mode & SND_CTL_READONLY) + fmode = O_RDONLY; + else + fmode = O_RDWR; + if (mode & SND_CTL_NONBLOCK) + fmode |= O_NONBLOCK; + if (mode & SND_CTL_ASYNC) + fmode |= O_ASYNC; + fd = snd_open_device(filename, fmode); + if (fd < 0) { + snd_card_load(card); + fd = snd_open_device(filename, fmode); + if (fd < 0) + return -errno; + } + if (ioctl(fd, SNDRV_CTL_IOCTL_PVERSION, &ver) < 0) { + err = -errno; + close(fd); + return err; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_CTL_VERSION_MAX)) { + close(fd); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } + hw = calloc(1, sizeof(snd_ctl_hw_t)); + if (hw == NULL) { + close(fd); + return -ENOMEM; + } + hw->card = card; + hw->fd = fd; + hw->protocol = ver; + + err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name); + if (err < 0) { + close(fd); + free(hw); + } + ctl->ops = &snd_ctl_hw_ops; + ctl->private_data = hw; + ctl->poll_fd = fd; + *handle = ctl; + return 0; +} + +int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + long card = -1; + const char *str; + int err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_get_index(str); + if (card < 0) + return card; + } + continue; + } + return -EINVAL; + } + if (card < 0) + return -EINVAL; + return snd_ctl_hw_open(handlep, name, card, mode); +} +SND_DLSYM_BUILD_VERSION(_snd_ctl_hw_open, SND_CONTROL_DLSYM_VERSION); diff --git a/src/control/control_local.h b/src/control/control_local.h new file mode 100644 index 0000000..49150d8 --- /dev/null +++ b/src/control/control_local.h @@ -0,0 +1,100 @@ +/* + * Control Interface - local header file + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "local.h" + +typedef struct _snd_ctl_ops { + int (*close)(snd_ctl_t *handle); + int (*nonblock)(snd_ctl_t *handle, int nonblock); + int (*async)(snd_ctl_t *handle, int sig, pid_t pid); + int (*subscribe_events)(snd_ctl_t *handle, int subscribe); + int (*card_info)(snd_ctl_t *handle, snd_ctl_card_info_t *info); + int (*element_list)(snd_ctl_t *handle, snd_ctl_elem_list_t *list); + int (*element_info)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); + int (*element_add)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); + int (*element_replace)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); + int (*element_remove)(snd_ctl_t *handle, snd_ctl_elem_id_t *id); + int (*element_read)(snd_ctl_t *handle, snd_ctl_elem_value_t *control); + int (*element_write)(snd_ctl_t *handle, snd_ctl_elem_value_t *control); + int (*element_lock)(snd_ctl_t *handle, snd_ctl_elem_id_t *lock); + int (*element_unlock)(snd_ctl_t *handle, snd_ctl_elem_id_t *unlock); + int (*element_tlv)(snd_ctl_t *handle, int op_flag, unsigned int numid, + unsigned int *tlv, unsigned int tlv_size); + int (*hwdep_next_device)(snd_ctl_t *handle, int *device); + int (*hwdep_info)(snd_ctl_t *handle, snd_hwdep_info_t * info); + int (*pcm_next_device)(snd_ctl_t *handle, int *device); + int (*pcm_info)(snd_ctl_t *handle, snd_pcm_info_t * info); + int (*pcm_prefer_subdevice)(snd_ctl_t *handle, int subdev); + int (*rawmidi_next_device)(snd_ctl_t *handle, int *device); + int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info); + int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev); + int (*set_power_state)(snd_ctl_t *handle, unsigned int state); + int (*get_power_state)(snd_ctl_t *handle, unsigned int *state); + int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event); + int (*poll_descriptors_count)(snd_ctl_t *handle); + int (*poll_descriptors)(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space); + int (*poll_revents)(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +} snd_ctl_ops_t; + + +struct _snd_ctl { + void *open_func; + char *name; + snd_ctl_type_t type; + const snd_ctl_ops_t *ops; + void *private_data; + int nonblock; + int poll_fd; + struct list_head async_handlers; +}; + +struct _snd_hctl_elem { + snd_ctl_elem_id_t id; /* must be always on top */ + struct list_head list; /* links for list of all helems */ + int compare_weight; /* compare weight (reversed) */ + /* event callback */ + snd_hctl_elem_callback_t callback; + void *callback_private; + /* links */ + snd_hctl_t *hctl; /* associated handle */ +}; + +struct _snd_hctl { + snd_ctl_t *ctl; + struct list_head elems; /* list of all controls */ + unsigned int alloc; + unsigned int count; + snd_hctl_elem_t **pelems; + snd_hctl_compare_t compare; + snd_hctl_callback_t callback; + void *callback_private; +}; + + +/* make local functions really local */ +#define snd_ctl_new snd1_ctl_new + +int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name); +int _snd_ctl_poll_descriptor(snd_ctl_t *ctl); +#define _snd_ctl_async_descriptor _snd_ctl_poll_descriptor +int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode); +int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode); +int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid); diff --git a/src/control/control_shm.c b/src/control/control_shm.c new file mode 100644 index 0000000..abab398 --- /dev/null +++ b/src/control/control_shm.c @@ -0,0 +1,679 @@ +/* + * Control - SHM Client + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aserver.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_control_shm = ""; +#endif + +#ifndef DOC_HIDDEN +typedef struct { + int socket; + volatile snd_ctl_shm_ctrl_t *ctrl; +} snd_ctl_shm_t; +#endif + +static int snd_ctl_shm_action(snd_ctl_t *ctl) +{ + snd_ctl_shm_t *shm = ctl->private_data; + int err; + char buf[1]; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = read(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + SNDERR("Server has not done the cmd"); + return -EBADFD; + } + return ctrl->result; +} + +static int snd_ctl_shm_action_fd(snd_ctl_t *ctl, int *fd) +{ + snd_ctl_shm_t *shm = ctl->private_data; + int err; + char buf[1]; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = snd_receive_fd(shm->socket, buf, 1, fd); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + SNDERR("Server has not done the cmd"); + return -EBADFD; + } + return ctrl->result; +} + +static int snd_ctl_shm_close(snd_ctl_t *ctl) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int result; + ctrl->cmd = SND_CTL_IOCTL_CLOSE; + result = snd_ctl_shm_action(ctl); + shmdt((void *)ctrl); + close(shm->socket); + free(shm); + return result; +} + +static int snd_ctl_shm_nonblock(snd_ctl_t *handle ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_ctl_shm_async(snd_ctl_t *ctl, int sig, pid_t pid) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_CTL_IOCTL_ASYNC; + ctrl->u.async.sig = sig; + if (pid == 0) + pid = getpid(); + ctrl->u.async.pid = pid; + return snd_ctl_shm_action(ctl); +} + +static int snd_ctl_shm_poll_descriptor(snd_ctl_t *ctl) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int fd, err; + ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR; + err = snd_ctl_shm_action_fd(ctl, &fd); + if (err < 0) + return err; + return fd; +} + +static int snd_ctl_shm_subscribe_events(snd_ctl_t *ctl, int subscribe) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS; + ctrl->u.subscribe_events = subscribe; + return snd_ctl_shm_action(ctl); +} + +static int snd_ctl_shm_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; +// ctrl->u.card_info = *info; + ctrl->cmd = SNDRV_CTL_IOCTL_CARD_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.card_info; + return err; +} + +static int snd_ctl_shm_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + size_t maxsize = CTL_SHM_DATA_MAXLEN; + size_t bytes = list->space * sizeof(*list->pids); + int err; + snd_ctl_elem_id_t *pids = list->pids; + if (bytes > maxsize) + return -EINVAL; + ctrl->u.element_list = *list; + ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_LIST; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *list = ctrl->u.element_list; + list->pids = pids; + bytes = list->used * sizeof(*list->pids); + memcpy(pids, (void *)ctrl->data, bytes); + return err; +} + +static int snd_ctl_shm_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.element_info = *info; + ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.element_info; + return err; +} + +static int snd_ctl_shm_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.element_read = *control; + ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_READ; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *control = ctrl->u.element_read; + return err; +} + +static int snd_ctl_shm_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.element_write = *control; + ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_WRITE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *control = ctrl->u.element_write; + return err; +} + +static int snd_ctl_shm_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.element_lock = *id; + ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_LOCK; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *id = ctrl->u.element_lock; + return err; +} + +static int snd_ctl_shm_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.element_unlock = *id; + ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_UNLOCK; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *id = ctrl->u.element_unlock; + return err; +} + +static int snd_ctl_shm_hwdep_next_device(snd_ctl_t *ctl, int * device) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.device = *device; + ctrl->cmd = SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *device = ctrl->u.device; + return err; +} + +static int snd_ctl_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.hwdep_info = *info; + ctrl->cmd = SNDRV_CTL_IOCTL_HWDEP_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.hwdep_info; + return err; +} + +static int snd_ctl_shm_pcm_next_device(snd_ctl_t *ctl, int * device) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.device = *device; + ctrl->cmd = SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *device = ctrl->u.device; + return err; +} + +static int snd_ctl_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.pcm_info = *info; + ctrl->cmd = SNDRV_CTL_IOCTL_PCM_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.pcm_info; + return err; +} + +static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.pcm_prefer_subdevice = subdev; + ctrl->cmd = SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + return err; +} + +static int snd_ctl_shm_rawmidi_next_device(snd_ctl_t *ctl, int * device) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.device = *device; + ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *device = ctrl->u.device; + return err; +} + +static int snd_ctl_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.rawmidi_info = *info; + ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_INFO; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *info = ctrl->u.rawmidi_info; + return err; +} + +static int snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.rawmidi_prefer_subdevice = subdev; + ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + return err; +} + +static int snd_ctl_shm_set_power_state(snd_ctl_t *ctl, unsigned int state) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.power_state = state; + ctrl->cmd = SNDRV_CTL_IOCTL_POWER; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + return err; +} + +static int snd_ctl_shm_get_power_state(snd_ctl_t *ctl, unsigned int *state) +{ + snd_ctl_shm_t *shm = ctl->private_data; + volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SNDRV_CTL_IOCTL_POWER_STATE; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *state = ctrl->u.power_state; + return err; +} + +static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event) +{ + snd_ctl_shm_t *shm; + volatile snd_ctl_shm_ctrl_t *ctrl; + int err; + err = snd_ctl_wait(ctl, -1); + if (err < 0) + return 0; + shm = ctl->private_data; + ctrl = shm->ctrl; + ctrl->u.read = *event; + ctrl->cmd = SND_CTL_IOCTL_READ; + err = snd_ctl_shm_action(ctl); + if (err < 0) + return err; + *event = ctrl->u.read; + return err; +} + +static const snd_ctl_ops_t snd_ctl_shm_ops = { + .close = snd_ctl_shm_close, + .nonblock = snd_ctl_shm_nonblock, + .async = snd_ctl_shm_async, + .subscribe_events = snd_ctl_shm_subscribe_events, + .card_info = snd_ctl_shm_card_info, + .element_list = snd_ctl_shm_elem_list, + .element_info = snd_ctl_shm_elem_info, + .element_read = snd_ctl_shm_elem_read, + .element_write = snd_ctl_shm_elem_write, + .element_lock = snd_ctl_shm_elem_lock, + .element_unlock = snd_ctl_shm_elem_unlock, + .hwdep_next_device = snd_ctl_shm_hwdep_next_device, + .hwdep_info = snd_ctl_shm_hwdep_info, + .pcm_next_device = snd_ctl_shm_pcm_next_device, + .pcm_info = snd_ctl_shm_pcm_info, + .pcm_prefer_subdevice = snd_ctl_shm_pcm_prefer_subdevice, + .rawmidi_next_device = snd_ctl_shm_rawmidi_next_device, + .rawmidi_info = snd_ctl_shm_rawmidi_info, + .rawmidi_prefer_subdevice = snd_ctl_shm_rawmidi_prefer_subdevice, + .set_power_state = snd_ctl_shm_set_power_state, + .get_power_state = snd_ctl_shm_get_power_state, + .read = snd_ctl_shm_read, +}; + +static int make_local_socket(const char *filename) +{ + size_t l = strlen(filename); + size_t size = offsetof(struct sockaddr_un, sun_path) + l; + struct sockaddr_un *addr = alloca(size); + int sock; + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + return -errno; + + addr->sun_family = AF_LOCAL; + memcpy(addr->sun_path, filename, l); + + if (connect(sock, (struct sockaddr *) addr, size) < 0) + return -errno; + return sock; +} + +#if 0 +static int make_inet_socket(const char *host, int port) +{ + struct sockaddr_in addr; + int sock; + struct hostent *h = gethostbyname(host); + if (!h) + return -ENOENT; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) + return -errno; + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr)); + + if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) + return -errno; + return sock; +} +#endif + +int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode) +{ + snd_ctl_t *ctl; + snd_ctl_shm_t *shm = NULL; + snd_client_open_request_t *req; + snd_client_open_answer_t ans; + size_t snamelen, reqlen; + int err; + int result; + int sock = -1; + snd_ctl_shm_ctrl_t *ctrl = NULL; + snamelen = strlen(sname); + if (snamelen > 255) + return -EINVAL; + + result = make_local_socket(sockname); + if (result < 0) { + SNDERR("server for socket %s is not running", sockname); + goto _err; + } + sock = result; + + reqlen = sizeof(*req) + snamelen; + req = alloca(reqlen); + memcpy(req->name, sname, snamelen); + req->dev_type = SND_DEV_TYPE_CONTROL; + req->transport_type = SND_TRANSPORT_TYPE_SHM; + req->stream = 0; + req->mode = mode; + req->namelen = snamelen; + err = write(sock, req, reqlen); + if (err < 0) { + SNDERR("write error"); + result = -errno; + goto _err; + } + if ((size_t) err != reqlen) { + SNDERR("write size error"); + result = -EINVAL; + goto _err; + } + err = read(sock, &ans, sizeof(ans)); + if (err < 0) { + SNDERR("read error"); + result = -errno; + goto _err; + } + if (err != sizeof(ans)) { + SNDERR("read size error"); + result = -EINVAL; + goto _err; + } + result = ans.result; + if (result < 0) + goto _err; + + ctrl = shmat(ans.cookie, 0, 0); + if (!ctrl) { + result = -errno; + goto _err; + } + + shm = calloc(1, sizeof(snd_ctl_shm_t)); + if (!shm) { + result = -ENOMEM; + goto _err; + } + + shm->socket = sock; + shm->ctrl = ctrl; + + err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name); + if (err < 0) { + result = err; + goto _err; + } + ctl->ops = &snd_ctl_shm_ops; + ctl->private_data = shm; + err = snd_ctl_shm_poll_descriptor(ctl); + if (err < 0) { + snd_ctl_close(ctl); + return err; + } + ctl->poll_fd = err; + *handlep = ctl; + return 0; + + _err: + close(sock); + if (ctrl) + shmdt(ctrl); + free(shm); + return result; +} + +int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + const char *server = NULL; + const char *ctl_name = NULL; + snd_config_t *sconfig; + const char *host = NULL; + const char *sockname = NULL; + long port = -1; + int err; + int local; + struct hostent *h; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "server") == 0) { + err = snd_config_get_string(n, &server); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "ctl") == 0) { + err = snd_config_get_string(n, &ctl_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!ctl_name) { + SNDERR("ctl is not defined"); + return -EINVAL; + } + if (!server) { + SNDERR("server is not defined"); + return -EINVAL; + } + err = snd_config_search_definition(root, "server", server, &sconfig); + if (err < 0) { + SNDERR("Unknown server %s", server); + return -EINVAL; + } + if (snd_config_get_type(sconfig) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for server %s definition", server); + err = -EINVAL; + goto _err; + } + snd_config_for_each(i, next, sconfig) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "host") == 0) { + err = snd_config_get_string(n, &host); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "socket") == 0) { + err = snd_config_get_string(n, &sockname); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "port") == 0) { + err = snd_config_get_integer(n, &port); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + + if (!host) { + SNDERR("host is not defined"); + goto _err; + } + if (!sockname) { + SNDERR("socket is not defined"); + goto _err; + } + h = gethostbyname(host); + if (!h) { + SNDERR("Cannot resolve %s", host); + goto _err; + } + local = snd_is_local(h); + if (!local) { + SNDERR("%s is not the local host", host); + goto _err; + } + err = snd_ctl_shm_open(handlep, name, sockname, ctl_name, mode); + _err: + snd_config_delete(sconfig); + return err; +} +SND_DLSYM_BUILD_VERSION(_snd_ctl_shm_open, SND_CONTROL_DLSYM_VERSION); diff --git a/src/control/control_symbols.c b/src/control/control_symbols.c new file mode 100644 index 0000000..0cccade --- /dev/null +++ b/src/control/control_symbols.c @@ -0,0 +1,37 @@ +/* + * Control Symbols + * Copyright (c) 2001 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +extern const char *_snd_module_control_hw; +extern const char *_snd_module_control_shm; +extern const char *_snd_module_control_ext; + +static const char **snd_control_open_objects[] = { + &_snd_module_control_hw, +#include "ctl_symbols_list.c" +}; + +void *snd_control_open_symbols(void) +{ + return snd_control_open_objects; +} + +#endif /* !PIC */ diff --git a/src/control/ctl_symbols_list.c b/src/control/ctl_symbols_list.c new file mode 100644 index 0000000..6731168 --- /dev/null +++ b/src/control/ctl_symbols_list.c @@ -0,0 +1,2 @@ +&_snd_module_control_shm, +&_snd_module_control_ext, diff --git a/src/control/ctlparse.c b/src/control/ctlparse.c new file mode 100644 index 0000000..a929816 --- /dev/null +++ b/src/control/ctlparse.c @@ -0,0 +1,351 @@ +/** + * \file control/control.c + * \brief CTL interface - parse ASCII identifiers and values + * \author Jaroslav Kysela + * \date 2010 + */ +/* + * Control Interface - ASCII parser + * Copyright (c) 2010 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "control_local.h" + +/* Function to convert from percentage to volume. val = percentage */ + +#define convert_prange1(val, min, max) \ + ceil((val) * ((max) - (min)) * 0.01 + (min)) + +#define check_range(val, min, max) \ + ((val < min) ? (min) : ((val > max) ? (max) : (val))) + +static long get_integer(const char **ptr, long min, long max) +{ + long val = min; + char *p = (char *)*ptr, *s; + + if (*p == ':') + p++; + if (*p == '\0' || (!isdigit(*p) && *p != '-')) + goto out; + + s = p; + val = strtol(s, &p, 10); + if (*p == '.') { + p++; + strtol(p, &p, 10); + } + if (*p == '%') { + val = (long)convert_prange1(strtod(s, NULL), min, max); + p++; + } + val = check_range(val, min, max); + if (*p == ',') + p++; + out: + *ptr = p; + return val; +} + +static long long get_integer64(const char **ptr, long long min, long long max) +{ + long long val = min; + char *p = (char *)*ptr, *s; + + if (*p == ':') + p++; + if (*p == '\0' || (!isdigit(*p) && *p != '-')) + goto out; + + s = p; + val = strtol(s, &p, 10); + if (*p == '.') { + p++; + strtol(p, &p, 10); + } + if (*p == '%') { + val = (long long)convert_prange1(strtod(s, NULL), min, max); + p++; + } + val = check_range(val, min, max); + if (*p == ',') + p++; + out: + *ptr = p; + return val; +} + +/** + * \brief return ASCII CTL element identifier name + * \param id CTL identifier + * \return ascii identifier of CTL element + * + * The string is allocated using strdup(). + */ +char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id) +{ + unsigned int index, device, subdevice; + char buf[256], buf1[32]; + + snprintf(buf, sizeof(buf), "numid=%u,iface=%s,name='%s'", + snd_ctl_elem_id_get_numid(id), + snd_ctl_elem_iface_name( + snd_ctl_elem_id_get_interface(id)), + snd_ctl_elem_id_get_name(id)); + buf[sizeof(buf)-1] = '\0'; + index = snd_ctl_elem_id_get_index(id); + device = snd_ctl_elem_id_get_device(id); + subdevice = snd_ctl_elem_id_get_subdevice(id); + if (index) { + snprintf(buf1, sizeof(buf1), ",index=%i", index); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + if (device) { + snprintf(buf1, sizeof(buf1), ",device=%i", device); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + if (subdevice) { + snprintf(buf1, sizeof(buf1), ",subdevice=%i", subdevice); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + return strdup(buf); +} + +/** + * \brief parse ASCII string as CTL element identifier + * \param dst destination CTL identifier + * \param str source ASCII string + * \return zero on success, otherwise a negative error code + */ +int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) +{ + int c, size, numid; + char *ptr; + + while (*str == ' ' || *str == '\t') + str++; + if (!(*str)) + return -EINVAL; + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */ + while (*str) { + if (!strncasecmp(str, "numid=", 6)) { + str += 6; + numid = atoi(str); + if (numid <= 0) { + fprintf(stderr, "amixer: Invalid numid %d\n", numid); + return -EINVAL; + } + snd_ctl_elem_id_set_numid(dst, atoi(str)); + while (isdigit(*str)) + str++; + } else if (!strncasecmp(str, "iface=", 6)) { + str += 6; + if (!strncasecmp(str, "card", 4)) { + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_CARD); + str += 4; + } else if (!strncasecmp(str, "mixer", 5)) { + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); + str += 5; + } else if (!strncasecmp(str, "pcm", 3)) { + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_PCM); + str += 3; + } else if (!strncasecmp(str, "rawmidi", 7)) { + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_RAWMIDI); + str += 7; + } else if (!strncasecmp(str, "timer", 5)) { + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_TIMER); + str += 5; + } else if (!strncasecmp(str, "sequencer", 9)) { + snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER); + str += 9; + } else { + return -EINVAL; + } + } else if (!strncasecmp(str, "name=", 5)) { + char buf[64]; + str += 5; + ptr = buf; + size = 0; + if (*str == '\'' || *str == '\"') { + c = *str++; + while (*str && *str != c) { + if (size < (int)sizeof(buf)) { + *ptr++ = *str; + size++; + } + str++; + } + if (*str == c) + str++; + } else { + while (*str && *str != ',') { + if (size < (int)sizeof(buf)) { + *ptr++ = *str; + size++; + } + str++; + } + } + *ptr = '\0'; + snd_ctl_elem_id_set_name(dst, buf); + } else if (!strncasecmp(str, "index=", 6)) { + str += 6; + snd_ctl_elem_id_set_index(dst, atoi(str)); + while (isdigit(*str)) + str++; + } else if (!strncasecmp(str, "device=", 7)) { + str += 7; + snd_ctl_elem_id_set_device(dst, atoi(str)); + while (isdigit(*str)) + str++; + } else if (!strncasecmp(str, "subdevice=", 10)) { + str += 10; + snd_ctl_elem_id_set_subdevice(dst, atoi(str)); + while (isdigit(*str)) + str++; + } + if (*str == ',') { + str++; + } else { + if (*str) + return -EINVAL; + } + } + return 0; +} + +static int get_ctl_enum_item_index(snd_ctl_t *handle, + snd_ctl_elem_info_t *info, + const char **ptrp) +{ + char *ptr = (char *)*ptrp; + int items, i, len; + const char *name; + + items = snd_ctl_elem_info_get_items(info); + if (items <= 0) + return -1; + + for (i = 0; i < items; i++) { + snd_ctl_elem_info_set_item(info, i); + if (snd_ctl_elem_info(handle, info) < 0) + return -1; + name = snd_ctl_elem_info_get_item_name(info); + len = strlen(name); + if (! strncmp(name, ptr, len)) { + if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') { + ptr += len; + *ptrp = ptr; + return i; + } + } + } + return -1; +} + +/** + * \brief parse ASCII string as CTL element value + * \param dst destination CTL element value + * \param info CTL element info structure + * \param value source ASCII string + * \return zero on success, otherwise a negative error code + */ +int snd_ctl_ascii_value_parse(snd_ctl_t *handle, + snd_ctl_elem_value_t *dst, + snd_ctl_elem_info_t *info, + const char *value) +{ + const char *ptr = value; + snd_ctl_elem_id_t *myid; + snd_ctl_elem_type_t type; + unsigned int idx, count; + long tmp; + long long tmp64; + + snd_ctl_elem_id_alloca(&myid); + snd_ctl_elem_info_get_id(info, myid); + type = snd_ctl_elem_info_get_type(info); + count = snd_ctl_elem_info_get_count(info); + snd_ctl_elem_value_set_id(dst, myid); + + for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) { + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + tmp = 0; + if (!strncasecmp(ptr, "on", 2) || + !strncasecmp(ptr, "up", 2)) { + tmp = 1; + ptr += 2; + } else if (!strncasecmp(ptr, "yes", 3)) { + tmp = 1; + ptr += 3; + } else if (!strncasecmp(ptr, "toggle", 6)) { + tmp = snd_ctl_elem_value_get_boolean(dst, idx); + tmp = tmp > 0 ? 0 : 1; + ptr += 6; + } else if (isdigit(*ptr)) { + tmp = atoi(ptr) > 0 ? 1 : 0; + while (isdigit(*ptr)) + ptr++; + } else { + while (*ptr && *ptr != ',') + ptr++; + } + snd_ctl_elem_value_set_boolean(dst, idx, tmp); + break; + case SND_CTL_ELEM_TYPE_INTEGER: + tmp = get_integer(&ptr, + snd_ctl_elem_info_get_min(info), + snd_ctl_elem_info_get_max(info)); + snd_ctl_elem_value_set_integer(dst, idx, tmp); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + tmp64 = get_integer64(&ptr, + snd_ctl_elem_info_get_min64(info), + snd_ctl_elem_info_get_max64(info)); + snd_ctl_elem_value_set_integer64(dst, idx, tmp64); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + tmp = get_ctl_enum_item_index(handle, info, &ptr); + if (tmp < 0) + tmp = get_integer(&ptr, 0, + snd_ctl_elem_info_get_items(info) - 1); + snd_ctl_elem_value_set_enumerated(dst, idx, tmp); + break; + case SND_CTL_ELEM_TYPE_BYTES: + tmp = get_integer(&ptr, 0, 255); + snd_ctl_elem_value_set_byte(dst, idx, tmp); + break; + default: + break; + } + if (!strchr(value, ',')) + ptr = value; + else if (*ptr == ',') + ptr++; + } + return 0; +} diff --git a/src/control/hcontrol.c b/src/control/hcontrol.c new file mode 100644 index 0000000..8ffc434 --- /dev/null +++ b/src/control/hcontrol.c @@ -0,0 +1,1015 @@ +/** + * \file control/hcontrol.c + * \brief HCTL Interface - High Level CTL + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2000 + * + * HCTL interface is designed to access preloaded and sorted primitive controls. + * Callbacks may be used for event handling. + * See \ref hcontrol page for more details. + */ +/* + * Control Interface - high level API + * Copyright (c) 2000 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page hcontrol High level control interface + +

High level control interface is designed to access preloaded and sorted primitive controls. + +\section hcontrol_general_overview General overview + +

High level control interface caches the accesses to primitive controls +to reduce overhead accessing the real controls in kernel drivers. + +*/ + +#include +#include +#include +#include +#include +#include +#include "control_local.h" +#ifdef HAVE_LIBPTHREAD +#include +#endif + +#ifndef DOC_HIDDEN +#define NOT_FOUND 1000000000 +#endif + +static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, + const snd_hctl_elem_t *c2); + +/** + * \brief Opens an HCTL + * \param hctlp Returned HCTL handle + * \param name ASCII identifier of the underlying CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode) +{ + snd_ctl_t *ctl; + int err; + + if ((err = snd_ctl_open(&ctl, name, mode)) < 0) + return err; + err = snd_hctl_open_ctl(hctlp, ctl); + if (err < 0) + snd_ctl_close(ctl); + return err; +} + +/** + * \brief Opens an HCTL + * \param hctlp Returned HCTL handle + * \param ctl underlying CTL handle + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl) +{ + snd_hctl_t *hctl; + + assert(hctlp); + *hctlp = NULL; + if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&hctl->elems); + hctl->ctl = ctl; + *hctlp = hctl; + return 0; +} + +/** + * \brief close HCTL handle + * \param hctl HCTL handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified HCTL handle and frees all associated + * resources. + */ +int snd_hctl_close(snd_hctl_t *hctl) +{ + int err; + + assert(hctl); + err = snd_ctl_close(hctl->ctl); + snd_hctl_free(hctl); + free(hctl); + return err; +} + +/** + * \brief get identifier of HCTL handle + * \param hctl HCTL handle + * \return ascii identifier of HCTL handle + * + * Returns the ASCII identifier of given HCTL handle. It's the same + * identifier specified in snd_hctl_open(). + */ +const char *snd_hctl_name(snd_hctl_t *hctl) +{ + assert(hctl); + return snd_ctl_name(hctl->ctl); +} + +/** + * \brief set nonblock mode + * \param hctl HCTL handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock) +{ + assert(hctl); + return snd_ctl_nonblock(hctl->ctl, nonblock); +} + +/** + * \brief set async mode + * \param hctl HCTL handle + * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) + * \param pid Process ID to signal: 0 current + * \return 0 on success otherwise a negative error code + * + * A signal is raised when a change happens. + */ +int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid) +{ + assert(hctl); + return snd_ctl_async(hctl->ctl, sig, pid); +} + +/** + * \brief get count of poll descriptors for HCTL handle + * \param hctl HCTL handle + * \return count of poll descriptors + */ +int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl) +{ + assert(hctl); + return snd_ctl_poll_descriptors_count(hctl->ctl); +} + +/** + * \brief get poll descriptors + * \param hctl HCTL handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space) +{ + assert(hctl); + return snd_ctl_poll_descriptors(hctl->ctl, pfds, space); +} + +/** + * \brief get returned events from poll descriptors + * \param hctl HCTL handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(hctl); + return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents); +} + +static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask, + snd_hctl_elem_t *elem) +{ + if (hctl->callback) + return hctl->callback(hctl, mask, elem); + return 0; +} + +static int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem, + unsigned int mask) +{ + if (elem->callback) + return elem->callback(elem, mask); + return 0; +} + +static int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) +{ + int res; + + for (res = 0; *names; names++, res += coef) { + if (!strncmp(*name, *names, strlen(*names))) { + *name += strlen(*names); + if (**name == ' ') + (*name)++; + return res+1; + } + } + return NOT_FOUND; +} + +static int get_compare_weight(const snd_ctl_elem_id_t *id) +{ + static const char *const names[] = { + "Master", + "Hardware Master", + "Headphone", + "Tone Control", + "3D Control", + "PCM", + "Front", + "Surround", + "Center", + "LFE", + "Synth", + "FM", + "Wave", + "Music", + "DSP", + "Line", + "CD", + "Mic", + "Phone", + "Video", + "Zoom Video", + "PC Speaker", + "Aux", + "Mono", + "ADC", + "Capture Source", + "Capture", + "Playback", + "Loopback", + "Analog Loopback", + "Digital Loopback", + "I2S", + "IEC958", + NULL + }; + static const char *const names1[] = { + "Switch", + "Volume", + "Playback", + "Capture", + "Bypass", + "Mono", + "Front", + "Rear", + "Pan", + "Output", + "-", + NULL + }; + static const char *const names2[] = { + "Switch", + "Volume", + "Bypass", + "Depth", + "Wide", + "Space", + "Level", + "Center", + NULL + }; + const char *name = (char *)id->name, *name1; + int res, res1; + + if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND) + return NOT_FOUND; + if (*name == '\0') + return res; + for (name1 = name; *name1 != '\0'; name1++); + for (name1--; name1 != name && *name1 != ' '; name1--); + while (name1 != name && *name1 == ' ') + name1--; + if (name1 != name) { + for (; name1 != name && *name1 != ' '; name1--); + name = name1; + if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND) + return res; + res += res1; + } else { + name = name1; + } + if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND) + return res; + return res + res1; +} + +static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir) +{ + unsigned int l, u; + snd_hctl_elem_t el; + int c = 0; + int idx = -1; + assert(hctl && id); + assert(hctl->compare); + el.id = *id; + el.compare_weight = get_compare_weight(id); + l = 0; + u = hctl->count; + while (l < u) { + idx = (l + u) / 2; + c = hctl->compare(&el, hctl->pelems[idx]); + if (c < 0) + u = idx; + else if (c > 0) + l = idx + 1; + else + break; + } + *dir = c; + return idx; +} + +static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem) +{ + int dir; + int idx; + elem->compare_weight = get_compare_weight(&elem->id); + if (hctl->count == hctl->alloc) { + snd_hctl_elem_t **h; + hctl->alloc += 32; + h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc); + if (!h) { + hctl->alloc -= 32; + return -ENOMEM; + } + hctl->pelems = h; + } + if (hctl->count == 0) { + list_add_tail(&elem->list, &hctl->elems); + hctl->pelems[0] = elem; + } else { + idx = _snd_hctl_find_elem(hctl, &elem->id, &dir); + assert(dir != 0); + if (dir > 0) { + list_add(&elem->list, &hctl->pelems[idx]->list); + idx++; + } else { + list_add_tail(&elem->list, &hctl->pelems[idx]->list); + } + memmove(hctl->pelems + idx + 1, + hctl->pelems + idx, + (hctl->count - idx) * sizeof(snd_hctl_elem_t *)); + hctl->pelems[idx] = elem; + } + hctl->count++; + return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem); +} + +static void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx) +{ + snd_hctl_elem_t *elem = hctl->pelems[idx]; + unsigned int m; + snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE); + list_del(&elem->list); + free(elem); + hctl->count--; + m = hctl->count - idx; + if (m > 0) + memmove(hctl->pelems + idx, + hctl->pelems + idx + 1, + m * sizeof(snd_hctl_elem_t *)); +} + +/** + * \brief free HCTL loaded elements + * \param hctl HCTL handle + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_free(snd_hctl_t *hctl) +{ + while (hctl->count > 0) + snd_hctl_elem_remove(hctl, hctl->count - 1); + free(hctl->pelems); + hctl->pelems = 0; + hctl->alloc = 0; + INIT_LIST_HEAD(&hctl->elems); + return 0; +} + +static snd_hctl_t *compare_hctl; +static int hctl_compare(const void *a, const void *b) { + return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a, + *(const snd_hctl_elem_t * const *) b); +} + +static void snd_hctl_sort(snd_hctl_t *hctl) +{ + unsigned int k; +#ifdef HAVE_LIBPTHREAD + static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + + assert(hctl); + assert(hctl->compare); + INIT_LIST_HEAD(&hctl->elems); + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&sync_lock); +#endif + compare_hctl = hctl; + qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare); +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&sync_lock); +#endif + for (k = 0; k < hctl->count; k++) + list_add_tail(&hctl->pelems[k]->list, &hctl->elems); +} + +/** + * \brief Change HCTL compare function and reorder elements + * \param hctl HCTL handle + * \param compare Element compare function + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare) +{ + assert(hctl); + hctl->compare = compare == NULL ? snd_hctl_compare_default : compare; + snd_hctl_sort(hctl); + return 0; +} + +/** + * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare + * \param c1 First HCTL element + * \param c2 Second HCTL element + * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2 + */ +int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, + const snd_hctl_elem_t *c2) +{ + return c1->id.numid - c2->id.numid; +} + +static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, + const snd_hctl_elem_t *c2) +{ + int res, d; + + d = c1->id.iface - c2->id.iface; + if (d != 0) + return d; + if (c1->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER) { + d = c1->compare_weight - c2->compare_weight; + if (d != 0) + return d; + } + d = c1->id.device - c2->id.device; + if (d != 0) + return d; + d = c1->id.subdevice - c2->id.subdevice; + if (d != 0) + return d; + res = strcmp((const char *)c1->id.name, (const char *)c2->id.name); + if (res != 0) + return res; + return c1->id.index - c2->id.index; +} + +/** + * \brief get first element for an HCTL + * \param hctl HCTL handle + * \return pointer to first element + */ +snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl) +{ + assert(hctl); + if (list_empty(&hctl->elems)) + return NULL; + return list_entry(hctl->elems.next, snd_hctl_elem_t, list); +} + +/** + * \brief get last element for an HCTL + * \param hctl HCTL handle + * \return pointer to last element + */ +snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl) +{ + assert(hctl); + if (list_empty(&hctl->elems)) + return NULL; + return list_entry(hctl->elems.prev, snd_hctl_elem_t, list); +} + +/** + * \brief get next HCTL element + * \param elem HCTL element + * \return pointer to next element + */ +snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem) +{ + assert(elem); + if (elem->list.next == &elem->hctl->elems) + return NULL; + return list_entry(elem->list.next, snd_hctl_elem_t, list); +} + +/** + * \brief get previous HCTL element + * \param elem HCTL element + * \return pointer to previous element + */ +snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem) +{ + assert(elem); + if (elem->list.prev == &elem->hctl->elems) + return NULL; + return list_entry(elem->list.prev, snd_hctl_elem_t, list); +} + +/** + * \brief Search an HCTL element + * \param hctl HCTL handle + * \param id Element identifier + * \return pointer to found HCTL element or NULL if it does not exists + */ +snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id) +{ + int dir; + int res = _snd_hctl_find_elem(hctl, id, &dir); + if (res < 0 || dir != 0) + return NULL; + return hctl->pelems[res]; +} + +/** + * \brief Load an HCTL with all elements and sort them + * \param hctl HCTL handle + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_load(snd_hctl_t *hctl) +{ + snd_ctl_elem_list_t list; + int err = 0; + unsigned int idx; + + assert(hctl); + assert(hctl->ctl); + assert(hctl->count == 0); + assert(list_empty(&hctl->elems)); + memset(&list, 0, sizeof(list)); + if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) + goto _end; + while (list.count != list.used) { + err = snd_ctl_elem_list_alloc_space(&list, list.count); + if (err < 0) + goto _end; + if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) + goto _end; + } + if (hctl->alloc < list.count) { + hctl->alloc = list.count; + free(hctl->pelems); + hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems)); + if (!hctl->pelems) { + err = -ENOMEM; + goto _end; + } + } + for (idx = 0; idx < list.count; idx++) { + snd_hctl_elem_t *elem; + elem = calloc(1, sizeof(snd_hctl_elem_t)); + if (elem == NULL) { + snd_hctl_free(hctl); + err = -ENOMEM; + goto _end; + } + elem->id = list.pids[idx]; + elem->hctl = hctl; + elem->compare_weight = get_compare_weight(&elem->id); + hctl->pelems[idx] = elem; + list_add_tail(&elem->list, &hctl->elems); + hctl->count++; + } + if (!hctl->compare) + hctl->compare = snd_hctl_compare_default; + snd_hctl_sort(hctl); + for (idx = 0; idx < hctl->count; idx++) { + int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, + hctl->pelems[idx]); + if (res < 0) + return res; + } + err = snd_ctl_subscribe_events(hctl->ctl, 1); + _end: + free(list.pids); + return err; +} + +/** + * \brief Set callback function for an HCTL + * \param hctl HCTL handle + * \param callback callback function + */ +void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback) +{ + assert(hctl); + hctl->callback = callback; +} + +/** + * \brief Set callback private value for an HCTL + * \param hctl HCTL handle + * \param callback_private callback private value + */ +void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private) +{ + assert(hctl); + hctl->callback_private = callback_private; +} + +/** + * \brief Get callback private value for an HCTL + * \param hctl HCTL handle + * \return callback private value + */ +void *snd_hctl_get_callback_private(snd_hctl_t *hctl) +{ + assert(hctl); + return hctl->callback_private; +} + +/** + * \brief Get number of loaded elements for an HCTL + * \param hctl HCTL handle + * \return elements count + */ +unsigned int snd_hctl_get_count(snd_hctl_t *hctl) +{ + return hctl->count; +} + +/** + * \brief Wait for a HCTL to become ready (i.e. at least one event pending) + * \param hctl HCTL handle + * \param timeout maximum time in milliseconds to wait + * \return a positive value on success otherwise a negative error code + * \retval 0 timeout occurred + * \retval 1 an event is pending + */ +int snd_hctl_wait(snd_hctl_t *hctl, int timeout) +{ + struct pollfd *pfd; + unsigned short *revents; + int i, npfds, pollio, err, err_poll; + + npfds = snd_hctl_poll_descriptors_count(hctl); + if (npfds <= 0 || npfds >= 16) { + SNDERR("Invalid poll_fds %d\n", npfds); + return -EIO; + } + pfd = alloca(sizeof(*pfd) * npfds); + revents = alloca(sizeof(*revents) * npfds); + err = snd_hctl_poll_descriptors(hctl, pfd, npfds); + if (err < 0) + return err; + if (err != npfds) { + SNDMSG("invalid poll descriptors %d\n", err); + return -EIO; + } + do { + pollio = 0; + err_poll = poll(pfd, npfds, timeout); + if (err_poll < 0) { + if (errno == EINTR) + continue; + return -errno; + } + if (! err_poll) + break; + err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents); + if (err < 0) + return err; + for (i = 0; i < npfds; i++) { + if (revents[i] & (POLLERR | POLLNVAL)) + return -EIO; + if ((revents[i] & (POLLIN | POLLOUT)) == 0) + continue; + pollio++; + } + } while (! pollio); + return err_poll > 0 ? 1 : 0; +} + +/** + * \brief Get a ctl handle associated to the given hctl handle + * \param hctl HCTL handle + * \return a ctl handle otherwise NULL + */ +snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl) +{ + return hctl->ctl; +} + +static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) +{ + snd_hctl_elem_t *elem; + int res; + + assert(hctl); + assert(hctl->ctl); + switch (event->type) { + case SND_CTL_EVENT_ELEM: + break; + default: + return 0; + } + if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) { + int dir; + res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir); + assert(res >= 0 && dir == 0); + if (res < 0 || dir != 0) + return -ENOENT; + snd_hctl_elem_remove(hctl, (unsigned int) res); + return 0; + } + if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) { + elem = calloc(1, sizeof(snd_hctl_elem_t)); + if (elem == NULL) + return -ENOMEM; + elem->id = event->data.elem.id; + elem->hctl = hctl; + res = snd_hctl_elem_add(hctl, elem); + if (res < 0) + return res; + } + if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO)) { + elem = snd_hctl_find_elem(hctl, &event->data.elem.id); + assert(elem); + if (!elem) + return -ENOENT; + res = snd_hctl_elem_throw_event(elem, event->data.elem.mask & + (SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO)); + if (res < 0) + return res; + } + return 0; +} + +/** + * \brief Handle pending HCTL events invoking callbacks + * \param hctl HCTL handle + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_handle_events(snd_hctl_t *hctl) +{ + snd_ctl_event_t event; + int res; + unsigned int count = 0; + + assert(hctl); + assert(hctl->ctl); + while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 && + res != -EAGAIN) { + if (res < 0) + return res; + res = snd_hctl_handle_event(hctl, &event); + if (res < 0) + return res; + count++; + } + return count; +} + +/** + * \brief Get information for an HCTL element + * \param elem HCTL element + * \param info HCTL element information + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info) +{ + assert(elem); + assert(elem->hctl); + assert(info); + info->id = elem->id; + return snd_ctl_elem_info(elem->hctl->ctl, info); +} + +/** + * \brief Get value for an HCTL element + * \param elem HCTL element + * \param value HCTL element value + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) +{ + assert(elem); + assert(elem->hctl); + assert(value); + value->id = elem->id; + return snd_ctl_elem_read(elem->hctl->ctl, value); +} + +/** + * \brief Set value for an HCTL element + * \param elem HCTL element + * \param value HCTL element value + * \retval 0 on success + * \retval >1 on success when value was changed + * \retval <0 a negative error code on failure + */ +int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) +{ + assert(elem); + assert(elem->hctl); + assert(value); + value->id = elem->id; + return snd_ctl_elem_write(elem->hctl->ctl, value); +} + +/** + * \brief Get TLV value for an HCTL element + * \param elem HCTL element + * \param tlv TLV array for value + * \param tlv_size size of TLV array in bytes + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size) +{ + assert(elem); + assert(tlv); + assert(tlv_size >= 12); + return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size); +} + +/** + * \brief Set TLV value for an HCTL element + * \param elem HCTL element + * \param tlv TLV array for value + * \retval 0 on success + * \retval >1 on success when value was changed + * \retval <0 a negative error code on failure + */ +int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv) +{ + assert(elem); + assert(tlv); + assert(tlv[1] >= 4); + return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv); +} + +/** + * \brief Set TLV value for an HCTL element + * \param elem HCTL element + * \param tlv TLV array for value + * \retval 0 on success + * \retval >1 on success when value was changed + * \retval <0 a negative error code on failure + */ +int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv) +{ + assert(elem); + assert(tlv); + assert(tlv[1] >= 4); + return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv); +} + +/** + * \brief Get HCTL handle for an HCTL element + * \param elem HCTL element + * \return HCTL handle + */ +snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem) +{ + assert(elem); + return elem->hctl; +} + +/** + * \brief Get CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param ptr Pointer to returned CTL element identifier + */ +void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr) +{ + assert(obj && ptr); + *ptr = obj->id; +} + +/** + * \brief Get element numeric identifier of a CTL element id/value + * \param obj CTL element id/value + * \return element numeric identifier + */ +unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj) +{ + assert(obj); + return obj->id.numid; +} + +/** + * \brief Get interface part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return interface part of element identifier + */ +snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj) +{ + assert(obj); + return obj->id.iface; +} + +/** + * \brief Get device part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return device part of element identifier + */ +unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj) +{ + assert(obj); + return obj->id.device; +} + +/** + * \brief Get subdevice part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return subdevice part of element identifier + */ +unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj) +{ + assert(obj); + return obj->id.subdevice; +} + +/** + * \brief Get name part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return name part of element identifier + */ +const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj) +{ + assert(obj); + return (const char *)obj->id.name; +} + +/** + * \brief Get index part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return index part of element identifier + */ +unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj) +{ + assert(obj); + return obj->id.index; +} + +/** + * \brief Set callback function for an HCTL element + * \param obj HCTL element + * \param val callback function + */ +void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val) +{ + assert(obj); + obj->callback = val; +} + +/** + * \brief Set callback private value for an HCTL element + * \param obj HCTL element + * \param val callback private value + */ +void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val) +{ + assert(obj); + obj->callback_private = val; +} + +/** + * \brief Get callback private value for an HCTL element + * \param obj HCTL element + * \return callback private value + */ +void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj) +{ + assert(obj); + return obj->callback_private; +} + diff --git a/src/control/namehint.c b/src/control/namehint.c new file mode 100644 index 0000000..faaa5d5 --- /dev/null +++ b/src/control/namehint.c @@ -0,0 +1,687 @@ +/** + * \file control/namehint.c + * \brief Give device name hints + * \author Jaroslav Kysela + * \date 2006 + */ +/* + * Give device name hints - main file + * Copyright (c) 2006 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "local.h" + +#ifndef DOC_HIDDEN +struct hint_list { + char **list; + unsigned int count; + unsigned int allocated; + const char *siface; + snd_ctl_elem_iface_t iface; + snd_ctl_t *ctl; + snd_ctl_card_info_t *info; + int card; + int device; + long device_input; + long device_output; + int stream; + int show_all; + char *cardname; +}; +#endif + +static int hint_list_add(struct hint_list *list, + const char *name, + const char *description) +{ + char *x; + + if (list->count == list->allocated) { + char **n = realloc(list->list, (list->allocated + 10) * sizeof(char *)); + if (n == NULL) + return -ENOMEM; + list->allocated += 10; + list->list = n; + } + if (name == NULL) { + x = NULL; + } else { + x = malloc(4 + strlen(name) + (description != NULL ? (4 + strlen(description) + 1) : 0) + 1); + if (x == NULL) + return -ENOMEM; + memcpy(x, "NAME", 4); + strcpy(x + 4, name); + if (description != NULL) { + strcat(x, "|DESC"); + strcat(x, description); + } + } + list->list[list->count++] = x; + return 0; +} + +static void zero_handler(const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED, + const char *function ATTRIBUTE_UNUSED, + int err ATTRIBUTE_UNUSED, + const char *fmt ATTRIBUTE_UNUSED, ...) +{ +} + +static int get_dev_name1(struct hint_list *list, char **res, int device, + int stream) +{ + *res = NULL; + if (device < 0) + return 0; + switch (list->iface) { +#ifdef BUILD_HWDEP + case SND_CTL_ELEM_IFACE_HWDEP: + { + snd_hwdep_info_t *info; + snd_hwdep_info_alloca(&info); + snd_hwdep_info_set_device(info, device); + if (snd_ctl_hwdep_info(list->ctl, info) < 0) + return 0; + *res = strdup(snd_hwdep_info_get_name(info)); + return 0; + } +#endif +#ifdef BUILD_PCM + case SND_CTL_ELEM_IFACE_PCM: + { + snd_pcm_info_t *info; + snd_pcm_info_alloca(&info); + snd_pcm_info_set_device(info, device); + snd_pcm_info_set_stream(info, stream ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK); + if (snd_ctl_pcm_info(list->ctl, info) < 0) + return 0; + switch (snd_pcm_info_get_class(info)) { + case SND_PCM_CLASS_MODEM: + case SND_PCM_CLASS_DIGITIZER: + return -ENODEV; + default: + break; + } + *res = strdup(snd_pcm_info_get_name(info)); + return 0; + } +#endif +#ifdef BUILD_RAWMIDI + case SND_CTL_ELEM_IFACE_RAWMIDI: + { + snd_rawmidi_info_t *info; + snd_rawmidi_info_alloca(&info); + snd_rawmidi_info_set_device(info, device); + snd_rawmidi_info_set_stream(info, stream ? SND_RAWMIDI_STREAM_INPUT : SND_RAWMIDI_STREAM_OUTPUT); + if (snd_ctl_rawmidi_info(list->ctl, info) < 0) + return 0; + *res = strdup(snd_rawmidi_info_get_name(info)); + return 0; + } +#endif + default: + return 0; + } +} + +static char *get_dev_name(struct hint_list *list) +{ + char *str1, *str2, *res; + int device; + + device = list->device_input >= 0 ? list->device_input : list->device; + if (get_dev_name1(list, &str1, device, 1) < 0) + return NULL; + device = list->device_output >= 0 ? list->device_output : list->device; + if (get_dev_name1(list, &str2, device, 0) < 0) { + if (str1) + free(str1); + return NULL; + } + if (str1 != NULL || str2 != NULL) { + if (str1 != NULL && str2 != NULL) { + if (strcmp(str1, str2) == 0) { + res = malloc(strlen(list->cardname) + strlen(str2) + 3); + if (res != NULL) { + strcpy(res, list->cardname); + strcat(res, ", "); + strcat(res, str2); + } + } else { + res = malloc(strlen(list->cardname) + strlen(str2) + strlen(str1) + 6); + if (res != NULL) { + strcpy(res, list->cardname); + strcat(res, ", "); + strcat(res, str2); + strcat(res, " / "); + strcat(res, str1); + } + } + free(str2); + free(str1); + return res; + } else { + if (str1 != NULL) { + str2 = "Input"; + } else { + str1 = str2; + str2 = "Output"; + } + res = malloc(strlen(list->cardname) + strlen(str1) + 19); + if (res == NULL) { + free(str1); + return NULL; + } + strcpy(res, list->cardname); + strcat(res, ", "); + strcat(res, str1); + strcat(res, "|IOID"); + strcat(res, str2); + free(str1); + return res; + } + } + /* if the specified device doesn't exist, skip this entry */ + if (list->device >= 0 || list->device_input >= 0 || list->device_output >= 0) + return NULL; + return strdup(list->cardname); +} + +#ifndef DOC_HIDDEN +#define BUF_SIZE 128 +#endif + +static int try_config(struct hint_list *list, + const char *base, + const char *name) +{ + snd_lib_error_handler_t eh; + snd_config_t *res = NULL, *cfg, *cfg1, *n; + snd_config_iterator_t i, next; + char *buf, *buf1 = NULL, *buf2; + const char *str; + int err = 0, level; + long dev = list->device; + int cleanup_res = 0; + + list->device_input = -1; + list->device_output = -1; + buf = malloc(BUF_SIZE); + if (buf == NULL) + return -ENOMEM; + sprintf(buf, "%s.%s", base, name); + /* look for redirection */ + if (snd_config_search(snd_config, buf, &cfg) >= 0 && + snd_config_get_string(cfg, &str) >= 0 && + ((strncmp(base, str, strlen(base)) == 0 && + str[strlen(base)] == '.') || strchr(str, '.') == NULL)) + goto __skip_add; + if (list->card >= 0 && list->device >= 0) + sprintf(buf, "%s:CARD=%s,DEV=%i", name, snd_ctl_card_info_get_id(list->info), list->device); + else if (list->card >= 0) + sprintf(buf, "%s:CARD=%s", name, snd_ctl_card_info_get_id(list->info)); + else + strcpy(buf, name); + eh = snd_lib_error; + snd_lib_error_set_handler(&zero_handler); + err = snd_config_search_definition(snd_config, base, buf, &res); + snd_lib_error_set_handler(eh); + if (err < 0) + goto __skip_add; + cleanup_res = 1; + err = -EINVAL; + if (snd_config_get_type(res) != SND_CONFIG_TYPE_COMPOUND) + goto __cleanup; + if (snd_config_search(res, "type", NULL) < 0) + goto __cleanup; + +#if 0 /* for debug purposes */ + { + snd_output_t *out; + fprintf(stderr, "********* PCM '%s':\n", buf); + snd_output_stdio_attach(&out, stderr, 0); + snd_config_save(res, out); + snd_output_close(out); + fprintf(stderr, "\n"); + } +#endif + + cfg1 = res; + level = 0; + __hint: + level++; + if (snd_config_search(cfg1, "type", &cfg) >= 0 && + snd_config_get_string(cfg, &str) >= 0 && + strcmp(str, "hw") == 0) { + dev = 0; + list->device_input = -1; + list->device_output = -1; + if (snd_config_search(cfg1, "device", &cfg) >= 0) { + if (snd_config_get_integer(cfg, &dev) < 0) { + SNDERR("(%s) device must be an integer", buf); + err = -EINVAL; + goto __cleanup; + } + } + } + + if (snd_config_search(cfg1, "hint", &cfg) >= 0) { + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("hint (%s) must be a compound", buf); + err = -EINVAL; + goto __cleanup; + } + if (level == 1 && + snd_config_search(cfg, "show", &n) >= 0 && + snd_config_get_bool(n) <= 0) + goto __skip_add; + if (buf1 == NULL && + snd_config_search(cfg, "description", &n) >= 0 && + snd_config_get_string(n, &str) >= 0) { + buf1 = strdup(str); + if (buf1 == NULL) { + err = -ENOMEM; + goto __cleanup; + } + } + if (snd_config_search(cfg, "device", &n) >= 0) { + if (snd_config_get_integer(n, &dev) < 0) { + SNDERR("(%s) device must be an integer", buf); + err = -EINVAL; + goto __cleanup; + } + list->device_input = dev; + list->device_output = dev; + } + if (snd_config_search(cfg, "device_input", &n) >= 0) { + if (snd_config_get_integer(n, &list->device_input) < 0) { + SNDERR("(%s) device_input must be an integer", buf); + err = -EINVAL; + goto __cleanup; + } + list->device_output = -1; + } + if (snd_config_search(cfg, "device_output", &n) >= 0) { + if (snd_config_get_integer(n, &list->device_output) < 0) { + SNDERR("(%s) device_output must be an integer", buf); + err = -EINVAL; + goto __cleanup; + } + } + } else if (level == 1 && !list->show_all) + goto __skip_add; + if (snd_config_search(cfg1, "slave", &cfg) >= 0 && + snd_config_search(cfg, base, &cfg1) >= 0) + goto __hint; + snd_config_delete(res); + res = NULL; + cleanup_res = 0; + if (strchr(buf, ':') != NULL) + goto __ok; + /* find, if all parameters have a default, */ + /* otherwise filter this definition */ + eh = snd_lib_error; + snd_lib_error_set_handler(&zero_handler); + err = snd_config_search_alias_hooks(snd_config, base, buf, &res); + snd_lib_error_set_handler(eh); + if (err < 0) + goto __cleanup; + if (snd_config_search(res, "@args", &cfg) >= 0) { + snd_config_for_each(i, next, cfg) { + if (snd_config_search(snd_config_iterator_entry(i), + "default", NULL) < 0) { + err = -EINVAL; + goto __cleanup; + } + } + } + __ok: + err = 0; + __cleanup: + if (err >= 0) { + list->device = dev; + str = list->card >= 0 ? get_dev_name(list) : NULL; + if (str != NULL) { + level = (buf1 == NULL ? 0 : strlen(buf1)) + 1 + strlen(str); + buf2 = realloc((char *)str, level + 1); + if (buf2 != NULL) { + if (buf1 != NULL) { + str = strchr(buf2, '|'); + if (str != NULL) + memmove(buf2 + (level - strlen(str)), str, strlen(str)); + else + str = buf2 + strlen(buf2); + *(char *)str++ = '\n'; + memcpy((char *)str, buf1, strlen(buf1)); + buf2[level] = '\0'; + free(buf1); + } + buf1 = buf2; + } else { + free((char *)str); + } + } else if (list->device >= 0) + goto __skip_add; + err = hint_list_add(list, buf, buf1); + } + __skip_add: + if (res && cleanup_res) + snd_config_delete(res); + if (buf1) + free(buf1); + free(buf); + return err; +} + +#ifndef DOC_HIDDEN +#define IFACE(v, fcn) [SND_CTL_ELEM_IFACE_##v] = (next_devices_t)fcn + +typedef int (*next_devices_t)(snd_ctl_t *, int *); + +static const next_devices_t next_devices[] = { + IFACE(CARD, NULL), + IFACE(HWDEP, snd_ctl_hwdep_next_device), + IFACE(MIXER, NULL), + IFACE(PCM, snd_ctl_pcm_next_device), + IFACE(RAWMIDI, snd_ctl_rawmidi_next_device), + IFACE(TIMER, NULL), + IFACE(SEQUENCER, NULL) +}; +#endif + +static int add_card(struct hint_list *list, int card) +{ + int err, ok; + snd_config_t *conf, *n; + snd_config_iterator_t i, next; + const char *str; + char ctl_name[16]; + snd_ctl_card_info_t *info; + int device, max_device = 0; + + snd_ctl_card_info_alloca(&info); + list->info = info; + err = snd_config_search(snd_config, list->siface, &conf); + if (err < 0) + return err; + sprintf(ctl_name, "hw:%i", card); + err = snd_ctl_open(&list->ctl, ctl_name, 0); + if (err < 0) + return err; + err = snd_ctl_card_info(list->ctl, info); + if (err < 0) + goto __error; + snd_config_for_each(i, next, conf) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &str) < 0) + continue; + + if (next_devices[list->iface] != NULL) { + list->card = card; + device = max_device = -1; + err = next_devices[list->iface](list->ctl, &device); + if (device < 0) + err = -EINVAL; + else + max_device = device; + while (err >= 0 && device >= 0) { + err = next_devices[list->iface](list->ctl, &device); + if (err >= 0 && device > max_device) + max_device = device; + } + ok = 0; + for (device = 0; err >= 0 && device <= max_device; device++) { + list->device = device; + err = try_config(list, list->siface, str); + if (err < 0) + break; + ok++; + } + if (ok) + continue; + } else { + err = -EINVAL; + } + if (err == -EXDEV) + continue; + if (err < 0) { + list->card = card; + list->device = -1; + err = try_config(list, list->siface, str); + } + if (err == -ENOMEM) + goto __error; + } + err = 0; + __error: + snd_ctl_close(list->ctl); + return err; +} + +static int get_card_name(struct hint_list *list, int card) +{ + char scard[16], *s; + int err; + + free(list->cardname); + list->cardname = NULL; + err = snd_card_get_name(card, &list->cardname); + if (err <= 0) + return 0; + sprintf(scard, " #%i", card); + s = realloc(list->cardname, strlen(list->cardname) + strlen(scard) + 1); + if (s == NULL) + return -ENOMEM; + list->cardname = s; + return 0; +} + +static int add_software_devices(struct hint_list *list) +{ + int err; + snd_config_t *conf, *n; + snd_config_iterator_t i, next; + const char *str; + + err = snd_config_search(snd_config, list->siface, &conf); + if (err < 0) + return err; + snd_config_for_each(i, next, conf) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &str) < 0) + continue; + list->card = -1; + list->device = -1; + err = try_config(list, list->siface, str); + if (err == -ENOMEM) + return -ENOMEM; + } + return 0; +} + +/** + * \brief Return string list with device name hints. + * \param card Card number or -1 (means all cards) + * \param iface Interface identification (like "pcm", "rawmidi", "timer", "seq") + * \param hints Result - array of string with device name hints + * \result zero if success, otherwise a negative error code + * + * Note: The device description is separated with '|' char. + * + * User defined hints are gathered from namehint.IFACE tree like: + * + * + * namehint.pcm {
+ * myfile "file:FILE=/tmp/soundwave.raw|Save sound output to /tmp/soundwave.raw"
+ * myplug "plug:front:Do all conversions for front speakers"
+ * } + *
+ * + * Special variables: defaults.namehint.showall specifies if all device + * definitions are accepted (boolean type). + */ +int snd_device_name_hint(int card, const char *iface, void ***hints) +{ + struct hint_list list; + char ehints[24]; + const char *str; + snd_config_t *conf; + snd_config_iterator_t i, next; + int err; + + if (hints == NULL) + return -EINVAL; + err = snd_config_update(); + if (err < 0) + return err; + list.list = NULL; + list.count = list.allocated = 0; + list.siface = iface; + if (strcmp(iface, "card") == 0) + list.iface = SND_CTL_ELEM_IFACE_CARD; + else if (strcmp(iface, "pcm") == 0) + list.iface = SND_CTL_ELEM_IFACE_PCM; + else if (strcmp(iface, "rawmidi") == 0) + list.iface = SND_CTL_ELEM_IFACE_RAWMIDI; + else if (strcmp(iface, "timer") == 0) + list.iface = SND_CTL_ELEM_IFACE_TIMER; + else if (strcmp(iface, "seq") == 0) + list.iface = SND_CTL_ELEM_IFACE_SEQUENCER; + else if (strcmp(iface, "hwdep") == 0) + list.iface = SND_CTL_ELEM_IFACE_HWDEP; + else if (strcmp(iface, "ctl") == 0) + list.iface = SND_CTL_ELEM_IFACE_MIXER; + else + return -EINVAL; + list.show_all = 0; + list.cardname = NULL; + if (snd_config_search(snd_config, "defaults.namehint.showall", &conf) >= 0) + list.show_all = snd_config_get_bool(conf) > 0; + if (card >= 0) { + err = get_card_name(&list, card); + if (err >= 0) + err = add_card(&list, card); + } else { + add_software_devices(&list); + err = snd_card_next(&card); + if (err < 0) + goto __error; + while (card >= 0) { + err = get_card_name(&list, card); + if (err < 0) + goto __error; + err = add_card(&list, card); + if (err < 0) + goto __error; + err = snd_card_next(&card); + if (err < 0) + goto __error; + } + } + sprintf(ehints, "namehint.%s", list.siface); + err = snd_config_search(snd_config, ehints, &conf); + if (err >= 0) { + snd_config_for_each(i, next, conf) { + if (snd_config_get_string(snd_config_iterator_entry(i), + &str) < 0) + continue; + err = hint_list_add(&list, str, NULL); + if (err < 0) + goto __error; + } + } + err = 0; + __error: + if (err < 0) { + snd_device_name_free_hint((void **)list.list); + if (list.cardname) + free(list.cardname); + return err; + } else { + err = hint_list_add(&list, NULL, NULL); + if (err < 0) + goto __error; + *hints = (void **)list.list; + if (list.cardname) + free(list.cardname); + } + return 0; +} + +/** + * \brief Free a string list with device name hints. + * \param hints A string list to free + * \result zero if success, otherwise a negative error code + */ +int snd_device_name_free_hint(void **hints) +{ + char **h; + + if (hints == NULL) + return 0; + h = (char **)hints; + while (*h) { + free(*h); + h++; + } + free(hints); + return 0; +} + +/** + * \brief Get a hint Free a string list with device name hints. + * \param hint A pointer to hint + * \param id Hint ID (see bellow) + * \result an allocated ASCII string if success, otherwise NULL + * + * List of valid IDs: + * NAME - name of device + * DESC - description of device + * IOID - input / output identification (Input or Output strings), + * not present (NULL) means both + */ +char *snd_device_name_get_hint(const void *hint, const char *id) +{ + const char *hint1 = (const char *)hint, *delim; + char *res; + unsigned size; + + if (strlen(id) != 4) + return NULL; + while (*hint1 != '\0') { + delim = strchr(hint1, '|'); + if (memcmp(id, hint1, 4) != 0) { + if (delim == NULL) + return NULL; + hint1 = delim + 1; + continue; + } + if (delim == NULL) + return strdup(hint1 + 4); + size = delim - hint1 - 4; + res = malloc(size + 1); + if (res != NULL) { + memcpy(res, hint1 + 4, size); + res[size] = '\0'; + } + return res; + } + return NULL; +} diff --git a/src/control/setup.c b/src/control/setup.c new file mode 100644 index 0000000..eecda45 --- /dev/null +++ b/src/control/setup.c @@ -0,0 +1,661 @@ +/** + * \file control/setup.c + * \brief Routines to setup control primitives from configuration + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2001 + * + * Routines to setup control primitives from configuration + */ +/* + * Control Interface - routines for setup from configuration + * Copyright (c) 2001 by Abramo Bagnara + * Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "local.h" + +#ifndef DOC_HIDDEN +typedef struct { + unsigned int lock: 1; + unsigned int preserve: 1; + snd_ctl_elem_id_t *id; + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *val; + snd_ctl_elem_value_t *mask; + snd_ctl_elem_value_t *old; + struct list_head list; +} snd_sctl_elem_t; + +struct _snd_sctl { + int mode; + snd_ctl_t *ctl; + struct list_head elems; +}; +#endif /* DOC_HIDDEN */ + +static int free_elems(snd_sctl_t *h) +{ + int err = 0; + while (!list_empty(&h->elems)) { + snd_sctl_elem_t *elem = list_entry(h->elems.next, snd_sctl_elem_t, list); + snd_ctl_elem_id_free(elem->id); + snd_ctl_elem_info_free(elem->info); + snd_ctl_elem_value_free(elem->val); + snd_ctl_elem_value_free(elem->mask); + snd_ctl_elem_value_free(elem->old); + list_del(&elem->list); + free(elem); + } + if ((h->mode & SND_SCTL_NOFREE) == 0) + err = snd_ctl_close(h->ctl); + free(h); + return err; +} + +/** + * \brief Install given values to control elements + * \param h Setup control handle + * \result zero if success, otherwise a negative error code + */ +int snd_sctl_install(snd_sctl_t *h) +{ + struct list_head *pos; + int err; + unsigned int k; + assert(h); + list_for_each(pos, &h->elems) { + snd_sctl_elem_t *elem = list_entry(pos, snd_sctl_elem_t, list); + unsigned int count; + snd_ctl_elem_type_t type; + if (elem->lock) { + err = snd_ctl_elem_lock(h->ctl, elem->id); + if (err < 0) { + SNDERR("Cannot lock ctl elem"); + return err; + } + } + err = snd_ctl_elem_read(h->ctl, elem->old); + if (err < 0) { + SNDERR("Cannot read ctl elem"); + return err; + } + count = snd_ctl_elem_info_get_count(elem->info); + type = snd_ctl_elem_info_get_type(elem->info); + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + for (k = 0; k < count; ++k) { + int old, val, mask; + old = snd_ctl_elem_value_get_boolean(elem->old, k); + mask = snd_ctl_elem_value_get_boolean(elem->mask, k); + old &= ~mask; + if (old) { + val = snd_ctl_elem_value_get_boolean(elem->val, k); + val |= old; + snd_ctl_elem_value_set_boolean(elem->val, k, val); + } + } + break; + case SND_CTL_ELEM_TYPE_INTEGER: + for (k = 0; k < count; ++k) { + long old, val, mask; + old = snd_ctl_elem_value_get_integer(elem->old, k); + mask = snd_ctl_elem_value_get_integer(elem->mask, k); + old &= ~mask; + if (old) { + val = snd_ctl_elem_value_get_integer(elem->val, k); + val |= old; + snd_ctl_elem_value_set_integer(elem->val, k, val); + } + } + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + for (k = 0; k < count; ++k) { + unsigned int old, val, mask; + old = snd_ctl_elem_value_get_enumerated(elem->old, k); + mask = snd_ctl_elem_value_get_enumerated(elem->mask, k); + old &= ~mask; + if (old) { + val = snd_ctl_elem_value_get_enumerated(elem->val, k); + val |= old; + snd_ctl_elem_value_set_enumerated(elem->val, k, val); + } + } + break; + case SND_CTL_ELEM_TYPE_IEC958: + count = sizeof(snd_aes_iec958_t); + /* Fall through */ + case SND_CTL_ELEM_TYPE_BYTES: + for (k = 0; k < count; ++k) { + unsigned char old, val, mask; + old = snd_ctl_elem_value_get_byte(elem->old, k); + mask = snd_ctl_elem_value_get_byte(elem->mask, k); + old &= ~mask; + if (old) { + val = snd_ctl_elem_value_get_byte(elem->val, k); + val |= old; + snd_ctl_elem_value_set_byte(elem->val, k, val); + } + } + break; + default: + assert(0); + break; + } + err = snd_ctl_elem_write(h->ctl, elem->val); + if (err < 0) { + SNDERR("Cannot write ctl elem"); + return err; + } + } + return 0; +} + +/** + * \brief Remove (restore) previous values from control elements + * \param h Setup control handle + * \result zero if success, otherwise a negative error code + */ +int snd_sctl_remove(snd_sctl_t *h) +{ + struct list_head *pos; + int err; + assert(h); + list_for_each(pos, &h->elems) { + snd_sctl_elem_t *elem = list_entry(pos, snd_sctl_elem_t, list); + if (elem->lock) { + err = snd_ctl_elem_unlock(h->ctl, elem->id); + if (err < 0) { + SNDERR("Cannot unlock ctl elem"); + return err; + } + } + /* Only restore the old value if it differs from the requested + * value, because if it has changed restoring the old value + * overrides the change. Take for example, a voice modem with + * a .conf that sets preserve off-hook. Start playback (on-hook + * to off-hook), start record (off-hook to off-hook), stop + * playback (off-hook to restore on-hook), stop record (on-hook + * to restore off-hook), Clearly you don't want to leave the + * modem "on the phone" now that there isn't any playback or + * recording active. + */ + if (elem->preserve && snd_ctl_elem_value_compare(elem->val, elem->old)) { + err = snd_ctl_elem_write(h->ctl, elem->old); + if (err < 0) { + SNDERR("Cannot restore ctl elem"); + return err; + } + } + } + return 0; +} + +static int snd_config_get_ctl_elem_enumerated(snd_config_t *n, snd_ctl_t *ctl, + snd_ctl_elem_info_t *info) +{ + const char *str; + long val; + unsigned int idx, items; + switch (snd_config_get_type(n)) { + case SND_CONFIG_TYPE_INTEGER: + snd_config_get_integer(n, &val); + return val; + case SND_CONFIG_TYPE_STRING: + snd_config_get_string(n, &str); + break; + default: + return -1; + } + items = snd_ctl_elem_info_get_items(info); + for (idx = 0; idx < items; idx++) { + int err; + snd_ctl_elem_info_set_item(info, idx); + err = snd_ctl_elem_info(ctl, info); + if (err < 0) { + SNDERR("Cannot obtain info for CTL elem"); + return err; + } + if (strcmp(str, snd_ctl_elem_info_get_item_name(info)) == 0) + return idx; + } + return -1; +} + +static int snd_config_get_ctl_elem_value(snd_config_t *conf, + snd_ctl_t *ctl, + snd_ctl_elem_value_t *val, + snd_ctl_elem_value_t *mask, + snd_ctl_elem_info_t *info) +{ + int err; + snd_config_iterator_t i, next; + snd_ctl_elem_id_t *id; + snd_ctl_elem_type_t type; + unsigned int count; + long v; + long idx; + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_value_get_id(val, id); + count = snd_ctl_elem_info_get_count(info); + type = snd_ctl_elem_info_get_type(info); + if (count == 1) { + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + v = snd_config_get_bool(conf); + if (v >= 0) { + snd_ctl_elem_value_set_boolean(val, 0, v); + if (mask) + snd_ctl_elem_value_set_boolean(mask, 0, 1); + return 0; + } + break; + case SND_CTL_ELEM_TYPE_INTEGER: + err = snd_config_get_integer(conf, &v); + if (err == 0) { + snd_ctl_elem_value_set_integer(val, 0, v); + if (mask) + snd_ctl_elem_value_set_integer(mask, 0, ~0L); + return 0; + } + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + v = snd_config_get_ctl_elem_enumerated(conf, ctl, info); + if (v >= 0) { + snd_ctl_elem_value_set_enumerated(val, 0, v); + if (mask) + snd_ctl_elem_value_set_enumerated(mask, 0, ~0); + return 0; + } + break; + case SND_CTL_ELEM_TYPE_BYTES: + case SND_CTL_ELEM_TYPE_IEC958: + break; + default: + SNDERR("Unknown control type: %d", type); + return -EINVAL; + } + } + switch (type) { + case SND_CTL_ELEM_TYPE_IEC958: + count = sizeof(snd_aes_iec958_t); + /* Fall through */ + case SND_CTL_ELEM_TYPE_BYTES: + { + const char *buf; + err = snd_config_get_string(conf, &buf); + if (err >= 0) { + int c1 = 0; + unsigned int len = strlen(buf); + unsigned int idx = 0; + if (len % 2 != 0 || len > count * 2) { + _bad_content: + SNDERR("bad value content\n"); + return -EINVAL; + } + while (*buf) { + int c = *buf++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else { + goto _bad_content; + } + if (idx % 2 == 1) { + snd_ctl_elem_value_set_byte(val, idx / 2, c1 << 4 | c); + if (mask) + snd_ctl_elem_value_set_byte(mask, idx / 2, 0xff); + } else + c1 = c; + idx++; + } + return 0; + } + } + default: + break; + } + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("bad value type"); + return -EINVAL; + } + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &idx); + if (err < 0 || idx < 0 || (unsigned int) idx >= count) { + SNDERR("bad value index"); + return -EINVAL; + } + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + v = snd_config_get_bool(n); + if (v < 0) + goto _bad_content; + snd_ctl_elem_value_set_boolean(val, idx, v); + if (mask) + snd_ctl_elem_value_set_boolean(mask, idx, 1); + break; + case SND_CTL_ELEM_TYPE_INTEGER: + err = snd_config_get_integer(n, &v); + if (err < 0) + goto _bad_content; + snd_ctl_elem_value_set_integer(val, idx, v); + if (mask) + snd_ctl_elem_value_set_integer(mask, idx, ~0L); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + v = snd_config_get_ctl_elem_enumerated(n, ctl, info); + if (v < 0) + goto _bad_content; + snd_ctl_elem_value_set_enumerated(val, idx, v); + if (mask) + snd_ctl_elem_value_set_enumerated(mask, idx, ~0); + break; + case SND_CTL_ELEM_TYPE_BYTES: + case SND_CTL_ELEM_TYPE_IEC958: + err = snd_config_get_integer(n, &v); + if (err < 0 || v < 0 || v > 255) + goto _bad_content; + snd_ctl_elem_value_set_byte(val, idx, v); + if (mask) + snd_ctl_elem_value_set_byte(mask, idx, 0xff); + break; + default: + break; + } + } + return 0; +} + +static int add_elem(snd_sctl_t *h, snd_config_t *_conf, snd_config_t *private_data) +{ + snd_config_t *conf; + snd_config_iterator_t i, next; + char *tmp; + int iface = SND_CTL_ELEM_IFACE_MIXER; + const char *name = NULL; + long index = 0; + long device = -1; + long subdevice = -1; + int lock = 0; + int preserve = 0; + int optional = 0; + snd_config_t *value = NULL, *mask = NULL; + snd_sctl_elem_t *elem = NULL; + int err; + err = snd_config_expand(_conf, _conf, NULL, private_data, &conf); + if (err < 0) + return err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) { + const char *ptr; + if ((err = snd_config_get_string(n, &ptr)) < 0) { + SNDERR("field %s is not a string", id); + goto _err; + } + if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) { + SNDERR("Invalid value for '%s'", id); + goto _err; + } + iface = err; + continue; + } + if (strcmp(id, "name") == 0) { + if ((err = snd_config_get_string(n, &name)) < 0) { + SNDERR("field %s is not a string", id); + goto _err; + } + continue; + } + if (strcmp(id, "index") == 0) { + if ((err = snd_config_get_integer(n, &index)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + continue; + } + if (strcmp(id, "device") == 0) { + if ((err = snd_config_get_integer(n, &device)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + continue; + } + if (strcmp(id, "subdevice") == 0) { + if ((err = snd_config_get_integer(n, &subdevice)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + continue; + } + if (strcmp(id, "lock") == 0) { + if ((err = snd_config_get_ascii(n, &tmp)) < 0) { + SNDERR("field %s has an invalid type", id); + goto _err; + } + err = snd_config_get_bool_ascii(tmp); + if (err < 0) { + SNDERR("field %s is not a boolean", id); + free(tmp); + goto _err; + } + lock = err; + free(tmp); + continue; + } + if (strcmp(id, "preserve") == 0) { + if ((err = snd_config_get_ascii(n, &tmp)) < 0) { + SNDERR("field %s has an invalid type", id); + goto _err; + } + err = snd_config_get_bool_ascii(tmp); + if (err < 0) { + SNDERR("field %s is not a boolean", id); + free(tmp); + goto _err; + } + preserve = err; + free(tmp); + continue; + } + if (strcmp(id, "value") == 0) { + value = n; + continue; + } + if (strcmp(id, "mask") == 0) { + mask = n; + continue; + } + if (strcmp(id, "optional") == 0) { + if ((err = snd_config_get_ascii(n, &tmp)) < 0) { + SNDERR("field %s has an invalid type", id); + goto _err; + } + err = snd_config_get_bool_ascii(tmp); + if (err < 0) { + SNDERR("field %s is not a boolean", id); + free(tmp); + goto _err; + } + optional = err; + free(tmp); + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (name == NULL) { + SNDERR("Missing control name"); + err = -EINVAL; + goto _err; + } + if (value == NULL) { + SNDERR("Missing control value"); + err = -EINVAL; + goto _err; + } + if (device < 0) + device = 0; + if (subdevice < 0) + subdevice = 0; + elem = calloc(1, sizeof(*elem)); + if (!elem) + return -ENOMEM; + err = snd_ctl_elem_id_malloc(&elem->id); + if (err < 0) + goto _err; + err = snd_ctl_elem_info_malloc(&elem->info); + if (err < 0) + goto _err; + err = snd_ctl_elem_value_malloc(&elem->val); + if (err < 0) + goto _err; + err = snd_ctl_elem_value_malloc(&elem->mask); + if (err < 0) + goto _err; + err = snd_ctl_elem_value_malloc(&elem->old); + if (err < 0) + goto _err; + elem->lock = lock; + elem->preserve = preserve; + snd_ctl_elem_id_set_interface(elem->id, iface); + snd_ctl_elem_id_set_name(elem->id, name); + snd_ctl_elem_id_set_index(elem->id, index); + snd_ctl_elem_id_set_device(elem->id, device); + snd_ctl_elem_id_set_subdevice(elem->id, subdevice); + snd_ctl_elem_info_set_id(elem->info, elem->id); + err = snd_ctl_elem_info(h->ctl, elem->info); + if (err < 0) { + if (! optional) + SNDERR("Cannot obtain info for CTL elem (%s,'%s',%li,%li,%li): %s", snd_ctl_elem_iface_name(iface), name, index, device, subdevice, snd_strerror(err)); + goto _err; + } + snd_ctl_elem_value_set_id(elem->val, elem->id); + snd_ctl_elem_value_set_id(elem->old, elem->id); + if (mask) { + err = snd_config_get_ctl_elem_value(value, h->ctl, elem->val, NULL, elem->info); + if (err < 0) + goto _err; + err = snd_config_get_ctl_elem_value(mask, h->ctl, elem->mask, NULL, elem->info); + if (err < 0) + goto _err; + } else { + err = snd_config_get_ctl_elem_value(value, h->ctl, elem->val, elem->mask, elem->info); + if (err < 0) + goto _err; + } + + err = snd_config_get_ctl_elem_value(value, h->ctl, elem->val, elem->mask, elem->info); + if (err < 0) + goto _err; + list_add_tail(&elem->list, &h->elems); + + _err: + if (err < 0 && elem) { + if (elem->id) + snd_ctl_elem_id_free(elem->id); + if (elem->info) + snd_ctl_elem_info_free(elem->info); + if (elem->val) + snd_ctl_elem_value_free(elem->val); + if (elem->mask) + snd_ctl_elem_value_free(elem->mask); + if (elem->old) + snd_ctl_elem_value_free(elem->old); + free(elem); + if (err != -ENOMEM && optional) + err = 0; /* ignore the error */ + } + if (conf) + snd_config_delete(conf); + return err; +} + +/** + * \brief Build setup control handle + * \param sctl Result - setup control handle + * \param handle Master control handle + * \param conf Setup configuration + * \param private_data Private data for runtime evaluation + * \param mode Build mode - SND_SCTL_xxxx + * \result zero if success, otherwise a negative error code + */ +int snd_sctl_build(snd_sctl_t **sctl, snd_ctl_t *handle, snd_config_t *conf, snd_config_t *private_data, int mode) +{ + snd_sctl_t *h; + snd_config_iterator_t i, next; + int err; + + assert(sctl); + assert(handle); + assert(conf); + *sctl = NULL; + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + h = calloc(1, sizeof(*h)); + if (!h) { + if (mode & SND_SCTL_NOFREE) + return -ENOMEM; + snd_ctl_close(handle); + return -ENOMEM; + } + h->mode = mode; + h->ctl = handle; + INIT_LIST_HEAD(&h->elems); + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + err = add_elem(h, n, private_data); + if (err < 0) { + free_elems(h); + return err; + } + } + *sctl = h; + return 0; +} + +/** + * \brief Free setup control handle + * \param sctl Setup control handle + * \result zero if success, otherwise a negative error code + */ +int snd_sctl_free(snd_sctl_t *sctl) +{ + assert(sctl); + return free_elems(sctl); +} diff --git a/src/control/tlv.c b/src/control/tlv.c new file mode 100644 index 0000000..f7c9976 --- /dev/null +++ b/src/control/tlv.c @@ -0,0 +1,502 @@ +/** + * \file control/tlv.c + * \brief dB conversion functions from control TLV information + * \author Takashi Iwai + * \date 2007 + */ +/* + * Control Interface - dB conversion functions from control TLV information + * + * Copyright (c) 2007 Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#ifndef HAVE_SOFT_FLOAT +#include +#endif +#include "control_local.h" + +#ifndef DOC_HIDDEN +/* convert to index of integer array */ +#define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int)) +/* max size of a TLV entry for dB information (including compound one) */ +#define MAX_TLV_RANGE_SIZE 256 +#endif + +/** + * \brief Parse TLV stream and retrieve dB information + * \param tlv the TLV source + * \param tlv_size the byte size of TLV source + * \param db_tlvp the pointer stored the dB TLV information + * \return the byte size of dB TLV information if found in the given + * TLV source, or a negative error code. + * + * This function parses the given TLV source and stores the TLV start + * point if the TLV information regarding dB conversion is found. + * The stored TLV pointer can be passed to the convesion functions + * #snd_tlv_convert_to_dB(), #snd_tlv_convert_from_dB() and + * #snd_tlv_get_dB_range(). + */ +int snd_tlv_parse_dB_info(unsigned int *tlv, + unsigned int tlv_size, + unsigned int **db_tlvp) +{ + unsigned int type; + unsigned int size; + int err; + + *db_tlvp = NULL; + type = tlv[0]; + size = tlv[1]; + tlv_size -= 2 * sizeof(int); + if (size > tlv_size) { + SNDERR("TLV size error"); + return -EINVAL; + } + switch (type) { + case SND_CTL_TLVT_CONTAINER: + size = int_index(size) * sizeof(int); + tlv += 2; + while (size > 0) { + unsigned int len; + err = snd_tlv_parse_dB_info(tlv, size, db_tlvp); + if (err < 0) + return err; /* error */ + if (err > 0) + return err; /* found */ + len = int_index(tlv[1]) + 2; + size -= len * sizeof(int); + tlv += len; + } + break; + case SND_CTL_TLVT_DB_SCALE: + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: +#ifndef HAVE_SOFT_FLOAT + case SND_CTL_TLVT_DB_LINEAR: +#endif + case SND_CTL_TLVT_DB_RANGE: { + unsigned int minsize; + if (type == SND_CTL_TLVT_DB_RANGE) + minsize = 4 * sizeof(int); + else + minsize = 2 * sizeof(int); + if (size < minsize) { + SNDERR("Invalid dB_scale TLV size"); + return -EINVAL; + } + if (size > MAX_TLV_RANGE_SIZE) { + SNDERR("Too big dB_scale TLV size: %d", size); + return -EINVAL; + } + *db_tlvp = tlv; + return size + sizeof(int) * 2; + } + default: + break; + } + return -EINVAL; /* not found */ +} + +/** + * \brief Get the dB min/max values + * \param tlv the TLV source returned by #snd_tlv_parse_dB_info() + * \param rangemin the minimum value of the raw volume + * \param rangemax the maximum value of the raw volume + * \param min the pointer to store the minimum dB value (in 0.01dB unit) + * \param max the pointer to store the maximum dB value (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max) +{ + int err; + + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + long rmin, rmax; + long submin, submax; + submin = (int)tlv[pos]; + submax = (int)tlv[pos + 1]; + if (rangemax < submax) + submax = rangemax; + err = snd_tlv_get_dB_range(tlv + pos + 2, + submin, submax, + &rmin, &rmax); + if (err < 0) + return err; + if (pos > 2) { + if (rmin < *min) + *min = rmin; + if (rmax > *max) + *max = rmax; + } else { + *min = rmin; + *max = rmax; + } + if (rangemax == submax) + return 0; + pos += int_index(tlv[pos + 3]) + 4; + } + return 0; + } + case SND_CTL_TLVT_DB_SCALE: { + int step; + if (tlv[3] & 0x10000) + *min = SND_CTL_TLV_DB_GAIN_MUTE; + else + *min = (int)tlv[2]; + step = (tlv[3] & 0xffff); + *max = (int)tlv[2] + step * (rangemax - rangemin); + return 0; + } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_LINEAR: + *min = (int)tlv[2]; + *max = (int)tlv[3]; + return 0; + case SND_CTL_TLVT_DB_MINMAX_MUTE: + *min = SND_CTL_TLV_DB_GAIN_MUTE; + *max = (int)tlv[3]; + return 0; + } + return -EINVAL; +} + +/** + * \brief Convert the given raw volume value to a dB gain + * \param tlv the TLV source returned by #snd_tlv_parse_dB_info() + * \param rangemin the minimum value of the raw volume + * \param rangemax the maximum value of the raw volume + * \param volume the raw volume value to convert + * \param db_gain the dB gain (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + if (volume >= rangemin && volume <= rangemax) + return snd_tlv_convert_to_dB(tlv + pos + 2, + rangemin, rangemax, + volume, db_gain); + pos += int_index(tlv[pos + 3]) + 4; + } + return -EINVAL; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, mute; + min = tlv[2]; + step = (tlv[3] & 0xffff); + mute = (tlv[3] >> 16) & 1; + if (mute && volume <= rangemin) + *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; + else + *db_gain = (volume - rangemin) * step + min; + return 0; + } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: { + int mindb, maxdb; + mindb = tlv[2]; + maxdb = tlv[3]; + if (volume <= rangemin || rangemax <= rangemin) { + if (tlv[0] == SND_CTL_TLVT_DB_MINMAX_MUTE) + *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; + else + *db_gain = mindb; + } else if (volume >= rangemax) + *db_gain = maxdb; + else + *db_gain = (maxdb - mindb) * (volume - rangemin) / + (rangemax - rangemin) + mindb; + return 0; + } +#ifndef HAVE_SOFT_FLOAT + case SND_CTL_TLVT_DB_LINEAR: { + int mindb = tlv[2]; + int maxdb = tlv[3]; + if (volume <= rangemin || rangemax <= rangemin) + *db_gain = mindb; + else if (volume >= rangemax) + *db_gain = maxdb; + else { + double val = (double)(volume - rangemin) / + (double)(rangemax - rangemin); + if (mindb <= SND_CTL_TLV_DB_GAIN_MUTE) + *db_gain = (long)(100.0 * 20.0 * log10(val)) + + maxdb; + else { + /* FIXME: precalculate and cache these values */ + double lmin = pow(10.0, mindb/2000.0); + double lmax = pow(10.0, maxdb/2000.0); + val = (lmax - lmin) * val + lmin; + *db_gain = (long)(100.0 * 20.0 * log10(val)); + } + } + return 0; + } +#endif + } + return -EINVAL; +} + +/** + * \brief Convert from dB gain to the corresponding raw value + * \param tlv the TLV source returned by #snd_tlv_parse_dB_info() + * \param rangemin the minimum value of the raw volume + * \param rangemax the maximum value of the raw volume + * \param db_gain the dB gain to convert (in 0.01dB unit) + * \param value the pointer to store the converted raw volume value + * \param xdir the direction for round-up. The value is round up + * when this is positive. + * \return 0 if successful, or a negative error code + */ +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + long dbmin, dbmax, prev_rangemax; + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + if (snd_tlv_get_dB_range(tlv, rangemin, rangemax, + &dbmin, &dbmax)) + return -EINVAL; + if (db_gain <= dbmin) { + *value = rangemin; + return 0; + } else if (db_gain >= dbmax) { + *value = rangemax; + return 0; + } + pos = 2; + prev_rangemax = 0; + while (pos + 4 <= len) { + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + if (!snd_tlv_get_dB_range(tlv + pos + 2, + rangemin, rangemax, + &dbmin, &dbmax) && + db_gain >= dbmin && db_gain <= dbmax) + return snd_tlv_convert_from_dB(tlv + pos + 2, + rangemin, rangemax, + db_gain, value, xdir); + else if (db_gain < dbmin) { + *value = xdir ? rangemin : prev_rangemax; + return 0; + } + prev_rangemax = rangemax; + pos += int_index(tlv[pos + 3]) + 4; + } + return -EINVAL; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, max; + min = tlv[2]; + step = (tlv[3] & 0xffff); + max = min + (int)(step * (rangemax - rangemin)); + if (db_gain <= min) + if (db_gain > SND_CTL_TLV_DB_GAIN_MUTE && xdir > 0 && + (tlv[3] & 0x10000)) + *value = rangemin + 1; + else + *value = rangemin; + else if (db_gain >= max) + *value = rangemax; + else { + long v = (db_gain - min) * (rangemax - rangemin); + if (xdir > 0) + v += (max - min) - 1; + v = v / (max - min) + rangemin; + *value = v; + } + return 0; + } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: { + int min, max; + min = tlv[2]; + max = tlv[3]; + if (db_gain <= min) + if (db_gain > SND_CTL_TLV_DB_GAIN_MUTE && xdir > 0 && + tlv[0] == SND_CTL_TLVT_DB_MINMAX_MUTE) + *value = rangemin + 1; + else + *value = rangemin; + else if (db_gain >= max) + *value = rangemax; + else { + long v = (db_gain - min) * (rangemax - rangemin); + if (xdir > 0) + v += (max - min) - 1; + v = v / (max - min) + rangemin; + *value = v; + } + return 0; + } +#ifndef HAVE_SOFT_FLOAT + case SND_CTL_TLVT_DB_LINEAR: { + int min, max; + min = tlv[2]; + max = tlv[3]; + if (db_gain <= min) + *value = rangemin; + else if (db_gain >= max) + *value = rangemax; + else { + /* FIXME: precalculate and cache vmin and vmax */ + double vmin, vmax, v; + vmin = (min <= SND_CTL_TLV_DB_GAIN_MUTE) ? 0.0 : + pow(10.0, (double)min / 2000.0); + vmax = !max ? 1.0 : pow(10.0, (double)max / 2000.0); + v = pow(10.0, (double)db_gain / 2000.0); + v = (v - vmin) * (rangemax - rangemin) / (vmax - vmin); + if (xdir > 0) + v = ceil(v); + *value = (long)v + rangemin; + } + return 0; + } +#endif + default: + break; + } + return -EINVAL; +} + +#ifndef DOC_HIDDEN +#define TEMP_TLV_SIZE 4096 +struct tlv_info { + long minval, maxval; + unsigned int *tlv; + unsigned int buf[TEMP_TLV_SIZE]; +}; +#endif + +static int get_tlv_info(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + struct tlv_info *rec) +{ + snd_ctl_elem_info_t *info; + int err; + + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_info_set_id(info, id); + err = snd_ctl_elem_info(ctl, info); + if (err < 0) + return err; + if (!snd_ctl_elem_info_is_tlv_readable(info)) + return -EINVAL; + if (snd_ctl_elem_info_get_type(info) != SND_CTL_ELEM_TYPE_INTEGER) + return -EINVAL; + rec->minval = snd_ctl_elem_info_get_min(info); + rec->maxval = snd_ctl_elem_info_get_max(info); + err = snd_ctl_elem_tlv_read(ctl, id, rec->buf, sizeof(rec->buf)); + if (err < 0) + return err; + err = snd_tlv_parse_dB_info(rec->buf, sizeof(rec->buf), &rec->tlv); + if (err < 0) + return err; + return 0; +} + +/** + * \brief Get the dB min/max values on the given control element + * \param ctl the control handler + * \param id the element id + * \param min the pointer to store the minimum dB value (in 0.01dB unit) + * \param max the pointer to store the maximum dB value (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long *min, long *max) +{ + struct tlv_info info; + int err; + + err = get_tlv_info(ctl, id, &info); + if (err < 0) + return err; + return snd_tlv_get_dB_range(info.tlv, info.minval, info.maxval, + min, max); +} + +/** + * \brief Convert the volume value to dB on the given control element + * \param ctl the control handler + * \param id the element id + * \param volume the raw volume value to convert + * \param db_gain the dB gain (in 0.01dB unit) + * \return 0 if successful, or a negative error code + */ +int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long volume, long *db_gain) +{ + struct tlv_info info; + int err; + + err = get_tlv_info(ctl, id, &info); + if (err < 0) + return err; + return snd_tlv_convert_to_dB(info.tlv, info.minval, info.maxval, + volume, db_gain); +} + +/** + * \brief Convert from dB gain to the raw volume value on the given control element + * \param ctl the control handler + * \param id the element id + * \param db_gain the dB gain to convert (in 0.01dB unit) + * \param value the pointer to store the converted raw volume value + * \param xdir the direction for round-up. The value is round up + * when this is positive. + * \return 0 if successful, or a negative error code + */ +int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long db_gain, long *value, int xdir) +{ + struct tlv_info info; + int err; + + err = get_tlv_info(ctl, id, &info); + if (err < 0) + return err; + return snd_tlv_convert_from_dB(info.tlv, info.minval, info.maxval, + db_gain, value, xdir); +} diff --git a/src/dlmisc.c b/src/dlmisc.c new file mode 100644 index 0000000..ecbbe8d --- /dev/null +++ b/src/dlmisc.c @@ -0,0 +1,311 @@ +/** + * \file dlmisc.c + * \brief dynamic loader helpers + * \author Jaroslav Kysela + * \date 2001 + * + * Dynamic loader helpers + */ +/* + * Dynamic loader helpers + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "list.h" +#include "local.h" +#ifdef HAVE_LIBPTHREAD +#include +#endif + +#ifndef DOC_HIDDEN +#ifndef PIC +struct snd_dlsym_link *snd_dlsym_start = NULL; +#endif +#endif + +/** + * \brief Opens a dynamic library - ALSA wrapper for \c dlopen. + * \param name name of the library, similar to \c dlopen. + * \param mode mode flags, similar to \c dlopen. + * \return Library handle if successful, otherwise \c NULL. + * + * This function can emulate dynamic linking for the static build of + * the alsa-lib library. In that case, \p name is set to \c NULL. + */ +void *snd_dlopen(const char *name, int mode) +{ +#ifndef PIC + if (name == NULL) + return &snd_dlsym_start; +#else +#ifdef HAVE_LIBDL + if (name == NULL) { + static const char * self = NULL; + if (self == NULL) { + Dl_info dlinfo; + if (dladdr(snd_dlopen, &dlinfo) > 0) + self = dlinfo.dli_fname; + } + name = self; + } +#endif +#endif +#ifdef HAVE_LIBDL + return dlopen(name, mode); +#else + return NULL; +#endif +} + +/** + * \brief Closes a dynamic library - ALSA wrapper for \c dlclose. + * \param handle Library handle, similar to \c dlclose. + * \return Zero if successful, otherwise an error code. + * + * This function can emulate dynamic linking for the static build of + * the alsa-lib library. + */ +int snd_dlclose(void *handle) +{ +#ifndef PIC + if (handle == &snd_dlsym_start) + return 0; +#endif +#ifdef HAVE_LIBDL + return dlclose(handle); +#else + return 0; +#endif +} + +/** + * \brief Verifies a dynamically loaded symbol. + * \param handle Library handle, similar to \c dlsym. + * \param name Symbol name. + * \param version Version of the symbol. + * \return Zero is successful, otherwise a negative error code. + * + * This function checks that the symbol with the version appended to its name + * does exist in the library. + */ +static int snd_dlsym_verify(void *handle, const char *name, const char *version) +{ +#ifdef HAVE_LIBDL + int res; + char *vname; + + if (handle == NULL) + return -EINVAL; + vname = alloca(1 + strlen(name) + strlen(version) + 1); + if (vname == NULL) + return -ENOMEM; + vname[0] = '_'; + strcpy(vname + 1, name); + strcat(vname, version); + res = dlsym(handle, vname) == NULL ? -ENOENT : 0; + // printf("dlsym verify: %i, vname = '%s'\n", res, vname); + if (res < 0) + SNDERR("unable to verify version for symbol %s", name); + return res; +#else + return 0; +#endif +} + +/** + * \brief Resolves a symbol from a dynamic library - ALSA wrapper for \c dlsym. + * \param handle Library handle, similar to \c dlsym. + * \param name Symbol name. + * \param version Version of the symbol. + * + * This function can emulate dynamic linking for the static build of + * the alsa-lib library. + * + * This special version of the \c dlsym function checks also the version + * of the symbol. A versioned symbol should be defined using the + * #SND_DLSYM_BUILD_VERSION macro. + */ +void *snd_dlsym(void *handle, const char *name, const char *version) +{ + int err; + +#ifndef PIC + if (handle == &snd_dlsym_start) { + /* it's the funny part: */ + /* we are looking for a symbol in a static library */ + struct snd_dlsym_link *link = snd_dlsym_start; + while (link) { + if (!strcmp(name, link->dlsym_name)) + return (void *)link->dlsym_ptr; + link = link->next; + } + return NULL; + } +#endif +#ifdef HAVE_LIBDL + if (version) { + err = snd_dlsym_verify(handle, name, version); + if (err < 0) + return NULL; + } + return dlsym(handle, name); +#else + return NULL; +#endif +} + +/* + * dlobj cache + */ + +#ifndef DOC_HIDDEN +struct dlobj_cache { + const char *lib; + const char *name; + void *dlobj; + void *func; + unsigned int refcnt; + struct list_head list; +}; + +#ifdef HAVE_LIBPTHREAD +static pthread_mutex_t snd_dlobj_mutex = PTHREAD_MUTEX_INITIALIZER; + +static inline void snd_dlobj_lock(void) +{ + pthread_mutex_lock(&snd_dlobj_mutex); +} + +static inline void snd_dlobj_unlock(void) +{ + pthread_mutex_unlock(&snd_dlobj_mutex); +} +#else +static inline void snd_dlobj_lock(void) {} +static inline void snd_dlobj_unlock(void) {} +#endif + +static LIST_HEAD(pcm_dlobj_list); + +void *snd_dlobj_cache_get(const char *lib, const char *name, + const char *version, int verbose) +{ + struct list_head *p; + struct dlobj_cache *c; + void *func, *dlobj = NULL; + int dlobj_close = 0; + + snd_dlobj_lock(); + list_for_each(p, &pcm_dlobj_list) { + c = list_entry(p, struct dlobj_cache, list); + if (c->lib && lib && strcmp(c->lib, lib) != 0) + continue; + if (!c->lib && lib) + continue; + if (!lib && c->lib) + continue; + dlobj = c->dlobj; + if (strcmp(c->name, name) == 0) { + c->refcnt++; + func = c->func; + snd_dlobj_unlock(); + return func; + } + } + if (dlobj == NULL) { + dlobj = snd_dlopen(lib, RTLD_NOW); + if (dlobj == NULL) { + if (verbose) + SNDERR("Cannot open shared library %s", + lib ? lib : "[builtin]"); + snd_dlobj_unlock(); + return NULL; + } + dlobj_close = 1; + } + func = snd_dlsym(dlobj, name, version); + if (func == NULL) { + if (verbose) + SNDERR("symbol %s is not defined inside %s", + name, lib ? lib : "[builtin]"); + goto __err; + } + c = malloc(sizeof(*c)); + if (! c) + goto __err; + c->refcnt = 1; + c->lib = lib ? strdup(lib) : NULL; + c->name = strdup(name); + if ((lib && ! c->lib) || ! c->name) { + free((void *)c->name); + free((void *)c->lib); + free(c); + __err: + if (dlobj_close) + snd_dlclose(dlobj); + snd_dlobj_unlock(); + return NULL; + } + c->dlobj = dlobj; + c->func = func; + list_add_tail(&c->list, &pcm_dlobj_list); + snd_dlobj_unlock(); + return func; +} + +int snd_dlobj_cache_put(void *func) +{ + struct list_head *p; + struct dlobj_cache *c; + unsigned int refcnt; + + snd_dlobj_lock(); + list_for_each(p, &pcm_dlobj_list) { + c = list_entry(p, struct dlobj_cache, list); + if (c->func == func) { + refcnt = c->refcnt; + if (c->refcnt > 0) + c->refcnt--; + snd_dlobj_unlock(); + return refcnt == 1 ? 0 : -EINVAL; + } + } + snd_dlobj_unlock(); + return -ENOENT; +} + +void snd_dlobj_cache_cleanup(void) +{ + struct list_head *p, *npos; + struct dlobj_cache *c; + + snd_dlobj_lock(); + list_for_each_safe(p, npos, &pcm_dlobj_list) { + c = list_entry(p, struct dlobj_cache, list); + if (c->refcnt == 0) { + list_del(p); + snd_dlclose(c->dlobj); + free((void *)c->name); /* shut up gcc warning */ + free((void *)c->lib); /* shut up gcc warning */ + free(c); + } + } + snd_dlobj_unlock(); +} +#endif diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..7d5f509 --- /dev/null +++ b/src/error.c @@ -0,0 +1,150 @@ +/** + * \file error.c + * \brief Error code handling routines + * \author Jaroslav Kysela + * \date 1998-2001 + * + * Error code handling routines. + */ +/* + * Copyright (c) 1998 by Jaroslav Kysela + * + * snd_strerror routine needs to be recoded for the locale support + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "local.h" + +/** + * Array of error codes in US ASCII. + */ +static const char *snd_error_codes[] = +{ + "Sound protocol is not compatible" +}; + +/** + * \brief Returns the message for an error code. + * \param errnum The error code number, which must be a system error code + * or an ALSA error code. + * \return The ASCII description of the given numeric error code. + */ +const char *snd_strerror(int errnum) +{ + if (errnum < 0) + errnum = -errnum; + if (errnum < SND_ERROR_BEGIN) + return (const char *) strerror(errnum); + errnum -= SND_ERROR_BEGIN; + if ((unsigned int) errnum >= sizeof(snd_error_codes) / sizeof(const char *)) + return "Unknown error"; + return snd_error_codes[errnum]; +} + +/** + * \brief The default error handler function. + * \param file The filename where the error was hit. + * \param line The line number. + * \param function The function name. + * \param err The error code. + * \param fmt The message (including the format characters). + * \param ... Optional arguments. + * + * Prints the error message including location to \c stderr. + */ +static void snd_lib_error_default(const char *file, int line, const char *function, int err, const char *fmt, ...) +{ + va_list arg; + va_start(arg, fmt); + fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function); + vfprintf(stderr, fmt, arg); + if (err) + fprintf(stderr, ": %s", snd_strerror(err)); + putc('\n', stderr); + va_end(arg); +} + +/** + * \ingroup Error + * Pointer to the error handler function. + * For internal use only. + */ +snd_lib_error_handler_t snd_lib_error = snd_lib_error_default; + +/** + * \brief Sets the error handler. + * \param handler The pointer to the new error handler function. + * + * This function sets a new error handler, or (if \c handler is \c NULL) + * the default one which prints the error messages to \c stderr. + */ +int snd_lib_error_set_handler(snd_lib_error_handler_t handler) +{ + snd_lib_error = handler == NULL ? snd_lib_error_default : handler; +#ifndef NDEBUG + if (snd_lib_error != snd_lib_error_default) + snd_err_msg = snd_lib_error; +#endif + return 0; +} + +/** + * \brief Returns the ALSA sound library version in ASCII format + * \return The ASCII description of the used ALSA sound library. + */ +const char *snd_asoundlib_version(void) +{ + return SND_LIB_VERSION_STR; +} + +#ifndef NDEBUG +/* + * internal error handling + */ +static void snd_err_msg_default(const char *file, int line, const char *function, int err, const char *fmt, ...) +{ + va_list arg; + const char *verbose; + + verbose = getenv("LIBASOUND_DEBUG"); + if (! verbose || ! *verbose) + return; + va_start(arg, fmt); + fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function); + vfprintf(stderr, fmt, arg); + if (err) + fprintf(stderr, ": %s", snd_strerror(err)); + putc('\n', stderr); + va_end(arg); +#ifdef ALSA_DEBUG_ASSERT + verbose = getenv("LIBASOUND_DEBUG_ASSERT"); + if (verbose && *verbose) + assert(0); +#endif +} + +/** + * The ALSA error message handler + */ +snd_lib_error_handler_t snd_err_msg = snd_err_msg_default; + +#endif diff --git a/src/hwdep/Makefile.am b/src/hwdep/Makefile.am new file mode 100644 index 0000000..0b626b9 --- /dev/null +++ b/src/hwdep/Makefile.am @@ -0,0 +1,8 @@ +EXTRA_LTLIBRARIES=libhwdep.la + +libhwdep_la_SOURCES = hwdep.c hwdep_hw.c hwdep_symbols.c +noinst_HEADERS = hwdep_local.h +all: libhwdep.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/hwdep/Makefile.in b/src/hwdep/Makefile.in new file mode 100644 index 0000000..a7eca3f --- /dev/null +++ b/src/hwdep/Makefile.in @@ -0,0 +1,492 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/hwdep +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libhwdep_la_LIBADD = +am_libhwdep_la_OBJECTS = hwdep.lo hwdep_hw.lo hwdep_symbols.lo +libhwdep_la_OBJECTS = $(am_libhwdep_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libhwdep_la_SOURCES) +DIST_SOURCES = $(libhwdep_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libhwdep.la +libhwdep_la_SOURCES = hwdep.c hwdep_hw.c hwdep_symbols.c +noinst_HEADERS = hwdep_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/hwdep/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/hwdep/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libhwdep.la: $(libhwdep_la_OBJECTS) $(libhwdep_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libhwdep_la_OBJECTS) $(libhwdep_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwdep.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwdep_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwdep_symbols.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + +all: libhwdep.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hwdep/hwdep.c b/src/hwdep/hwdep.c new file mode 100644 index 0000000..b882b35 --- /dev/null +++ b/src/hwdep/hwdep.c @@ -0,0 +1,760 @@ +/** + * \file hwdep/hwdep.c + * \brief HwDep Interface (hardware dependent) + * \author Jaroslav Kysela + * \date 2000-2001 + * + * HwDep (hardware dependent) Interface is designed for individual hardware + * access. This interface does not cover any API specification. + */ +/* + * Hardware dependent Interface - main file + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "hwdep_local.h" + +static int snd_hwdep_open_conf(snd_hwdep_t **hwdep, + const char *name, snd_config_t *hwdep_root, + snd_config_t *hwdep_conf, int mode) +{ + const char *str; + char buf[256]; + int err; + snd_config_t *conf, *type_conf = NULL; + snd_config_iterator_t i, next; + const char *id; + const char *lib = NULL, *open_name = NULL; + int (*open_func)(snd_hwdep_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL; +#ifndef PIC + extern void *snd_hwdep_open_symbols(void); +#endif + void *h = NULL; + if (snd_config_get_type(hwdep_conf) != SND_CONFIG_TYPE_COMPOUND) { + if (name) + SNDERR("Invalid type for HWDEP %s definition", name); + else + SNDERR("Invalid type for HWDEP definition"); + return -EINVAL; + } + err = snd_config_search(hwdep_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(hwdep_root, "hwdep_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for HWDEP type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + open_name = buf; + snprintf(buf, sizeof(buf), "_snd_hwdep_%s_open", str); + } +#ifndef PIC + snd_hwdep_open_symbols(); +#endif + h = snd_dlopen(lib, RTLD_NOW); + if (h) + open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_HWDEP_DLSYM_VERSION)); + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + if (err >= 0) { + err = open_func(hwdep, name, hwdep_root, hwdep_conf, mode); + if (err >= 0) { + (*hwdep)->dl_handle = h; + } else { + snd_dlclose(h); + } + } + return err; +} + +static int snd_hwdep_open_noupdate(snd_hwdep_t **hwdep, snd_config_t *root, const char *name, int mode) +{ + int err; + snd_config_t *hwdep_conf; + err = snd_config_search_definition(root, "hwdep", name, &hwdep_conf); + if (err < 0) { + SNDERR("Unknown HwDep %s", name); + return err; + } + err = snd_hwdep_open_conf(hwdep, name, root, hwdep_conf, mode); + snd_config_delete(hwdep_conf); + return err; +} + +/** + * \brief Opens a new connection to the HwDep interface. + * \param hwdep Returned handle (NULL if not wanted) + * \param name ASCII identifier of the HwDep handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the HwDep interface specified with + * an ASCII identifier and mode. + */ +int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode) +{ + int err; + assert(hwdep && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_hwdep_open_noupdate(hwdep, snd_config, name, mode); +} + +/** + * \brief Opens a new connection to the HwDep interface using local configuration + * \param hwdep Returned handle (NULL if not wanted) + * \param name ASCII identifier of the HwDep handle + * \param mode Open mode + * \param lconf The local configuration tree + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the HwDep interface specified with + * an ASCII identifier and mode. + */ +int snd_hwdep_open_lconf(snd_hwdep_t **hwdep, const char *name, + int mode, snd_config_t *lconf) +{ + assert(hwdep && name && lconf); + return snd_hwdep_open_noupdate(hwdep, lconf, name, mode); +} + +/** + * \brief close HwDep handle + * \param hwdep HwDep handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified HwDep handle and frees all associated + * resources. + */ +int snd_hwdep_close(snd_hwdep_t *hwdep) +{ + int err; + assert(hwdep); + err = hwdep->ops->close(hwdep); + if (hwdep->dl_handle) + snd_dlclose(hwdep->dl_handle); + free(hwdep->name); + free(hwdep); + return err; +} + +/** + * \brief get identifier of HwDep handle + * \param hwdep a Hwdep handle + * \return ascii identifier of HwDep handle + * + * Returns the ASCII identifier of given HwDep handle. It's the same + * identifier specified in snd_hwdep_open(). + */ +const char *snd_hwdep_name(snd_hwdep_t *hwdep) +{ + assert(hwdep); + return hwdep->name; +} + +/** + * \brief get type of HwDep handle + * \param hwdep a HwDep handle + * \return type of HwDep handle + * + * Returns the type #snd_hwdep_type_t of given HwDep handle. + */ +snd_hwdep_type_t snd_hwdep_type(snd_hwdep_t *hwdep) +{ + assert(hwdep); + return hwdep->type; +} + +/** + * \brief get count of poll descriptors for HwDep handle + * \param hwdep HwDep handle + * \return count of poll descriptors + */ +int snd_hwdep_poll_descriptors_count(snd_hwdep_t *hwdep) +{ + assert(hwdep); + return 1; +} + +/** + * \brief get poll descriptors + * \param hwdep HwDep handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_hwdep_poll_descriptors(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int space) +{ + assert(hwdep); + if (space >= 1) { + pfds->fd = hwdep->poll_fd; + switch (hwdep->mode & O_ACCMODE) { + case O_WRONLY: + pfds->events = POLLOUT|POLLERR|POLLNVAL; + break; + case O_RDONLY: + pfds->events = POLLIN|POLLERR|POLLNVAL; + break; + case O_RDWR: + pfds->events = POLLOUT|POLLIN|POLLERR|POLLNVAL; + break; + default: + return -EIO; + } + return 1; + } + return 0; +} + +/** + * \brief get returned events from poll descriptors + * \param hwdep HwDep handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int snd_hwdep_poll_descriptors_revents(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(hwdep && pfds && revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +/** + * \brief set nonblock mode + * \param hwdep HwDep handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int snd_hwdep_nonblock(snd_hwdep_t *hwdep, int nonblock) +{ + int err; + assert(hwdep); + if ((err = hwdep->ops->nonblock(hwdep, nonblock)) < 0) + return err; + if (nonblock) + hwdep->mode |= SND_HWDEP_OPEN_NONBLOCK; + else + hwdep->mode &= ~SND_HWDEP_OPEN_NONBLOCK; + return 0; +} + +/** + * \brief get size of the snd_hwdep_info_t structure in bytes + * \return size of the snd_hwdep_info_t structure in bytes + */ +size_t snd_hwdep_info_sizeof() +{ + return sizeof(snd_hwdep_info_t); +} + +/** + * \brief allocate a new snd_hwdep_info_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_hwdep_info_t structure using the standard + * malloc C library function. + */ +int snd_hwdep_info_malloc(snd_hwdep_info_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_hwdep_info_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_hwdep_info_t structure + * \param info pointer to the snd_hwdep_info_t structure to free + * + * Frees the given snd_hwdep_info_t structure using the standard + * free C library function. + */ +void snd_hwdep_info_free(snd_hwdep_info_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_hwdep_info_t structure to another + * \param dst destination snd_hwdep_info_t structure + * \param src source snd_hwdep_info_t structure + */ +void snd_hwdep_info_copy(snd_hwdep_info_t *dst, const snd_hwdep_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief get hwdep card number + * \param obj pointer to a snd_hwdep_info_t structure + * \return hwdep card number + */ +int snd_hwdep_info_get_card(const snd_hwdep_info_t *obj) +{ + assert(obj); + return obj->card; +} + +/** + * \brief get hwdep device number + * \param info pointer to a snd_hwdep_info_t structure + * \return hwdep device number + */ +unsigned int snd_hwdep_info_get_device(const snd_hwdep_info_t *info) +{ + assert(info); + return info->device; +} + +/** + * \brief get hwdep driver identifier + * \param obj pointer to a snd_hwdep_info_t structure + * \return hwdep driver identifier + */ +const char *snd_hwdep_info_get_id(const snd_hwdep_info_t *obj) +{ + assert(obj); + return (const char *)obj->id; +} + +/** + * \brief get hwdep driver name + * \param obj pointer to a snd_hwdep_info_t structure + * \return hwdep driver name + */ +const char *snd_hwdep_info_get_name(const snd_hwdep_info_t *obj) +{ + assert(obj); + return (const char *)obj->name; +} + +/** + * \brief get hwdep protocol interface + * \param obj pointer to a snd_hwdep_info_t structure + * \return hwdep protocol interface + */ +snd_hwdep_iface_t snd_hwdep_info_get_iface(const snd_hwdep_info_t *obj) +{ + assert(obj); + return obj->iface; +} + +/** + * \brief set hwdep device number + * \param obj pointer to a snd_hwdep_info_t structure + * \param val hwdep device + */ +void snd_hwdep_info_set_device(snd_hwdep_info_t *obj, unsigned int val) +{ + assert(obj); + obj->device = val; +} + +/** + * \brief get information about HwDep handle + * \param hwdep HwDep handle + * \param info pointer to a snd_hwdep_info_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_hwdep_info(snd_hwdep_t *hwdep, snd_hwdep_info_t * info) +{ + assert(hwdep); + assert(info); + return hwdep->ops->info(hwdep, info); +} + +/** + * \brief do hardware dependent ioctl + * \param hwdep HwDep handle + * \param request ioctl command + * \param arg ioctl argument + * \return 0 on success otherwise a negative error code + */ +int snd_hwdep_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg) +{ + assert(hwdep); + return hwdep->ops->ioctl(hwdep, request, arg); +} + +/** + * \brief write bytes using HwDep handle + * \param hwdep HwDep handle + * \param buffer buffer containing bytes to write + * \param size output buffer size in bytes + */ +ssize_t snd_hwdep_write(snd_hwdep_t *hwdep, const void *buffer, size_t size) +{ + assert(hwdep); + assert(((hwdep->mode & O_ACCMODE) == O_WRONLY) || ((hwdep->mode & O_ACCMODE) == O_RDWR)); + assert(buffer || size == 0); + return hwdep->ops->write(hwdep, buffer, size); +} + +/** + * \brief read bytes using HwDep handle + * \param hwdep HwDep handle + * \param buffer buffer to store the input bytes + * \param size input buffer size in bytes + */ +ssize_t snd_hwdep_read(snd_hwdep_t *hwdep, void *buffer, size_t size) +{ + assert(hwdep); + assert(((hwdep->mode & O_ACCMODE) == O_RDONLY) || ((hwdep->mode & O_ACCMODE) == O_RDWR)); + assert(buffer || size == 0); + return (hwdep->ops->read)(hwdep, buffer, size); +} + +/** + * \brief get the DSP status information + * \param hwdep HwDep handle + * \param info pointer to a snd_hwdep_dsp_status_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_hwdep_dsp_status(snd_hwdep_t *hwdep, snd_hwdep_dsp_status_t *info) +{ + assert(hwdep); + assert(info); + return hwdep->ops->ioctl(hwdep, SNDRV_HWDEP_IOCTL_DSP_STATUS, (void*)info); +} + +/** + * \brief load the DSP block + * \param hwdep HwDep handle + * \param block pointer to a snd_hwdep_dsp_image_t structure to transfer + * \return 0 on success otherwise a negative error code + */ +int snd_hwdep_dsp_load(snd_hwdep_t *hwdep, snd_hwdep_dsp_image_t *block) +{ + assert(hwdep); + assert(block); + return hwdep->ops->ioctl(hwdep, SNDRV_HWDEP_IOCTL_DSP_LOAD, (void*)block); +} + +/** + * \brief get size of the snd_hwdep_dsp_status_t structure in bytes + * \return size of the snd_hwdep_dsp_status_t structure in bytes + */ +size_t snd_hwdep_dsp_status_sizeof() +{ + return sizeof(snd_hwdep_dsp_status_t); +} + +/** + * \brief allocate a new snd_hwdep_dsp_status_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_hwdep_dsp_status_t structure using the standard + * malloc C library function. + */ +int snd_hwdep_dsp_status_malloc(snd_hwdep_dsp_status_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_hwdep_dsp_status_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_hwdep_dsp_status_t structure + * \param info pointer to the snd_hwdep_dsp_status_t structure to free + * + * Frees the given snd_hwdep_dsp_status_t structure using the standard + * free C library function. + */ +void snd_hwdep_dsp_status_free(snd_hwdep_dsp_status_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_hwdep_dsp_status_t structure to another + * \param dst destination snd_hwdep_dsp_status_t structure + * \param src source snd_hwdep_dsp_status_t structure + */ +void snd_hwdep_dsp_status_copy(snd_hwdep_dsp_status_t *dst, const snd_hwdep_dsp_status_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief get the driver version of dsp loader + * \param obj pointer to a snd_hwdep_dsp_status_t structure + * \return the driver version + */ +unsigned int snd_hwdep_dsp_status_get_version(const snd_hwdep_dsp_status_t *obj) +{ + assert(obj); + return obj->version; +} + +/** + * \brief get the driver id of dsp loader + * \param obj pointer to a snd_hwdep_dsp_status_t structure + * \return the driver id string + */ +const char *snd_hwdep_dsp_status_get_id(const snd_hwdep_dsp_status_t *obj) +{ + assert(obj); + return (const char *)obj->id; +} + +/** + * \brief get number of dsp blocks + * \param obj pointer to a snd_hwdep_dsp_status_t structure + * \return number of dsp blocks + */ +unsigned int snd_hwdep_dsp_status_get_num_dsps(const snd_hwdep_dsp_status_t *obj) +{ + assert(obj); + return obj->num_dsps; +} + +/** + * \brief get the bit flags of the loaded dsp blocks + * \param info pointer to a snd_hwdep_dsp_status_t structure + * \return the big flags of the loaded dsp blocks + */ +unsigned int snd_hwdep_dsp_status_get_dsp_loaded(const snd_hwdep_dsp_status_t *info) +{ + assert(info); + return info->dsp_loaded; +} + +/** + * \brief get the chip status of dsp loader + * \param obj pointer to a snd_hwdep_dsp_status_t structure + * \return non-zero if all DSP blocks are loaded and the chip is ready + */ +unsigned int snd_hwdep_dsp_status_get_chip_ready(const snd_hwdep_dsp_status_t *obj) +{ + assert(obj); + return obj->chip_ready; +} + +/** + * \brief get size of the snd_hwdep_dsp_image_t structure in bytes + * \return size of the snd_hwdep_dsp_image_t structure in bytes + */ +size_t snd_hwdep_dsp_image_sizeof() +{ + return sizeof(snd_hwdep_dsp_image_t); +} + +/** + * \brief allocate a new snd_hwdep_dsp_image_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_hwdep_dsp_image_t structure using the standard + * malloc C library function. + */ +int snd_hwdep_dsp_image_malloc(snd_hwdep_dsp_image_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_hwdep_dsp_image_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_hwdep_dsp_image_t structure + * \param info pointer to the snd_hwdep_dsp_image_t structure to free + * + * Frees the given snd_hwdep_dsp_image_t structure using the standard + * free C library function. + */ +void snd_hwdep_dsp_image_free(snd_hwdep_dsp_image_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_hwdep_dsp_image_t structure to another + * \param dst destination snd_hwdep_dsp_image_t structure + * \param src source snd_hwdep_dsp_image_t structure + */ +void snd_hwdep_dsp_image_copy(snd_hwdep_dsp_image_t *dst, const snd_hwdep_dsp_image_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief get the DSP block index + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \return the index of the DSP block + */ +unsigned int snd_hwdep_dsp_image_get_index(const snd_hwdep_dsp_image_t *obj) +{ + assert(obj); + return obj->index; +} + +/** + * \brief get the name of the DSP block + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \return the name string of the DSP block + */ +const char *snd_hwdep_dsp_image_get_name(const snd_hwdep_dsp_image_t *obj) +{ + assert(obj); + return (const char *)obj->name; +} + +/** + * \brief get the length of the DSP block + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \return the length of the DSP block in bytes + */ +size_t snd_hwdep_dsp_image_get_length(const snd_hwdep_dsp_image_t *obj) +{ + assert(obj); + return obj->length; +} + +/** + * \brief get the image pointer of the DSP block + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \return the image pointer of the DSP block + */ +const void *snd_hwdep_dsp_image_get_image(const snd_hwdep_dsp_image_t *obj) +{ + assert(obj); + return obj->image; +} + +/** + * \brief set the DSP block index + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \param index the index value to set + */ +void snd_hwdep_dsp_image_set_index(snd_hwdep_dsp_image_t *obj, unsigned int index) +{ + assert(obj); + obj->index = index; +} + +/** + * \brief set the name of the DSP block + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \param name the name string + */ +void snd_hwdep_dsp_image_set_name(snd_hwdep_dsp_image_t *obj, const char *name) +{ + assert(obj && name); + strncpy((char *)obj->name, name, sizeof(obj->name)); + obj->name[sizeof(obj->name)-1] = 0; +} + +/** + * \brief set the DSP block length + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \param length the length of the DSP block + */ +void snd_hwdep_dsp_image_set_length(snd_hwdep_dsp_image_t *obj, size_t length) +{ + assert(obj); + obj->length = length; +} + +/** + * \brief set the DSP block image pointer + * \param obj pointer to a snd_hwdep_dsp_image_t structure + * \param image the DSP image pointer + */ +void snd_hwdep_dsp_image_set_image(snd_hwdep_dsp_image_t *obj, void *image) +{ + assert(obj); + obj->image = image; +} + diff --git a/src/hwdep/hwdep_hw.c b/src/hwdep/hwdep_hw.c new file mode 100644 index 0000000..e4fcdc3 --- /dev/null +++ b/src/hwdep/hwdep_hw.c @@ -0,0 +1,190 @@ +/* + * Hardware dependent Interface - main file for hardware access + * Copyright (c) 2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "hwdep_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_hwdep_hw = ""; +#endif + +#define SNDRV_FILE_HWDEP ALSA_DEVICE_DIRECTORY "hwC%iD%i" +#define SNDRV_HWDEP_VERSION_MAX SNDRV_PROTOCOL_VERSION(1, 0, 1) + +static int snd_hwdep_hw_close(snd_hwdep_t *hwdep) +{ + int res; + assert(hwdep); + res = close(hwdep->poll_fd) < 0 ? -errno : 0; + return res; +} + +static int snd_hwdep_hw_nonblock(snd_hwdep_t *hwdep, int nonblock) +{ + long flags; + assert(hwdep); + if ((flags = fcntl(hwdep->poll_fd, F_GETFL)) < 0) + return -errno; + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(hwdep->poll_fd, F_SETFL, flags) < 0) + return -errno; + return 0; +} + +static int snd_hwdep_hw_info(snd_hwdep_t *hwdep, snd_hwdep_info_t *info) +{ + assert(hwdep && info); + if (ioctl(hwdep->poll_fd, SNDRV_HWDEP_IOCTL_INFO, info) < 0) + return -errno; + return 0; +} + +static int snd_hwdep_hw_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg) +{ + assert(hwdep); + if (ioctl(hwdep->poll_fd, request, arg) < 0) + return -errno; + return 0; +} + +static ssize_t snd_hwdep_hw_write(snd_hwdep_t *hwdep, const void *buffer, size_t size) +{ + ssize_t result; + assert(hwdep && (buffer || size == 0)); + result = write(hwdep->poll_fd, buffer, size); + if (result < 0) + return -errno; + return result; +} + +static ssize_t snd_hwdep_hw_read(snd_hwdep_t *hwdep, void *buffer, size_t size) +{ + ssize_t result; + assert(hwdep && (buffer || size == 0)); + result = read(hwdep->poll_fd, buffer, size); + if (result < 0) + return -errno; + return result; +} + +static const snd_hwdep_ops_t snd_hwdep_hw_ops = { + .close = snd_hwdep_hw_close, + .nonblock = snd_hwdep_hw_nonblock, + .info = snd_hwdep_hw_info, + .ioctl = snd_hwdep_hw_ioctl, + .write = snd_hwdep_hw_write, + .read = snd_hwdep_hw_read, +}; + +int snd_hwdep_hw_open(snd_hwdep_t **handle, const char *name, int card, int device, int mode) +{ + int fd, ver, ret; + char filename[sizeof(SNDRV_FILE_HWDEP) + 20]; + snd_hwdep_t *hwdep; + assert(handle); + + *handle = NULL; + + if (card < 0 || card >= 32) + return -EINVAL; + sprintf(filename, SNDRV_FILE_HWDEP, card, device); + fd = snd_open_device(filename, mode); + if (fd < 0) { + snd_card_load(card); + fd = snd_open_device(filename, mode); + if (fd < 0) + return -errno; + } + if (ioctl(fd, SNDRV_HWDEP_IOCTL_PVERSION, &ver) < 0) { + ret = -errno; + close(fd); + return ret; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_HWDEP_VERSION_MAX)) { + close(fd); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } + hwdep = (snd_hwdep_t *) calloc(1, sizeof(snd_hwdep_t)); + if (hwdep == NULL) { + close(fd); + return -ENOMEM; + } + hwdep->name = strdup(name); + hwdep->poll_fd = fd; + hwdep->mode = mode; + hwdep->type = SND_HWDEP_TYPE_HW; + hwdep->ops = &snd_hwdep_hw_ops; + *handle = hwdep; + return 0; +} + +int _snd_hwdep_hw_open(snd_hwdep_t **hwdep, char *name, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + long card = -1, device = 0; + const char *str; + int err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_get_index(str); + if (card < 0) + return card; + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) + return err; + continue; + } + SNDERR("Unexpected field %s", id); + return -EINVAL; + } + if (card < 0) + return -EINVAL; + return snd_hwdep_hw_open(hwdep, name, card, device, mode); +} +SND_DLSYM_BUILD_VERSION(_snd_hwdep_hw_open, SND_HWDEP_DLSYM_VERSION); diff --git a/src/hwdep/hwdep_local.h b/src/hwdep/hwdep_local.h new file mode 100644 index 0000000..47467f9 --- /dev/null +++ b/src/hwdep/hwdep_local.h @@ -0,0 +1,46 @@ +/* + * HwDep interface - local header file + * Copyright (c) 2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "local.h" + +typedef struct { + int (*close)(snd_hwdep_t *hwdep); + int (*nonblock)(snd_hwdep_t *hwdep, int nonblock); + int (*info)(snd_hwdep_t *hwdep, snd_hwdep_info_t *info); + int (*ioctl)(snd_hwdep_t *hwdep, unsigned int request, void * arg); + ssize_t (*write)(snd_hwdep_t *hwdep, const void *buffer, size_t size); + ssize_t (*read)(snd_hwdep_t *hwdep, void *buffer, size_t size); +} snd_hwdep_ops_t; + +struct _snd_hwdep { + void *dl_handle; + char *name; + snd_hwdep_type_t type; + int mode; + int poll_fd; + const snd_hwdep_ops_t *ops; + void *private_data; +}; + +int snd_hwdep_hw_open(snd_hwdep_t **handle, const char *name, int card, int device, int mode); diff --git a/src/hwdep/hwdep_symbols.c b/src/hwdep/hwdep_symbols.c new file mode 100644 index 0000000..aaa5667 --- /dev/null +++ b/src/hwdep/hwdep_symbols.c @@ -0,0 +1,34 @@ +/* + * HwDep Symbols + * Copyright (c) 2001 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +extern const char *_snd_module_hwdep_hw; + +static const char **snd_hwdep_open_objects[] = { + &_snd_module_hwdep_hw +}; + +void *snd_hwdep_open_symbols(void) +{ + return snd_hwdep_open_objects; +} + +#endif diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..7cfbe56 --- /dev/null +++ b/src/input.c @@ -0,0 +1,337 @@ +/** + * \file input.c + * \brief Generic stdio-like input interface + * \author Abramo Bagnara + * \date 2000 + * + * Generic stdio-like input interface + */ +/* + * Input object + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "local.h" + +#ifndef DOC_HIDDEN + +typedef struct _snd_input_ops { + int (*close)(snd_input_t *input); + int (*scan)(snd_input_t *input, const char *format, va_list args); + char *(*(gets))(snd_input_t *input, char *str, size_t size); + int (*getch)(snd_input_t *input); + int (*ungetch)(snd_input_t *input, int c); +} snd_input_ops_t; + +struct _snd_input { + snd_input_type_t type; + const snd_input_ops_t *ops; + void *private_data; +}; +#endif + +/** + * \brief Closes an input handle. + * \param input The input handle to be closed. + * \return Zero if successful, otherwise a negative error code. + */ +int snd_input_close(snd_input_t *input) +{ + int err = input->ops->close(input); + free(input); + return err; +} + +/** + * \brief Reads formatted input (like \c fscanf(3)) from an input handle. + * \param input The input handle. + * \param format Format string in \c fscanf format. + * \param ... Other \c fscanf arguments. + * \return The number of input items assigned, or \c EOF. + * + * \bug Reading from a memory buffer doesn't work. + */ +int snd_input_scanf(snd_input_t *input, const char *format, ...) +{ + int result; + va_list args; + va_start(args, format); + result = input->ops->scan(input, format, args); + va_end(args); + return result; +} + +/** + * \brief Reads a line from an input handle (like \c fgets(3)). + * \param input The input handle. + * \param str Address of the destination buffer. + * \param size The size of the destination buffer. + * \return Pointer to the buffer if successful, otherwise \c NULL. + * + * Like \c fgets, the returned string is zero-terminated, and contains + * the new-line character \c '\\n' if the line fits into the buffer. + */ +char *snd_input_gets(snd_input_t *input, char *str, size_t size) +{ + return (input->ops->gets)(input, str, size); +} + +/** + * \brief Reads a character from an input handle (like \c fgetc(3)). + * \param input The input handle. + * \return The character read, or \c EOF on end of file or error. + */ +int snd_input_getc(snd_input_t *input) +{ + return input->ops->getch(input); +} + +/** + * \brief Puts the last character read back to an input handle (like \c ungetc(3)). + * \param input The input handle. + * \param c The character to push back. + * \return The character pushed back, or \c EOF on error. + */ +int snd_input_ungetc(snd_input_t *input, int c) +{ + return input->ops->ungetch(input, c); +} + +#ifndef DOC_HIDDEN +typedef struct _snd_input_stdio { + int close; + FILE *fp; +} snd_input_stdio_t; + +static int snd_input_stdio_close(snd_input_t *input ATTRIBUTE_UNUSED) +{ + snd_input_stdio_t *stdio = input->private_data; + if (stdio->close) + fclose(stdio->fp); + free(stdio); + return 0; +} + +static int snd_input_stdio_scan(snd_input_t *input, const char *format, va_list args) +{ + snd_input_stdio_t *stdio = input->private_data; + extern int vfscanf(FILE *, const char *, va_list); + return vfscanf(stdio->fp, format, args); +} + +static char *snd_input_stdio_gets(snd_input_t *input, char *str, size_t size) +{ + snd_input_stdio_t *stdio = input->private_data; + return fgets(str, (int) size, stdio->fp); +} + +static int snd_input_stdio_getc(snd_input_t *input) +{ + snd_input_stdio_t *stdio = input->private_data; + return getc(stdio->fp); +} + +static int snd_input_stdio_ungetc(snd_input_t *input, int c) +{ + snd_input_stdio_t *stdio = input->private_data; + return ungetc(c, stdio->fp); +} + +static const snd_input_ops_t snd_input_stdio_ops = { + .close = snd_input_stdio_close, + .scan = snd_input_stdio_scan, + .gets = snd_input_stdio_gets, + .getch = snd_input_stdio_getc, + .ungetch = snd_input_stdio_ungetc, +}; +#endif + +/** + * \brief Creates a new input object using an existing stdio \c FILE pointer. + * \param inputp The function puts the pointer to the new input object + * at the address specified by \p inputp. + * \param fp The \c FILE pointer to read from. + * Reading begins at the current file position. + * \param _close Close flag. Set this to 1 if #snd_input_close should close + * \p fp by calling \c fclose. + * \return Zero if successful, otherwise a negative error code. + */ +int snd_input_stdio_attach(snd_input_t **inputp, FILE *fp, int _close) +{ + snd_input_t *input; + snd_input_stdio_t *stdio; + assert(inputp && fp); + stdio = calloc(1, sizeof(*stdio)); + if (!stdio) + return -ENOMEM; + input = calloc(1, sizeof(*input)); + if (!input) { + free(stdio); + return -ENOMEM; + } + stdio->fp = fp; + stdio->close = _close; + input->type = SND_INPUT_STDIO; + input->ops = &snd_input_stdio_ops; + input->private_data = stdio; + *inputp = input; + return 0; +} + +/** + * \brief Creates a new input object reading from a file. + * \param inputp The functions puts the pointer to the new input object + * at the address specified by \p inputp. + * \param file The name of the file to read from. + * \param mode The open mode, like \c fopen(3). + * \return Zero if successful, otherwise a negative error code. + */ +int snd_input_stdio_open(snd_input_t **inputp, const char *file, const char *mode) +{ + int err; + FILE *fp = fopen(file, mode); + if (!fp) { + //SYSERR("fopen"); + return -errno; + } + err = snd_input_stdio_attach(inputp, fp, 1); + if (err < 0) + fclose(fp); + return err; +} + +#ifndef DOC_HIDDEN + +typedef struct _snd_input_buffer { + unsigned char *buf; + unsigned char *ptr; + size_t size; +} snd_input_buffer_t; + +static int snd_input_buffer_close(snd_input_t *input) +{ + snd_input_buffer_t *buffer = input->private_data; + free(buffer->buf); + free(buffer); + return 0; +} + +static int snd_input_buffer_scan(snd_input_t *input, const char *format, va_list args) +{ + snd_input_buffer_t *buffer = input->private_data; + extern int vsscanf(const char *, const char *, va_list); + /* FIXME: how can I obtain consumed chars count? */ + assert(0); + return vsscanf((char *)buffer->ptr, format, args); +} + +static char *snd_input_buffer_gets(snd_input_t *input, char *str, size_t size) +{ + snd_input_buffer_t *buffer = input->private_data; + size_t bsize = buffer->size; + while (--size > 0 && bsize > 0) { + unsigned char c = *buffer->ptr++; + bsize--; + *str++ = c; + if (c == '\n') + break; + } + if (bsize == buffer->size) + return NULL; + buffer->size = bsize; + *str = '\0'; + return str; +} + +static int snd_input_buffer_getc(snd_input_t *input) +{ + snd_input_buffer_t *buffer = input->private_data; + if (buffer->size == 0) + return EOF; + buffer->size--; + return *buffer->ptr++; +} + +static int snd_input_buffer_ungetc(snd_input_t *input, int c) +{ + snd_input_buffer_t *buffer = input->private_data; + if (buffer->ptr == buffer->buf) + return EOF; + buffer->ptr--; + assert(*buffer->ptr == (unsigned char) c); + buffer->size++; + return c; +} + +static const snd_input_ops_t snd_input_buffer_ops = { + .close = snd_input_buffer_close, + .scan = snd_input_buffer_scan, + .gets = snd_input_buffer_gets, + .getch = snd_input_buffer_getc, + .ungetch = snd_input_buffer_ungetc, +}; +#endif + +/** + * \brief Creates a new input object from a memory buffer. + * \param inputp The function puts the pointer to the new input object + * at the address specified by \p inputp. + * \param buf Address of the input buffer. + * \param size Size of the input buffer. + * \return Zero if successful, otherwise a negative error code. + * + * This functions creates a copy of the input buffer, so the application is + * not required to preserve the buffer after this function has been called. + */ +int snd_input_buffer_open(snd_input_t **inputp, const char *buf, ssize_t size) +{ + snd_input_t *input; + snd_input_buffer_t *buffer; + assert(inputp); + buffer = calloc(1, sizeof(*buffer)); + if (!buffer) + return -ENOMEM; + input = calloc(1, sizeof(*input)); + if (!input) { + free(buffer); + return -ENOMEM; + } + if (size < 0) + size = strlen(buf); + buffer->buf = malloc((size_t)size + 1); + if (!buffer->buf) { + free(input); + free(buffer); + return -ENOMEM; + } + memcpy(buffer->buf, buf, (size_t) size); + buffer->buf[size] = 0; + buffer->ptr = buffer->buf; + buffer->size = size; + input->type = SND_INPUT_BUFFER; + input->ops = &snd_input_buffer_ops; + input->private_data = buffer; + *inputp = input; + return 0; +} + diff --git a/src/mixer/Makefile.am b/src/mixer/Makefile.am new file mode 100644 index 0000000..bb466ed --- /dev/null +++ b/src/mixer/Makefile.am @@ -0,0 +1,10 @@ +EXTRA_LTLIBRARIES=libmixer.la + +libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c simple_abst.c + +noinst_HEADERS = mixer_local.h mixer_simple.h + +all: libmixer.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/mixer/Makefile.in b/src/mixer/Makefile.in new file mode 100644 index 0000000..2d5e0c3 --- /dev/null +++ b/src/mixer/Makefile.in @@ -0,0 +1,496 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/mixer +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libmixer_la_LIBADD = +am_libmixer_la_OBJECTS = bag.lo mixer.lo simple.lo simple_none.lo \ + simple_abst.lo +libmixer_la_OBJECTS = $(am_libmixer_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libmixer_la_SOURCES) +DIST_SOURCES = $(libmixer_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libmixer.la +libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c simple_abst.c +noinst_HEADERS = mixer_local.h mixer_simple.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/mixer/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/mixer/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libmixer.la: $(libmixer_la_OBJECTS) $(libmixer_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmixer_la_OBJECTS) $(libmixer_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bag.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mixer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_abst.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_none.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +all: libmixer.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/mixer/bag.c b/src/mixer/bag.c new file mode 100644 index 0000000..d88a900 --- /dev/null +++ b/src/mixer/bag.c @@ -0,0 +1,73 @@ +/* + * Bag of pointers + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "mixer_local.h" + +int bag_new(bag_t **bag) +{ + bag_t *b = malloc(sizeof(*b)); + if (!b) + return -ENOMEM; + INIT_LIST_HEAD(b); + *bag = b; + return 0; +} + +void bag_free(bag_t *bag) +{ + assert(list_empty(bag)); + free(bag); +} + +int bag_empty(bag_t *bag) +{ + return list_empty(bag); +} + +int bag_add(bag_t *bag, void *ptr) +{ + bag1_t *b = malloc(sizeof(*b)); + if (!b) + return -ENOMEM; + b->ptr = ptr; + list_add_tail(&b->list, bag); + return 0; +} + +int bag_del(bag_t *bag, void *ptr) +{ + struct list_head *pos; + list_for_each(pos, bag) { + bag1_t *b = list_entry(pos, bag1_t, list); + if (b->ptr == ptr) { + list_del(&b->list); + free(b); + return 0; + } + } + return -ENOENT; +} + +void bag_del_all(bag_t *bag) +{ + while (!list_empty(bag)) + list_del(bag->next); +} diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c new file mode 100644 index 0000000..85d843f --- /dev/null +++ b/src/mixer/mixer.c @@ -0,0 +1,1083 @@ +/** + * \file mixer/mixer.c + * \brief Mixer Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2001 + * + * Mixer interface is designed to access mixer elements. + * Callbacks may be used for event handling. + */ +/* + * Mixer Interface - main file + * Copyright (c) 1998/1999/2000 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page mixer Mixer interface + +

Mixer interface is designed to access the abstracted mixer controls. +This is an abstraction layer over the hcontrol layer. + +\section mixer_general_overview General overview + +*/ + +#include +#include +#include +#include +#include +#include +#include "mixer_local.h" + +#ifndef DOC_HIDDEN +typedef struct _snd_mixer_slave { + snd_hctl_t *hctl; + struct list_head list; +} snd_mixer_slave_t; + +#endif + +static int snd_mixer_compare_default(const snd_mixer_elem_t *c1, + const snd_mixer_elem_t *c2); + + +/** + * \brief Opens an empty mixer + * \param mixerp Returned mixer handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED) +{ + snd_mixer_t *mixer; + assert(mixerp); + mixer = calloc(1, sizeof(*mixer)); + if (mixer == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&mixer->slaves); + INIT_LIST_HEAD(&mixer->classes); + INIT_LIST_HEAD(&mixer->elems); + mixer->compare = snd_mixer_compare_default; + *mixerp = mixer; + return 0; +} + +/** + * \brief Attach an HCTL element to a mixer element + * \param melem Mixer element + * \param helem HCTL element + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_attach(snd_mixer_elem_t *melem, + snd_hctl_elem_t *helem) +{ + bag_t *bag = snd_hctl_elem_get_callback_private(helem); + int err; + err = bag_add(bag, melem); + if (err < 0) + return err; + return bag_add(&melem->helems, helem); +} + +/** + * \brief Detach an HCTL element from a mixer element + * \param melem Mixer element + * \param helem HCTL element + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_detach(snd_mixer_elem_t *melem, + snd_hctl_elem_t *helem) +{ + bag_t *bag = snd_hctl_elem_get_callback_private(helem); + int err; + err = bag_del(bag, melem); + assert(err >= 0); + err = bag_del(&melem->helems, helem); + assert(err >= 0); + return 0; +} + +/** + * \brief Return true if a mixer element does not contain any HCTL elements + * \param melem Mixer element + * \return 0 if not empty, 1 if empty + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_empty(snd_mixer_elem_t *melem) +{ + return bag_empty(&melem->helems); +} + +static int hctl_elem_event_handler(snd_hctl_elem_t *helem, + unsigned int mask) +{ + bag_t *bag = snd_hctl_elem_get_callback_private(helem); + if (mask == SND_CTL_EVENT_MASK_REMOVE) { + int res = 0; + int err; + bag_iterator_t i, n; + bag_for_each_safe(i, n, bag) { + snd_mixer_elem_t *melem = bag_iterator_entry(i); + snd_mixer_class_t *class = melem->class; + err = class->event(class, mask, helem, melem); + if (err < 0) + res = err; + } + assert(bag_empty(bag)); + bag_free(bag); + return res; + } + if (mask & (SND_CTL_EVENT_MASK_VALUE | SND_CTL_EVENT_MASK_INFO)) { + int err = 0; + bag_iterator_t i, n; + bag_for_each_safe(i, n, bag) { + snd_mixer_elem_t *melem = bag_iterator_entry(i); + snd_mixer_class_t *class = melem->class; + err = class->event(class, mask, helem, melem); + if (err < 0) + return err; + } + } + return 0; +} + +static int hctl_event_handler(snd_hctl_t *hctl, unsigned int mask, + snd_hctl_elem_t *elem) +{ + snd_mixer_t *mixer = snd_hctl_get_callback_private(hctl); + int res = 0; + if (mask & SND_CTL_EVENT_MASK_ADD) { + struct list_head *pos; + bag_t *bag; + int err = bag_new(&bag); + if (err < 0) + return err; + snd_hctl_elem_set_callback(elem, hctl_elem_event_handler); + snd_hctl_elem_set_callback_private(elem, bag); + list_for_each(pos, &mixer->classes) { + snd_mixer_class_t *c; + c = list_entry(pos, snd_mixer_class_t, list); + err = c->event(c, mask, elem, NULL); + if (err < 0) + res = err; + } + } + return res; +} + + +/** + * \brief Attach an HCTL specified with the CTL device name to an opened mixer + * \param mixer Mixer handle + * \param name HCTL name (see #snd_hctl_open) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_attach(snd_mixer_t *mixer, const char *name) +{ + snd_hctl_t *hctl; + int err; + + err = snd_hctl_open(&hctl, name, 0); + if (err < 0) + return err; + err = snd_mixer_attach_hctl(mixer, hctl); + if (err < 0) { + snd_hctl_close(hctl); + return err; + } + return 0; +} + +/** + * \brief Attach an HCTL to an opened mixer + * \param mixer Mixer handle + * \param hctl the HCTL to be attached + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) +{ + snd_mixer_slave_t *slave; + int err; + + assert(hctl); + slave = calloc(1, sizeof(*slave)); + if (slave == NULL) + return -ENOMEM; + err = snd_hctl_nonblock(hctl, 1); + if (err < 0) { + snd_hctl_close(hctl); + free(slave); + return err; + } + snd_hctl_set_callback(hctl, hctl_event_handler); + snd_hctl_set_callback_private(hctl, mixer); + slave->hctl = hctl; + list_add_tail(&slave->list, &mixer->slaves); + return 0; +} + +/** + * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources + * \param mixer Mixer handle + * \param name HCTL previously attached + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_detach(snd_mixer_t *mixer, const char *name) +{ + struct list_head *pos; + list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + s = list_entry(pos, snd_mixer_slave_t, list); + if (strcmp(name, snd_hctl_name(s->hctl)) == 0) { + snd_hctl_close(s->hctl); + list_del(pos); + free(s); + return 0; + } + } + return -ENOENT; +} + +/** + * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources + * \param mixer Mixer handle + * \param hctl HCTL previously attached + * \return 0 on success otherwise a negative error code + * + * Note: The hctl handle is not closed! + */ +int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) +{ + struct list_head *pos; + list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + s = list_entry(pos, snd_mixer_slave_t, list); + if (hctl == s->hctl) { + list_del(pos); + free(s); + return 0; + } + } + return -ENOENT; +} + +/** + * \brief Obtain a HCTL pointer associated to given name + * \param mixer Mixer handle + * \param name HCTL previously attached + * \param hctl HCTL pointer + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl) +{ + struct list_head *pos; + list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + s = list_entry(pos, snd_mixer_slave_t, list); + if (strcmp(name, snd_hctl_name(s->hctl)) == 0) { + *hctl = s->hctl; + return 0; + } + } + return -ENOENT; +} + +static int snd_mixer_throw_event(snd_mixer_t *mixer, unsigned int mask, + snd_mixer_elem_t *elem) +{ + mixer->events++; + if (mixer->callback) + return mixer->callback(mixer, mask, elem); + return 0; +} + +static int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem, unsigned int mask) +{ + elem->class->mixer->events++; + if (elem->callback) + return elem->callback(elem, mask); + return 0; +} + +static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir) +{ + unsigned int l, u; + int c = 0; + int idx = -1; + assert(mixer && elem); + assert(mixer->compare); + l = 0; + u = mixer->count; + while (l < u) { + idx = (l + u) / 2; + c = mixer->compare(elem, mixer->pelems[idx]); + if (c < 0) + u = idx; + else if (c > 0) + l = idx + 1; + else + break; + } + *dir = c; + return idx; +} + +/** + * \brief Get private data associated to give mixer element + * \param elem Mixer element + * \return private data + * + * For use by mixer element class specific code. + */ +void *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem) +{ + return elem->private_data; +} + +/** + * \brief Allocate a new mixer element + * \param elem Returned mixer element + * \param type Mixer element type + * \param compare_weight Mixer element compare weight + * \param private_data Private data + * \param private_free Private data free callback + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_new(snd_mixer_elem_t **elem, + snd_mixer_elem_type_t type, + int compare_weight, + void *private_data, + void (*private_free)(snd_mixer_elem_t *elem)) +{ + snd_mixer_elem_t *melem = calloc(1, sizeof(*melem)); + if (melem == NULL) + return -ENOMEM; + melem->type = type; + melem->compare_weight = compare_weight; + melem->private_data = private_data; + melem->private_free = private_free; + INIT_LIST_HEAD(&melem->helems); + *elem = melem; + return 0; +} + +/** + * \brief Add an element for a registered mixer element class + * \param elem Mixer element + * \param class Mixer element class + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class) +{ + int dir, idx; + snd_mixer_t *mixer = class->mixer; + elem->class = class; + + if (mixer->count == mixer->alloc) { + snd_mixer_elem_t **m; + mixer->alloc += 32; + m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc); + if (!m) { + mixer->alloc -= 32; + return -ENOMEM; + } + mixer->pelems = m; + } + if (mixer->count == 0) { + list_add_tail(&elem->list, &mixer->elems); + mixer->pelems[0] = elem; + } else { + idx = _snd_mixer_find_elem(mixer, elem, &dir); + assert(dir != 0); + if (dir > 0) { + list_add(&elem->list, &mixer->pelems[idx]->list); + idx++; + } else { + list_add_tail(&elem->list, &mixer->pelems[idx]->list); + } + memmove(mixer->pelems + idx + 1, + mixer->pelems + idx, + (mixer->count - idx) * sizeof(snd_mixer_elem_t *)); + mixer->pelems[idx] = elem; + } + mixer->count++; + return snd_mixer_throw_event(mixer, SND_CTL_EVENT_MASK_ADD, elem); +} + +/** + * \brief Remove a mixer element + * \param elem Mixer element + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_remove(snd_mixer_elem_t *elem) +{ + snd_mixer_t *mixer = elem->class->mixer; + bag_iterator_t i, n; + int err, idx, dir; + unsigned int m; + assert(elem); + assert(mixer->count); + idx = _snd_mixer_find_elem(mixer, elem, &dir); + if (dir != 0) + return -EINVAL; + bag_for_each_safe(i, n, &elem->helems) { + snd_hctl_elem_t *helem = bag_iterator_entry(i); + snd_mixer_elem_detach(elem, helem); + } + err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE); + list_del(&elem->list); + snd_mixer_elem_free(elem); + mixer->count--; + m = mixer->count - idx; + if (m > 0) + memmove(mixer->pelems + idx, + mixer->pelems + idx + 1, + m * sizeof(snd_mixer_elem_t *)); + return err; +} + +/** + * \brief Free a mixer element + * \param elem Mixer element + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +void snd_mixer_elem_free(snd_mixer_elem_t *elem) +{ + if (elem->private_free) + elem->private_free(elem); + free(elem); +} + +/** + * \brief Mixer element informations are changed + * \param elem Mixer element + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_info(snd_mixer_elem_t *elem) +{ + return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO); +} + +/** + * \brief Mixer element values is changed + * \param elem Mixer element + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_elem_value(snd_mixer_elem_t *elem) +{ + return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE); +} + +/** + * \brief Register mixer element class + * \param class Mixer element class + * \param mixer Mixer handle + * \return 0 on success otherwise a negative error code + * + * For use by mixer element class specific code. + */ +int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer) +{ + struct list_head *pos; + class->mixer = mixer; + list_add_tail(&class->list, &mixer->classes); + if (!class->event) + return 0; + list_for_each(pos, &mixer->slaves) { + int err; + snd_mixer_slave_t *slave; + snd_hctl_elem_t *elem; + slave = list_entry(pos, snd_mixer_slave_t, list); + elem = snd_hctl_first_elem(slave->hctl); + while (elem) { + err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL); + if (err < 0) + return err; + elem = snd_hctl_elem_next(elem); + } + } + return 0; +} + +/** + * \brief Unregister mixer element class and remove all its elements + * \param class Mixer element class + * \return 0 on success otherwise a negative error code + * + * Note that the class structure is also deallocated! + */ +int snd_mixer_class_unregister(snd_mixer_class_t *class) +{ + unsigned int k; + snd_mixer_elem_t *e; + snd_mixer_t *mixer = class->mixer; + for (k = mixer->count; k > 0; k--) { + e = mixer->pelems[k-1]; + if (e->class == class) + snd_mixer_elem_remove(e); + } + if (class->private_free) + class->private_free(class); + list_del(&class->list); + free(class); + return 0; +} + +/** + * \brief Load a mixer elements + * \param mixer Mixer handle + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_load(snd_mixer_t *mixer) +{ + struct list_head *pos; + list_for_each(pos, &mixer->slaves) { + int err; + snd_mixer_slave_t *s; + s = list_entry(pos, snd_mixer_slave_t, list); + err = snd_hctl_load(s->hctl); + if (err < 0) + return err; + } + return 0; +} + +/** + * \brief Unload all mixer elements and free all related resources + * \param mixer Mixer handle + */ +void snd_mixer_free(snd_mixer_t *mixer) +{ + struct list_head *pos; + list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + s = list_entry(pos, snd_mixer_slave_t, list); + snd_hctl_free(s->hctl); + } +} + +/** + * \brief Close a mixer and free all related resources + * \param mixer Mixer handle + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_close(snd_mixer_t *mixer) +{ + int res = 0; + assert(mixer); + while (!list_empty(&mixer->classes)) { + snd_mixer_class_t *c; + c = list_entry(mixer->classes.next, snd_mixer_class_t, list); + snd_mixer_class_unregister(c); + } + assert(list_empty(&mixer->elems)); + assert(mixer->count == 0); + free(mixer->pelems); + mixer->pelems = NULL; + while (!list_empty(&mixer->slaves)) { + int err; + snd_mixer_slave_t *s; + s = list_entry(mixer->slaves.next, snd_mixer_slave_t, list); + err = snd_hctl_close(s->hctl); + if (err < 0) + res = err; + list_del(&s->list); + free(s); + } + free(mixer); + return res; +} + +static int snd_mixer_compare_default(const snd_mixer_elem_t *c1, + const snd_mixer_elem_t *c2) +{ + int d = c1->compare_weight - c2->compare_weight; + if (d) + return d; + assert(c1->class && c1->class->compare); + assert(c2->class && c2->class->compare); + assert(c1->class == c2->class); + return c1->class->compare(c1, c2); +} + +static int mixer_compare(const void *a, const void *b) +{ + snd_mixer_t *mixer; + + mixer = (*((const snd_mixer_elem_t * const *)a))->class->mixer; + return mixer->compare(*(const snd_mixer_elem_t * const *)a, *(const snd_mixer_elem_t * const *)b); +} + +static int snd_mixer_sort(snd_mixer_t *mixer) +{ + unsigned int k; + assert(mixer); + assert(mixer->compare); + INIT_LIST_HEAD(&mixer->elems); + qsort(mixer->pelems, mixer->count, sizeof(snd_mixer_elem_t *), mixer_compare); + for (k = 0; k < mixer->count; k++) + list_add_tail(&mixer->pelems[k]->list, &mixer->elems); + return 0; +} + +/** + * \brief Change mixer compare function and reorder elements + * \param mixer Mixer handle + * \param compare Element compare function + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare) +{ + snd_mixer_compare_t compare_old; + int err; + + assert(mixer); + compare_old = mixer->compare; + mixer->compare = compare == NULL ? snd_mixer_compare_default : compare; + if ((err = snd_mixer_sort(mixer)) < 0) { + mixer->compare = compare_old; + return err; + } + return 0; +} + +/** + * \brief get count of poll descriptors for mixer handle + * \param mixer Mixer handle + * \return count of poll descriptors + */ +int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer) +{ + struct list_head *pos; + unsigned int c = 0; + assert(mixer); + list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + int n; + s = list_entry(pos, snd_mixer_slave_t, list); + n = snd_hctl_poll_descriptors_count(s->hctl); + if (n < 0) + return n; + c += n; + } + return c; +} + +/** + * \brief get poll descriptors + * \param mixer Mixer handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space) +{ + struct list_head *pos; + unsigned int count = 0; + assert(mixer); + list_for_each(pos, &mixer->slaves) { + snd_mixer_slave_t *s; + int n; + s = list_entry(pos, snd_mixer_slave_t, list); + n = snd_hctl_poll_descriptors(s->hctl, pfds, space); + if (n < 0) + return n; + if (space >= (unsigned int) n) { + count += n; + space -= n; + pfds += n; + } else + space = 0; + } + return count; +} + +/** + * \brief get returned events from poll descriptors + * \param mixer Mixer handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + unsigned int idx; + unsigned short res; + assert(mixer && pfds && revents); + if (nfds == 0) + return -EINVAL; + res = 0; + for (idx = 0; idx < nfds; idx++) + res |= pfds->revents & (POLLIN|POLLERR|POLLNVAL); + *revents = res; + return 0; +} + +/** + * \brief Wait for a mixer to become ready (i.e. at least one event pending) + * \param mixer Mixer handle + * \param timeout maximum time in milliseconds to wait + * \return 0 otherwise a negative error code on failure + */ +int snd_mixer_wait(snd_mixer_t *mixer, int timeout) +{ + struct pollfd spfds[16]; + struct pollfd *pfds = spfds; + int err; + int count; + count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0])); + if (count < 0) + return count; + if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) { + pfds = malloc(count * sizeof(*pfds)); + if (!pfds) + return -ENOMEM; + err = snd_mixer_poll_descriptors(mixer, pfds, + (unsigned int) count); + assert(err == count); + } + err = poll(pfds, (unsigned int) count, timeout); + if (err < 0) + return -errno; + return 0; +} + +/** + * \brief get first element for a mixer + * \param mixer Mixer handle + * \return pointer to first element + */ +snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer) +{ + assert(mixer); + if (list_empty(&mixer->elems)) + return NULL; + return list_entry(mixer->elems.next, snd_mixer_elem_t, list); +} + +/** + * \brief get last element for a mixer + * \param mixer Mixer handle + * \return pointer to last element + */ +snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer) +{ + assert(mixer); + if (list_empty(&mixer->elems)) + return NULL; + return list_entry(mixer->elems.prev, snd_mixer_elem_t, list); +} + +/** + * \brief get next mixer element + * \param elem mixer element + * \return pointer to next element + */ +snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem) +{ + assert(elem); + if (elem->list.next == &elem->class->mixer->elems) + return NULL; + return list_entry(elem->list.next, snd_mixer_elem_t, list); +} + +/** + * \brief get previous mixer element + * \param elem mixer element + * \return pointer to previous element + */ +snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem) +{ + assert(elem); + if (elem->list.prev == &elem->class->mixer->elems) + return NULL; + return list_entry(elem->list.prev, snd_mixer_elem_t, list); +} + +/** + * \brief Handle pending mixer events invoking callbacks + * \param mixer Mixer handle + * \return Number of events that occured on success, otherwise a negative error code on failure + */ +int snd_mixer_handle_events(snd_mixer_t *mixer) +{ + struct list_head *pos; + assert(mixer); + mixer->events = 0; + list_for_each(pos, &mixer->slaves) { + int err; + snd_mixer_slave_t *s; + s = list_entry(pos, snd_mixer_slave_t, list); + err = snd_hctl_handle_events(s->hctl); + if (err < 0) + return err; + } + return mixer->events; +} + +/** + * \brief Set callback function for a mixer + * \param obj mixer handle + * \param val callback function + */ +void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val) +{ + assert(obj); + obj->callback = val; +} + +/** + * \brief Set callback private value for a mixer + * \param mixer mixer handle + * \param val callback private value + */ +void snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val) +{ + assert(mixer); + mixer->callback_private = val; +} + +/** + * \brief Get callback private value for a mixer + * \param mixer mixer handle + * \return callback private value + */ +void * snd_mixer_get_callback_private(const snd_mixer_t *mixer) +{ + assert(mixer); + return mixer->callback_private; +} + +/** + * \brief Get elements count for a mixer + * \param mixer mixer handle + * \return elements count + */ +unsigned int snd_mixer_get_count(const snd_mixer_t *mixer) +{ + assert(mixer); + return mixer->count; +} + +/** + * \brief Set callback function for a mixer element + * \param mixer mixer element + * \param val callback function + */ +void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val) +{ + assert(mixer); + mixer->callback = val; +} + +/** + * \brief Set callback private value for a mixer element + * \param mixer mixer element + * \param val callback private value + */ +void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *mixer, void * val) +{ + assert(mixer); + mixer->callback_private = val; +} + +/** + * \brief Get callback private value for a mixer element + * \param mixer mixer element + * \return callback private value + */ +void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *mixer) +{ + assert(mixer); + return mixer->callback_private; +} + +/** + * \brief Get type for a mixer element + * \param mixer mixer element + * \return mixer element type + */ +snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer) +{ + assert(mixer); + return mixer->type; +} + + +/** + * \brief get size of #snd_mixer_class_t + * \return size in bytes + */ +size_t snd_mixer_class_sizeof() +{ + return sizeof(snd_mixer_class_t); +} + +/** + * \brief allocate an invalid #snd_mixer_class_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_mixer_class_malloc(snd_mixer_class_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_mixer_class_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_mixer_class_t + * \param obj pointer to object to free + */ +void snd_mixer_class_free(snd_mixer_class_t *obj) +{ + if (obj->private_free) + obj->private_free(obj); + free(obj); +} + +/** + * \brief copy one #snd_mixer_class_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get a mixer associated to given mixer class + * \param obj Mixer simple class identifier + * \return mixer pointer + */ +snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *obj) +{ + assert(obj); + return obj->mixer; +} + +/** + * \brief Get mixer event callback associated to given mixer class + * \param obj Mixer simple class identifier + * \return event callback pointer + */ +snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *obj) +{ + assert(obj); + return obj->event; +} + +/** + * \brief Get mixer private data associated to given mixer class + * \param obj Mixer simple class identifier + * \return event callback pointer + */ +void *snd_mixer_class_get_private(const snd_mixer_class_t *obj) +{ + assert(obj); + return obj->private_data; +} + + +/** + * \brief Get mixer compare callback associated to given mixer class + * \param obj Mixer simple class identifier + * \return event callback pointer + */ +snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *obj) +{ + assert(obj); + return obj->compare; +} + +/** + * \brief Set mixer event callback to given mixer class + * \param obj Mixer simple class identifier + * \param event Event callback + * \return zero if success, otherwise a negative error code + */ +int snd_mixer_class_set_event(snd_mixer_class_t *obj, snd_mixer_event_t event) +{ + assert(obj); + obj->event = event; + return 0; +} + +/** + * \brief Set mixer private data to given mixer class + * \param obj Mixer simple class identifier + * \param private_data class private data + * \return zero if success, otherwise a negative error code + */ +int snd_mixer_class_set_private(snd_mixer_class_t *obj, void *private_data) +{ + assert(obj); + obj->private_data = private_data; + return 0; +} + +/** + * \brief Set mixer private data free callback to given mixer class + * \param obj Mixer simple class identifier + * \param private_free Mixer class private data free callback + * \return zero if success, otherwise a negative error code + */ +int snd_mixer_class_set_private_free(snd_mixer_class_t *obj, void (*private_free)(snd_mixer_class_t *class)) +{ + assert(obj); + obj->private_free = private_free; + return 0; +} + +/** + * \brief Set mixer compare callback to given mixer class + * \param obj Mixer simple class identifier + * \param compare the compare callback to be used + * \return zero if success, otherwise a negative error code + */ +int snd_mixer_class_set_compare(snd_mixer_class_t *obj, snd_mixer_compare_t compare) +{ + assert(obj); + obj->compare = compare; + return 0; +} diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h new file mode 100644 index 0000000..27b4a3b --- /dev/null +++ b/src/mixer/mixer_local.h @@ -0,0 +1,82 @@ +/* + * Mixer Interface - local header file + * Copyright (c) 2000 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "local.h" + +typedef struct _bag1 { + void *ptr; + struct list_head list; +} bag1_t; + +typedef struct list_head bag_t; + +int bag_new(bag_t **bag); +void bag_free(bag_t *bag); +int bag_add(bag_t *bag, void *ptr); +int bag_del(bag_t *bag, void *ptr); +int bag_empty(bag_t *bag); +void bag_del_all(bag_t *bag); + +typedef struct list_head *bag_iterator_t; + +#define bag_iterator_entry(i) (list_entry((i), bag1_t, list)->ptr) +#define bag_for_each(pos, bag) list_for_each(pos, bag) +#define bag_for_each_safe(pos, next, bag) list_for_each_safe(pos, next, bag) + +struct _snd_mixer_class { + struct list_head list; + snd_mixer_t *mixer; + snd_mixer_event_t event; + void *private_data; + void (*private_free)(snd_mixer_class_t *class); + snd_mixer_compare_t compare; +}; + +struct _snd_mixer_elem { + snd_mixer_elem_type_t type; + struct list_head list; /* links for list of all elems */ + snd_mixer_class_t *class; + void *private_data; + void (*private_free)(snd_mixer_elem_t *elem); + snd_mixer_elem_callback_t callback; + void *callback_private; + bag_t helems; + int compare_weight; /* compare weight (reversed) */ +}; + +struct _snd_mixer { + struct list_head slaves; /* list of all slaves */ + struct list_head classes; /* list of all elem classes */ + struct list_head elems; /* list of all elems */ + snd_mixer_elem_t **pelems; /* array of all elems */ + unsigned int count; + unsigned int alloc; + unsigned int events; + snd_mixer_callback_t callback; + void *callback_private; + snd_mixer_compare_t compare; +}; + +struct _snd_mixer_selem_id { + char name[60]; + unsigned int index; +}; diff --git a/src/mixer/mixer_simple.h b/src/mixer/mixer_simple.h new file mode 100644 index 0000000..e88b007 --- /dev/null +++ b/src/mixer/mixer_simple.h @@ -0,0 +1,31 @@ +/* + * Mixer Simple Interface - local header file + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "mixer_abst.h" + +/* make local functions really local */ +#define snd_mixer_simple_none_register \ + snd1_mixer_simple_none_register +#define snd_mixer_simple_basic_register \ + snd1_mixer_simple_basic_register + +int snd_mixer_simple_none_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp); +int snd_mixer_simple_basic_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp); diff --git a/src/mixer/simple.c b/src/mixer/simple.c new file mode 100644 index 0000000..8079fe7 --- /dev/null +++ b/src/mixer/simple.c @@ -0,0 +1,1055 @@ +/** + * \file mixer/simple.c + * \brief Mixer Simple Element Class Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2001-2004 + * + * Mixer simple element class interface. + */ +/* + * Mixer Interface - simple controls + * Copyright (c) 2000,2004 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mixer_local.h" +#include "mixer_simple.h" + +/** + * \brief Register mixer simple element class + * \param mixer Mixer handle + * \param options Options container + * \param classp Pointer to returned mixer simple element class handle (or NULL) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_register(snd_mixer_t *mixer, + struct snd_mixer_selem_regopt *options, + snd_mixer_class_t **classp) +{ + if (options && options->ver == 1) { + if (options->device != NULL && + (options->playback_pcm != NULL || + options->capture_pcm != NULL)) + return -EINVAL; + if (options->device == NULL && + options->playback_pcm == NULL && + options->capture_pcm == NULL) + return -EINVAL; + } + if (options == NULL || + (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) { + int err = snd_mixer_simple_none_register(mixer, options, classp); + if (err < 0) + return err; + if (options != NULL) { + err = snd_mixer_attach(mixer, options->device); + if (err < 0) + return err; + } + return 0; + } else if (options->ver == 1) { + if (options->abstract == SND_MIXER_SABSTRACT_BASIC) + return snd_mixer_simple_basic_register(mixer, options, classp); + } + return -ENXIO; +} + +#ifndef DOC_HIDDEN + +#define CHECK_BASIC(xelem) \ +{ \ + assert(xelem); \ + assert((xelem)->type == SND_MIXER_ELEM_SIMPLE); \ +} + +#define CHECK_DIR(xelem, xwhat) \ +{ \ + unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \ + if (! (xcaps & (xwhat))) \ + return -EINVAL; \ +} + +#define CHECK_DIR_CHN(xelem, xwhat, xjoin, xchannel) \ +{ \ + unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \ + if (! (xcaps & (xwhat))) \ + return -EINVAL; \ + if (xcaps & (xjoin)) \ + xchannel = 0; \ +} + +#define CHECK_ENUM(xelem) \ + if (!(((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM))) \ + return -EINVAL; + +#define COND_CAPS(xelem, what) \ + !!(((sm_selem_t *)(elem)->private_data)->caps & (what)) + +#endif /* !DOC_HIDDEN */ + +#ifndef DOC_HIDDEN +int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2) +{ + sm_selem_t *s1 = c1->private_data; + sm_selem_t *s2 = c2->private_data; + int res = strcmp(s1->id->name, s2->id->name); + if (res) + return res; + return s1->id->index - s2->id->index; +} +#endif + +/** + * \brief Find a mixer simple element + * \param mixer Mixer handle + * \param id Mixer simple element identifier + * \return mixer simple element handle or NULL if not found + */ +snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, + const snd_mixer_selem_id_t *id) +{ + struct list_head *list; + snd_mixer_elem_t *e; + sm_selem_t *s; + + list_for_each(list, &mixer->elems) { + e = list_entry(list, snd_mixer_elem_t, list); + if (e->type != SND_MIXER_ELEM_SIMPLE) + continue; + s = e->private_data; + if (!strcmp(s->id->name, id->name) && s->id->index == id->index) + return e; + } + return NULL; +} + +/** + * \brief Get mixer simple element identifier + * \param elem Mixer simple element handle + * \param id returned mixer simple element identifier + */ +void snd_mixer_selem_get_id(snd_mixer_elem_t *elem, + snd_mixer_selem_id_t *id) +{ + sm_selem_t *s; + assert(id); + CHECK_BASIC(elem); + s = elem->private_data; + *id = *s->id; +} + +/** + * \brief Get name part of mixer simple element identifier + * \param elem Mixer simple element handle + * \return name part of simple element identifier + */ +const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem) +{ + sm_selem_t *s; + CHECK_BASIC(elem); + s = elem->private_data; + return s->id->name; +} + +/** + * \brief Get index part of mixer simple element identifier + * \param elem Mixer simple element handle + * \return index part of simple element identifier + */ +unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem) +{ + sm_selem_t *s; + CHECK_BASIC(elem); + s = elem->private_data; + return s->id->index; +} + +/** + * \brief Return true if mixer simple element has only one volume control for both playback and capture + * \param elem Mixer simple element handle + * \return 0 separated control, 1 common control + */ +int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_GVOLUME); +} + +/** + * \brief Return true if mixer simple element has only one switch control for both playback and capture + * \param elem Mixer simple element handle + * \return 0 separated control, 1 common control + */ +int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_GSWITCH); +} + +/** + * \brief Return name of mixer simple element channel + * \param channel mixer simple element channel identifier + * \return channel name + */ +const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel) +{ + static const char *const array[SND_MIXER_SCHN_LAST + 1] = { + [SND_MIXER_SCHN_FRONT_LEFT] = "Front Left", + [SND_MIXER_SCHN_FRONT_RIGHT] = "Front Right", + [SND_MIXER_SCHN_REAR_LEFT] = "Rear Left", + [SND_MIXER_SCHN_REAR_RIGHT] = "Rear Right", + [SND_MIXER_SCHN_FRONT_CENTER] = "Front Center", + [SND_MIXER_SCHN_WOOFER] = "Woofer", + [SND_MIXER_SCHN_SIDE_LEFT] = "Side Left", + [SND_MIXER_SCHN_SIDE_RIGHT] = "Side Right", + [SND_MIXER_SCHN_REAR_CENTER] = "Rear Center" + }; + const char *p; + assert(channel <= SND_MIXER_SCHN_LAST); + p = array[channel]; + if (!p) + return "?"; + return p; +} + +/** + * \brief Get info about the active state of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not active, 1 if active + */ +int snd_mixer_selem_is_active(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0); +} + +/** + * \brief Get info about channels of playback stream of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not mono, 1 if mono + */ +int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_MONO, 0); +} + +/** + * \brief Get info about channels of playback stream of a mixer simple element + * \param elem Mixer simple element handle + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present + */ +int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) +{ + CHECK_BASIC(elem); + return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_CHANNEL, (int)channel); +} + +/** + * \brief Get range for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum + * \param max Pointer to returned maximum + */ +int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_PVOLUME); + return sm_selem_ops(elem)->get_range(elem, SM_PLAY, min, max); +} + +/** + * \brief Get range in dB for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum (dB * 100) + * \param max Pointer to returned maximum (dB * 100) + */ +int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_PVOLUME); + return sm_selem_ops(elem)->get_dB_range(elem, SM_PLAY, min, max); +} + +/** + * \brief Set range for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min minimum volume value + * \param max maximum volume value + */ +int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, + long min, long max) +{ + CHECK_BASIC(elem); + assert(min < max); + CHECK_DIR(elem, SM_CAP_PVOLUME); + return sm_selem_ops(elem)->set_range(elem, SM_PLAY, min, max); +} + +/** + * \brief Return info about playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_PVOLUME); +} + +/** + * \brief Return info about playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN); +} + +/** + * \brief Return info about playback switch control existence of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_PSWITCH); +} + +/** + * \brief Return info about playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN); +} + +/** + * \brief Return corresponding dB value to an integer playback volume for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_PVOLUME); + return sm_selem_ops(elem)->ask_vol_dB(elem, SM_PLAY, value, dBvalue); +} + +/** + * \brief Return corresponding integer playback volume for given dB value for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_PVOLUME); + return sm_selem_ops(elem)->ask_dB_vol(elem, SM_PLAY, dBvalue, value, dir); +} + +/** + * \brief Return value of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); + return sm_selem_ops(elem)->get_volume(elem, SM_PLAY, channel, value); +} + +/** + * \brief Return value of playback volume in dB control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value (dB * 100) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + unsigned int caps; + + CHECK_BASIC(elem); + caps = ((sm_selem_t *)elem->private_data)->caps; + if (!(caps & SM_CAP_PVOLUME)) + return -EINVAL; + if (caps & SM_CAP_PVOLUME_JOIN) + channel = 0; + return sm_selem_ops(elem)->get_dB(elem, SM_PLAY, channel, value); +} + +/** + * \brief Return value of playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel); + return sm_selem_ops(elem)->get_switch(elem, SM_PLAY, channel, value); +} + +/** + * \brief Set value of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); + return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value); +} + +/** + * \brief Set value in dB of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); + return sm_selem_ops(elem)->set_dB(elem, SM_PLAY, channel, value, dir); +} + +/** + * \brief Set value of playback volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value) +{ + snd_mixer_selem_channel_id_t chn; + int err; + + for (chn = 0; chn < 32; chn++) { + if (!snd_mixer_selem_has_playback_channel(elem, chn)) + continue; + err = snd_mixer_selem_set_playback_volume(elem, chn, value); + if (err < 0) + return err; + if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) + return 0; + } + return 0; +} + +/** + * \brief Set value in dB of playback volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir) +{ + snd_mixer_selem_channel_id_t chn; + int err; + + for (chn = 0; chn < 32; chn++) { + if (!snd_mixer_selem_has_playback_channel(elem, chn)) + continue; + err = snd_mixer_selem_set_playback_dB(elem, chn, value, dir); + if (err < 0) + return err; + if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) + return 0; + } + return 0; +} + +/** + * \brief Set value of playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel); + return sm_selem_ops(elem)->set_switch(elem, SM_PLAY, channel, value); +} + +/** + * \brief Set value of playback switch control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value) +{ + snd_mixer_selem_channel_id_t chn; + int err; + + CHECK_BASIC(elem); + for (chn = 0; chn < 32; chn++) { + if (!snd_mixer_selem_has_playback_channel(elem, chn)) + continue; + err = snd_mixer_selem_set_playback_switch(elem, chn, value); + if (err < 0) + return err; + if (chn == 0 && snd_mixer_selem_has_playback_switch_joined(elem)) + return 0; + } + return 0; +} + +/** + * \brief Get info about channels of capture stream of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not mono, 1 if mono + */ +int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH); + return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_MONO, 0); +} + +/** + * \brief Get info about channels of capture stream of a mixer simple element + * \param elem Mixer simple element handle + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present + */ +int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH); + return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_CHANNEL, channel); +} + +/** + * \brief Get range for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum + * \param max Pointer to returned maximum + */ +int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_CVOLUME); + return sm_selem_ops(elem)->get_range(elem, SM_CAPT, min, max); +} + +/** + * \brief Get range in dB for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum (dB * 100) + * \param max Pointer to returned maximum (dB * 100) + */ +int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_CVOLUME); + return sm_selem_ops(elem)->get_dB_range(elem, SM_CAPT, min, max); +} + +/** + * \brief Set range for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min minimum volume value + * \param max maximum volume value + */ +int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, + long min, long max) +{ + CHECK_BASIC(elem); + assert(min < max); + CHECK_DIR(elem, SM_CAP_CVOLUME); + return sm_selem_ops(elem)->set_range(elem, SM_CAPT, min, max); +} + +/** + * \brief Return info about capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_CVOLUME); +} + +/** + * \brief Return info about capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN); +} + +/** + * \brief Return info about capture switch control existence of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_CSWITCH); +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN); +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group) + */ +int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL); +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive) + */ +int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem) +{ + sm_selem_t *s; + CHECK_BASIC(elem); + s = elem->private_data; + if (! (s->caps & SM_CAP_CSWITCH_EXCL)) + return -EINVAL; + return s->capture_group; +} + +/** + * \brief Return corresponding dB value to an integer capture volume for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_CVOLUME); + return sm_selem_ops(elem)->ask_vol_dB(elem, SM_CAPT, value, dBvalue); +} + +/** + * \brief Return corresponding integer capture volume for given dB value for a mixer simple element + * \param elem Mixer simple element handle + * \param dBvalue dB value to be converted to integer range + * \param value pointer to returned integer value + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) +{ + CHECK_BASIC(elem); + CHECK_DIR(elem, SM_CAP_CVOLUME); + return sm_selem_ops(elem)->ask_dB_vol(elem, SM_CAPT, dBvalue, value, dir); +} + +/** + * \brief Return value of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); + return sm_selem_ops(elem)->get_volume(elem, SM_CAPT, channel, value); +} + +/** + * \brief Return value of capture volume in dB control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value (dB * 100) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); + return sm_selem_ops(elem)->get_dB(elem, SM_CAPT, channel, value); +} + +/** + * \brief Return value of capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel); + return sm_selem_ops(elem)->get_switch(elem, SM_CAPT, channel, value); +} + +/** + * \brief Set value of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); + return sm_selem_ops(elem)->set_volume(elem, SM_CAPT, channel, value); +} + +/** + * \brief Set value in dB of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); + return sm_selem_ops(elem)->set_dB(elem, SM_CAPT, channel, value, dir); +} + +/** + * \brief Set value of capture volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value) +{ + snd_mixer_selem_channel_id_t chn; + int err; + + for (chn = 0; chn < 32; chn++) { + if (!snd_mixer_selem_has_capture_channel(elem, chn)) + continue; + err = snd_mixer_selem_set_capture_volume(elem, chn, value); + if (err < 0) + return err; + if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem)) + return 0; + } + return 0; +} + +/** + * \brief Set value in dB of capture volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir) +{ + snd_mixer_selem_channel_id_t chn; + int err; + + for (chn = 0; chn < 32; chn++) { + if (!snd_mixer_selem_has_capture_channel(elem, chn)) + continue; + err = snd_mixer_selem_set_capture_dB(elem, chn, value, dir); + if (err < 0) + return err; + if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem)) + return 0; + } + return 0; +} + +/** + * \brief Set value of capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) +{ + CHECK_BASIC(elem); + CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel); + return sm_selem_ops(elem)->set_switch(elem, SM_CAPT, channel, value); +} + +/** + * \brief Set value of capture switch control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value) +{ + snd_mixer_selem_channel_id_t chn; + int err; + + for (chn = 0; chn < 32; chn++) { + if (!snd_mixer_selem_has_capture_channel(elem, chn)) + continue; + err = snd_mixer_selem_set_capture_switch(elem, chn, value); + if (err < 0) + return err; + if (chn == 0 && snd_mixer_selem_has_capture_switch_joined(elem)) + return 0; + } + return 0; +} + +/** + * \brief Return true if mixer simple element is an enumerated control + * \param elem Mixer simple element handle + * \return 0 normal volume/switch control, 1 enumerated control + */ +int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0); +} + +/** + * \brief Return true if mixer simple enumerated element belongs to the playback direction + * \param elem Mixer simple element handle + * \return 0 no playback direction, 1 playback direction + */ +int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + CHECK_ENUM(elem); + return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1); +} + +/** + * \brief Return true if mixer simple enumerated element belongs to the capture direction + * \param elem Mixer simple element handle + * \return 0 no capture direction, 1 capture direction + */ +int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + CHECK_ENUM(elem); + return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1); +} + +/** + * \brief Return the number of enumerated items of the given mixer simple element + * \param elem Mixer simple element handle + * \return the number of enumerated items, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) +{ + CHECK_BASIC(elem); + CHECK_ENUM(elem); + return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0); +} + +/** + * \brief get the enumerated item string for the given mixer simple element + * \param elem Mixer simple element handle + * \param item the index of the enumerated item to query + * \param maxlen the maximal length to be stored + * \param buf the buffer to store the name string + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, + unsigned int item, + size_t maxlen, char *buf) +{ + CHECK_BASIC(elem); + CHECK_ENUM(elem); + return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf); +} + +/** + * \brief get the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param itemp the pointer to store the index of the enumerated item + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int *itemp) +{ + CHECK_BASIC(elem); + CHECK_ENUM(elem); + return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp); +} + +/** + * \brief set the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param item the enumerated item index + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int item) +{ + CHECK_BASIC(elem); + CHECK_ENUM(elem); + return sm_selem_ops(elem)->set_enum_item(elem, channel, item); +} + +/** + * \brief get size of #snd_mixer_selem_id_t + * \return size in bytes + */ +size_t snd_mixer_selem_id_sizeof() +{ + return sizeof(snd_mixer_selem_id_t); +} + +/** + * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_mixer_selem_id_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_mixer_selem_id_t + * \param obj pointer to object to free + */ +void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_mixer_selem_id_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get name part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \return name part + */ +const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj) +{ + assert(obj); + return obj->name; +} + +/** + * \brief Get index part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \return index part + */ +unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj) +{ + assert(obj); + return obj->index; +} + +/** + * \brief Set name part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \param val name part + */ +void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val) +{ + assert(obj); + strncpy(obj->name, val, sizeof(obj->name)); + obj->name[sizeof(obj->name)-1] = '\0'; +} + +/** + * \brief Set index part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \param val index part + */ +void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val) +{ + assert(obj); + obj->index = val; +} diff --git a/src/mixer/simple_abst.c b/src/mixer/simple_abst.c new file mode 100644 index 0000000..9e9aaf5 --- /dev/null +++ b/src/mixer/simple_abst.c @@ -0,0 +1,420 @@ +/** + * \file mixer/simple_abst.c + * \brief Mixer Simple Element Class Interface - Module Abstraction + * \author Jaroslav Kysela + * \date 2005 + * + * Mixer simple element class interface. + */ +/* + * Mixer Interface - simple controls - abstraction module + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "asoundlib.h" +#include "mixer_simple.h" + +#ifndef DOC_HIDDEN + +#define SO_PATH ALSA_PLUGIN_DIR "/smixer" + +typedef struct _class_priv { + char *device; + snd_ctl_t *ctl; + snd_hctl_t *hctl; + int attach_flag; + snd_ctl_card_info_t *info; + void *dlhandle; + void *private_data; + void (*private_free)(snd_mixer_class_t *class); +} class_priv_t; + +typedef int (*snd_mixer_sbasic_init_t)(snd_mixer_class_t *class); +typedef int (*snd_mixer_sfbasic_init_t)(snd_mixer_class_t *class, + snd_mixer_t *mixer, + const char *device); + +#endif /* !DOC_HIDDEN */ + +static int try_open(snd_mixer_class_t *class, const char *lib) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + snd_mixer_event_t event_func; + snd_mixer_sbasic_init_t init_func = NULL; + char *xlib, *path; + void *h; + int err = 0; + + path = getenv("ALSA_MIXER_SIMPLE_MODULES"); + if (!path) + path = SO_PATH; + xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); + if (xlib == NULL) + return -ENOMEM; + strcpy(xlib, path); + strcat(xlib, "/"); + strcat(xlib, lib); + h = snd_dlopen(xlib, RTLD_NOW); + if (h == NULL) { + SNDERR("Unable to open library '%s'", xlib); + free(xlib); + return -ENXIO; + } + priv->dlhandle = h; + event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL); + if (event_func == NULL) { + SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); + err = -ENXIO; + } + if (err == 0) { + init_func = snd_dlsym(h, "alsa_mixer_simple_init", NULL); + if (init_func == NULL) { + SNDERR("Symbol 'alsa_mixer_simple_init' was not found in '%s'", xlib); + err = -ENXIO; + } + } + free(xlib); + err = err == 0 ? init_func(class) : err; + if (err < 0) + return err; + snd_mixer_class_set_event(class, event_func); + return 1; +} + +static int try_open_full(snd_mixer_class_t *class, snd_mixer_t *mixer, + const char *lib, const char *device) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + snd_mixer_event_t event_func; + snd_mixer_sfbasic_init_t init_func = NULL; + char *xlib, *path; + void *h; + int err = 0; + + path = getenv("ALSA_MIXER_SIMPLE_MODULES"); + if (!path) + path = SO_PATH; + xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); + if (xlib == NULL) + return -ENOMEM; + strcpy(xlib, path); + strcat(xlib, "/"); + strcat(xlib, lib); + /* note python modules requires RTLD_GLOBAL */ + h = snd_dlopen(xlib, RTLD_NOW|RTLD_GLOBAL); + if (h == NULL) { + SNDERR("Unable to open library '%s'", xlib); + free(xlib); + return -ENXIO; + } + priv->dlhandle = h; + event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL); + if (event_func == NULL) { + SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); + err = -ENXIO; + } + if (err == 0) { + init_func = snd_dlsym(h, "alsa_mixer_simple_finit", NULL); + if (init_func == NULL) { + SNDERR("Symbol 'alsa_mixer_simple_finit' was not found in '%s'", xlib); + err = -ENXIO; + } + } + free(xlib); + err = err == 0 ? init_func(class, mixer, device) : err; + if (err < 0) + return err; + snd_mixer_class_set_event(class, event_func); + return 1; +} + +static int match(snd_mixer_class_t *class, const char *lib, const char *searchl) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + const char *components; + + if (searchl == NULL) + return try_open(class, lib); + components = snd_ctl_card_info_get_components(priv->info); + while (*components != '\0') { + if (!strncmp(components, searchl, strlen(searchl))) + return try_open(class, lib); + while (*components != ' ' && *components != '\0') + components++; + while (*components == ' ' && *components != '\0') + components++; + } + return 0; +} + +static int find_full(snd_mixer_class_t *class, snd_mixer_t *mixer, + snd_config_t *top, const char *device) +{ + snd_config_iterator_t i, next; + char *lib; + const char *id; + int err; + + snd_config_for_each(i, next, top) { + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "_full")) + continue; + err = snd_config_get_string(n, (const char **)&lib); + if (err < 0) + return err; + err = try_open_full(class, mixer, lib, device); + if (err < 0) + return err; + return 0; + } + return -ENOENT; +} + +static int find_module(snd_mixer_class_t *class, snd_config_t *top) +{ + snd_config_iterator_t i, next; + snd_config_iterator_t j, jnext; + char *lib, *searchl; + const char *id; + int err; + + snd_config_for_each(i, next, top) { + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + if (*id == '_') + continue; + searchl = NULL; + lib = NULL; + snd_config_for_each(j, jnext, n) { + snd_config_t *m = snd_config_iterator_entry(j); + if (snd_config_get_id(m, &id) < 0) + continue; + if (!strcmp(id, "searchl")) { + err = snd_config_get_string(m, (const char **)&searchl); + if (err < 0) + return err; + continue; + } + if (!strcmp(id, "lib")) { + err = snd_config_get_string(m, (const char **)&lib); + if (err < 0) + return err; + continue; + } + } + err = match(class, lib, searchl); + if (err == 1) + return 0; + if (err < 0) + return err; + } + return -ENOENT; +} + +static void private_free(snd_mixer_class_t *class) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + + if (priv->private_free) + priv->private_free(class); + if (priv->dlhandle) + snd_dlclose(priv->dlhandle); + if (priv->info) + snd_ctl_card_info_free(priv->info); + if (priv->hctl) { + if (priv->attach_flag) + snd_mixer_detach_hctl(snd_mixer_class_get_mixer(class), priv->hctl); + snd_hctl_close(priv->hctl); + } else if (priv->ctl) + snd_ctl_close(priv->ctl); + free(priv->device); + free(priv); +} + +/** + * \brief Register mixer simple element class - basic abstraction + * \param mixer Mixer handle + * \param options Options container + * \param classp Pointer to returned mixer simple element class handle (or NULL + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_simple_basic_register(snd_mixer_t *mixer, + struct snd_mixer_selem_regopt *options, + snd_mixer_class_t **classp) +{ + snd_mixer_class_t *class; + class_priv_t *priv = calloc(1, sizeof(*priv)); + const char *file; + snd_input_t *input; + snd_config_t *top = NULL; + int err; + + if (priv == NULL) + return -ENOMEM; + if (options->device == NULL) { + free(priv); + return -EINVAL; + } + if (snd_mixer_class_malloc(&class)) { + free(priv); + return -ENOMEM; + } + priv->device = strdup(options->device); + if (priv->device == NULL) { + free(priv); + snd_mixer_class_free(class); + return -ENOMEM; + } + snd_mixer_class_set_compare(class, snd_mixer_selem_compare); + snd_mixer_class_set_private(class, priv); + snd_mixer_class_set_private_free(class, private_free); + file = getenv("ALSA_MIXER_SIMPLE"); + if (!file) + file = ALSA_CONFIG_DIR "/smixer.conf"; + err = snd_config_top(&top); + if (err >= 0) { + err = snd_input_stdio_open(&input, file, "r"); + if (err < 0) { + SNDERR("unable to open simple mixer configuration file '%s'", file); + goto __error; + } + err = snd_config_load(top, input); + snd_input_close(input); + if (err < 0) { + SNDERR("%s may be old or corrupted: consider to remove or fix it", file); + goto __error; + } + err = find_full(class, mixer, top, priv->device); + if (err >= 0) + goto __full; + } + if (err >= 0) { + err = snd_ctl_open(&priv->ctl, priv->device, 0); + if (err < 0) { + SNDERR("unable to open control device '%s': %s", priv->device, snd_strerror(err)); + goto __error; + } + err = snd_hctl_open_ctl(&priv->hctl, priv->ctl); + if (err < 0) + goto __error; + err = snd_ctl_card_info_malloc(&priv->info); + if (err < 0) + goto __error; + err = snd_ctl_card_info(priv->ctl, priv->info); + if (err < 0) + goto __error; + } + if (err >= 0) + err = find_module(class, top); + if (err >= 0) + err = snd_mixer_attach_hctl(mixer, priv->hctl); + if (err >= 0) { + priv->attach_flag = 1; + err = snd_mixer_class_register(class, mixer); + } + __full: + if (err < 0) { + __error: + if (top) + snd_config_delete(top); + if (class) + snd_mixer_class_free(class); + return err; + } + if (top) + snd_config_delete(top); + if (classp) + *classp = class; + return 0; +} + +/** + * \brief Basic Mixer Abstraction - Get information about device + * \param class Mixer class + * \param info Info structure + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + + if (class == NULL || info == NULL) + return -EINVAL; + info->device = priv->device; + info->ctl = priv->ctl; + info->hctl = priv->hctl; + info->info = priv->info; + return 0; +} + +/** + * \brief Get private data for basic abstraction + * \param class Mixer class + * \return private data + */ +void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + + if (class == NULL) + return NULL; + return priv->private_data; +} + +/** + * \brief Set private data for basic abstraction + * \param class Mixer class + * \param private_data Private data + */ +void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data) +{ + class_priv_t *priv; + + if (class == NULL) + return; + priv = snd_mixer_class_get_private(class); + priv->private_data = private_data; +} + +/** + * \brief Set private data free callback for basic abstraction + * \param class Mixer class + * \param private_free free callback for private data + */ +void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class)) +{ + class_priv_t *priv; + + if (class == NULL) + return; + priv = snd_mixer_class_get_private(class); + priv->private_free = private_free; +} diff --git a/src/mixer/simple_none.c b/src/mixer/simple_none.c new file mode 100644 index 0000000..426f2d7 --- /dev/null +++ b/src/mixer/simple_none.c @@ -0,0 +1,1727 @@ +/** + * \file mixer/simple_none.c + * \brief Mixer Simple Element Class Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2001-2004 + * + * Mixer simple element class interface. + */ +/* + * Mixer Interface - simple controls + * Copyright (c) 2000,2004 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mixer_simple.h" +#include "config.h" + +#ifndef DOC_HIDDEN + +#define MIXER_COMPARE_WEIGHT_SIMPLE_BASE 0 +#define MIXER_COMPARE_WEIGHT_NEXT_BASE 10000000 +#define MIXER_COMPARE_WEIGHT_NOT_FOUND 1000000000 + +typedef enum _selem_ctl_type { + CTL_SINGLE, + CTL_GLOBAL_ENUM, + CTL_GLOBAL_SWITCH, + CTL_GLOBAL_VOLUME, + CTL_GLOBAL_ROUTE, + CTL_PLAYBACK_ENUM, + CTL_PLAYBACK_SWITCH, + CTL_PLAYBACK_VOLUME, + CTL_PLAYBACK_ROUTE, + CTL_CAPTURE_ENUM, + CTL_CAPTURE_SWITCH, + CTL_CAPTURE_VOLUME, + CTL_CAPTURE_ROUTE, + CTL_CAPTURE_SOURCE, + CTL_LAST = CTL_CAPTURE_SOURCE, +} selem_ctl_type_t; + +typedef struct _selem_ctl { + snd_hctl_elem_t *elem; + snd_ctl_elem_type_t type; + unsigned int inactive: 1; + unsigned int values; + long min, max; +} selem_ctl_t; + +typedef struct _selem_none { + sm_selem_t selem; + selem_ctl_t ctls[CTL_LAST + 1]; + unsigned int capture_item; + struct selem_str { + unsigned int range: 1; /* Forced range */ + unsigned int db_initialized: 1; + unsigned int db_init_error: 1; + long min, max; + unsigned int channels; + long vol[32]; + unsigned int sw; + unsigned int *db_info; + } str[2]; +} selem_none_t; + +static const struct mixer_name_table { + const char *longname; + const char *shortname; +} name_table[] = { + {"Tone Control - Switch", "Tone"}, + {"Tone Control - Bass", "Bass"}, + {"Tone Control - Treble", "Treble"}, + {"Synth Tone Control - Switch", "Synth Tone"}, + {"Synth Tone Control - Bass", "Synth Bass"}, + {"Synth Tone Control - Treble", "Synth Treble"}, + {0, 0}, +}; + +#endif /* !DOC_HIDDEN */ + +static const char *get_short_name(const char *lname) +{ + const struct mixer_name_table *p; + for (p = name_table; p->longname; p++) { + if (!strcmp(lname, p->longname)) + return p->shortname; + } + return lname; +} + +static int compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) +{ + int res; + + for (res = 0; *names; names++, res += coef) { + if (!strncmp(*name, *names, strlen(*names))) { + *name += strlen(*names); + if (**name == ' ') + (*name)++; + return res+1; + } + } + return MIXER_COMPARE_WEIGHT_NOT_FOUND; +} + +static int get_compare_weight(const char *name, unsigned int idx) +{ + static const char *const names[] = { + "Master", + "Headphone", + "Speaker", + "Tone", + "Bass", + "Treble", + "3D Control", + "PCM", + "Front", + "Surround", + "Center", + "LFE", + "Side", + "Synth", + "FM", + "Wave", + "Music", + "DSP", + "Line", + "CD", + "Mic", + "Video", + "Zoom Video", + "Phone", + "I2S", + "IEC958", + "PC Speaker", + "Beep", + "Aux", + "Mono", + "Playback", + "Capture", + "Mix", + NULL + }; + static const char *const names1[] = { + "-", + NULL, + }; + static const char *const names2[] = { + "Mono", + "Digital", + "Switch", + "Depth", + "Wide", + "Space", + "Level", + "Center", + "Output", + "Boost", + "Tone", + "Bass", + "Treble", + NULL, + }; + const char *name1; + int res, res1; + + if ((res = compare_mixer_priority_lookup((const char **)&name, names, 1000)) == MIXER_COMPARE_WEIGHT_NOT_FOUND) + return MIXER_COMPARE_WEIGHT_NOT_FOUND; + if (*name == '\0') + goto __res; + for (name1 = name; *name1 != '\0'; name1++); + for (name1--; name1 != name && *name1 != ' '; name1--); + while (name1 != name && *name1 == ' ') + name1--; + if (name1 != name) { + for (; name1 != name && *name1 != ' '; name1--); + name = name1; + if ((res1 = compare_mixer_priority_lookup((const char **)&name, names1, 200)) == MIXER_COMPARE_WEIGHT_NOT_FOUND) + return res; + res += res1; + } else { + name = name1; + } + if ((res1 = compare_mixer_priority_lookup((const char **)&name, names2, 20)) == MIXER_COMPARE_WEIGHT_NOT_FOUND) + return res; + __res: + return MIXER_COMPARE_WEIGHT_SIMPLE_BASE + res + idx; +} + +static long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) +{ + int64_t n; + if (c->max == c->min) + return s->str[dir].min; + n = (int64_t) (value - c->min) * (s->str[dir].max - s->str[dir].min); + return s->str[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min); +} + +static long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) +{ + int64_t n; + if (s->str[dir].max == s->str[dir].min) + return c->min; + n = (int64_t) (value - s->str[dir].min) * (c->max - c->min); + return c->min + (n + (s->str[dir].max - s->str[dir].min) / 2) / (s->str[dir].max - s->str[dir].min); +} + +static int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < s->str[dir].channels; idx++) { + unsigned int idx1 = idx; + if (idx >= c->values) + idx1 = 0; + s->str[dir].vol[idx] = to_user(s, dir, c, snd_ctl_elem_value_get_integer(ctl, idx1)); + } + return 0; +} + +static int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < s->str[dir].channels; idx++) { + unsigned int idx1 = idx; + if (idx >= c->values) + idx1 = 0; + if (!snd_ctl_elem_value_get_integer(ctl, idx1)) + s->str[dir].sw &= ~(1 << idx); + } + return 0; +} + +static int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < s->str[dir].channels; idx++) { + unsigned int idx1 = idx; + if (idx >= c->values) + idx1 = 0; + if (!snd_ctl_elem_value_get_integer(ctl, idx1 * c->values + idx1)) + s->str[dir].sw &= ~(1 << idx); + } + return 0; +} + +static int elem_read_enum(selem_none_t *s) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + int type; + selem_ctl_t *c; + type = CTL_GLOBAL_ENUM; + if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) + type = CTL_GLOBAL_ENUM; + else if (s->selem.caps & SM_CAP_PENUM) + type = CTL_PLAYBACK_ENUM; + else if (s->selem.caps & SM_CAP_CENUM) + type = CTL_CAPTURE_ENUM; + c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < s->str[0].channels; idx++) { + unsigned int idx1 = idx; + if (idx >= c->values) + idx1 = 0; + s->str[0].vol[idx] = snd_ctl_elem_value_get_enumerated(ctl, idx1); + } + return 0; +} + +static int selem_read(snd_mixer_elem_t *elem) +{ + selem_none_t *s; + unsigned int idx; + int err = 0; + long pvol[32], cvol[32]; + unsigned int psw, csw; + + assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); + s = snd_mixer_elem_get_private(elem); + + memcpy(pvol, s->str[SM_PLAY].vol, sizeof(pvol)); + memset(&s->str[SM_PLAY].vol, 0, sizeof(s->str[SM_PLAY].vol)); + psw = s->str[SM_PLAY].sw; + s->str[SM_PLAY].sw = ~0U; + memcpy(cvol, s->str[SM_CAPT].vol, sizeof(cvol)); + memset(&s->str[SM_CAPT].vol, 0, sizeof(s->str[SM_CAPT].vol)); + csw = s->str[SM_CAPT].sw; + s->str[SM_CAPT].sw = ~0U; + + if (s->ctls[CTL_GLOBAL_ENUM].elem) { + err = elem_read_enum(s); + if (err < 0) + return err; + goto __skip_cswitch; + } + + if (s->ctls[CTL_CAPTURE_ENUM].elem) { + err = elem_read_enum(s); + if (err < 0) + return err; + goto __skip_cswitch; + } + + if (s->ctls[CTL_PLAYBACK_ENUM].elem) { + err = elem_read_enum(s); + if (err < 0) + return err; + goto __skip_cswitch; + } + + + if (s->ctls[CTL_PLAYBACK_VOLUME].elem) + err = elem_read_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME); + else if (s->ctls[CTL_GLOBAL_VOLUME].elem) + err = elem_read_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME); + else if (s->ctls[CTL_SINGLE].elem && + s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) + err = elem_read_volume(s, SM_PLAY, CTL_SINGLE); + if (err < 0) + return err; + + if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) { + s->str[SM_PLAY].sw = 0; + goto __skip_pswitch; + } + if (s->ctls[CTL_PLAYBACK_SWITCH].elem) { + err = elem_read_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_GLOBAL_SWITCH].elem) { + err = elem_read_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_SINGLE].elem && + s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) { + err = elem_read_switch(s, SM_PLAY, CTL_SINGLE); + if (err < 0) + return err; + } + if (s->ctls[CTL_PLAYBACK_ROUTE].elem) { + err = elem_read_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE); + if (err < 0) + return err; + } + if (s->ctls[CTL_GLOBAL_ROUTE].elem) { + err = elem_read_route(s, SM_PLAY, CTL_GLOBAL_ROUTE); + if (err < 0) + return err; + } + __skip_pswitch: + + if (s->ctls[CTL_CAPTURE_VOLUME].elem) + err = elem_read_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME); + else if (s->ctls[CTL_GLOBAL_VOLUME].elem) + err = elem_read_volume(s, SM_CAPT, CTL_GLOBAL_VOLUME); + else if (s->ctls[CTL_SINGLE].elem && + s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) + err = elem_read_volume(s, SM_CAPT, CTL_SINGLE); + if (err < 0) + return err; + + if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) { + s->str[SM_CAPT].sw = 0; + goto __skip_cswitch; + } + if (s->ctls[CTL_CAPTURE_SWITCH].elem) { + err = elem_read_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_GLOBAL_SWITCH].elem) { + err = elem_read_switch(s, SM_CAPT, CTL_GLOBAL_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_SINGLE].elem && + s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) { + err = elem_read_switch(s, SM_CAPT, CTL_SINGLE); + if (err < 0) + return err; + } + if (s->ctls[CTL_CAPTURE_ROUTE].elem) { + err = elem_read_route(s, SM_CAPT, CTL_CAPTURE_ROUTE); + if (err < 0) + return err; + } + if (s->ctls[CTL_GLOBAL_ROUTE].elem) { + err = elem_read_route(s, SM_CAPT, CTL_GLOBAL_ROUTE); + if (err < 0) + return err; + } + if (s->ctls[CTL_CAPTURE_SOURCE].elem) { + snd_ctl_elem_value_t *ctl; + selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; + snd_ctl_elem_value_alloca(&ctl); + err = snd_hctl_elem_read(c->elem, ctl); + if (err < 0) + return err; + for (idx = 0; idx < s->str[SM_CAPT].channels; idx++) { + unsigned int idx1 = idx; + if (idx >= c->values) + idx1 = 0; + if (snd_ctl_elem_value_get_enumerated(ctl, idx1) != s->capture_item) + s->str[SM_CAPT].sw &= ~(1 << idx); + } + } + __skip_cswitch: + + if (memcmp(pvol, s->str[SM_PLAY].vol, sizeof(pvol)) || + psw != s->str[SM_PLAY].sw || + memcmp(cvol, s->str[SM_CAPT].vol, sizeof(cvol)) || + csw != s->str[SM_CAPT].sw) + return 1; + return 0; +} + +static int elem_write_volume(selem_none_t *s, int dir, selem_ctl_type_t type) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < c->values; idx++) + snd_ctl_elem_value_set_integer(ctl, idx, from_user(s, dir, c, s->str[dir].vol[idx])); + if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + return err; + return 0; +} + +static int elem_write_switch(selem_none_t *s, int dir, selem_ctl_type_t type) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < c->values; idx++) + snd_ctl_elem_value_set_integer(ctl, idx, !!(s->str[dir].sw & (1 << idx))); + if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + return err; + return 0; +} + +static int elem_write_switch_constant(selem_none_t *s, selem_ctl_type_t type, int val) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < c->values; idx++) + snd_ctl_elem_value_set_integer(ctl, idx, !!val); + if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + return err; + return 0; +} + +static int elem_write_route(selem_none_t *s, int dir, selem_ctl_type_t type) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < c->values * c->values; idx++) + snd_ctl_elem_value_set_integer(ctl, idx, 0); + for (idx = 0; idx < c->values; idx++) + snd_ctl_elem_value_set_integer(ctl, idx * c->values + idx, !!(s->str[dir].sw & (1 << idx))); + if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + return err; + return 0; +} + +static int elem_write_enum(selem_none_t *s) +{ + snd_ctl_elem_value_t *ctl; + unsigned int idx; + int err; + int type; + selem_ctl_t *c; + type = CTL_GLOBAL_ENUM; + if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) == (SM_CAP_CENUM | SM_CAP_PENUM) ) + type = CTL_GLOBAL_ENUM; + else if (s->selem.caps & SM_CAP_PENUM) + type = CTL_PLAYBACK_ENUM; + else if (s->selem.caps & SM_CAP_CENUM) + type = CTL_CAPTURE_ENUM; + c = &s->ctls[type]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < c->values; idx++) + snd_ctl_elem_value_set_enumerated(ctl, idx, (unsigned int)s->str[0].vol[idx]); + if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + return err; + return 0; +} + +static int selem_write_main(snd_mixer_elem_t *elem) +{ + selem_none_t *s; + unsigned int idx; + int err; + + assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); + s = snd_mixer_elem_get_private(elem); + + if (s->ctls[CTL_GLOBAL_ENUM].elem) + return elem_write_enum(s); + + if (s->ctls[CTL_PLAYBACK_ENUM].elem) + return elem_write_enum(s); + + if (s->ctls[CTL_CAPTURE_ENUM].elem) + return elem_write_enum(s); + + if (s->ctls[CTL_SINGLE].elem) { + if (s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) + err = elem_write_volume(s, SM_PLAY, CTL_SINGLE); + else + err = elem_write_switch(s, SM_PLAY, CTL_SINGLE); + if (err < 0) + return err; + } + if (s->ctls[CTL_GLOBAL_VOLUME].elem) { + err = elem_write_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME); + if (err < 0) + return err; + } + if (s->ctls[CTL_GLOBAL_SWITCH].elem) { + if (s->ctls[CTL_PLAYBACK_SWITCH].elem && s->ctls[CTL_CAPTURE_SWITCH].elem) + err = elem_write_switch_constant(s, CTL_GLOBAL_SWITCH, 1); + else + err = elem_write_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_PLAYBACK_VOLUME].elem) { + err = elem_write_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME); + if (err < 0) + return err; + } + if (s->ctls[CTL_PLAYBACK_SWITCH].elem) { + err = elem_write_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_PLAYBACK_ROUTE].elem) { + err = elem_write_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE); + if (err < 0) + return err; + } + if (s->ctls[CTL_CAPTURE_VOLUME].elem) { + err = elem_write_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME); + if (err < 0) + return err; + } + if (s->ctls[CTL_CAPTURE_SWITCH].elem) { + err = elem_write_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH); + if (err < 0) + return err; + } + if (s->ctls[CTL_CAPTURE_ROUTE].elem) { + err = elem_write_route(s, SM_CAPT, CTL_CAPTURE_ROUTE); + if (err < 0) + return err; + } + if (s->ctls[CTL_CAPTURE_SOURCE].elem) { + snd_ctl_elem_value_t *ctl; + selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; + snd_ctl_elem_value_alloca(&ctl); + if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + return err; + for (idx = 0; idx < c->values; idx++) { + if (s->str[SM_CAPT].sw & (1 << idx)) + snd_ctl_elem_value_set_enumerated(ctl, idx, s->capture_item); + } + if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + return err; + /* update the element, don't remove */ + err = selem_read(elem); + if (err < 0) + return err; + } + return 0; +} + +static int selem_write(snd_mixer_elem_t *elem) +{ + int err; + + err = selem_write_main(elem); + if (err < 0) + selem_read(elem); + return err; +} + +static void selem_free(snd_mixer_elem_t *elem) +{ + selem_none_t *simple = snd_mixer_elem_get_private(elem); + assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); + if (simple->selem.id) + snd_mixer_selem_id_free(simple->selem.id); + /* free db range information */ + free(simple->str[0].db_info); + free(simple->str[1].db_info); + free(simple); +} + +static int simple_update(snd_mixer_elem_t *melem) +{ + selem_none_t *simple; + unsigned int caps, pchannels, cchannels; + long pmin, pmax, cmin, cmax; + selem_ctl_t *ctl; + const char *name; + + caps = 0; + pchannels = 0; + pmin = LONG_MAX; + pmax = LONG_MIN; + cchannels = 0; + cmin = LONG_MAX; + cmax = LONG_MIN; + assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE); + simple = snd_mixer_elem_get_private(melem); + name = snd_mixer_selem_get_name(melem); + ctl = &simple->ctls[CTL_SINGLE]; + if (ctl->elem) { + pchannels = cchannels = ctl->values; + if (ctl->type == SND_CTL_ELEM_TYPE_INTEGER) { + caps |= SM_CAP_GVOLUME; + pmin = cmin = ctl->min; + pmax = cmax = ctl->max; + } else + caps |= SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_GLOBAL_SWITCH]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + if (cchannels < ctl->values) + cchannels = ctl->values; + caps |= SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_GLOBAL_ROUTE]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + if (cchannels < ctl->values) + cchannels = ctl->values; + caps |= SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_GLOBAL_VOLUME]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + if (pmin > ctl->min) + pmin = ctl->min; + if (pmax < ctl->max) + pmax = ctl->max; + if (cchannels < ctl->values) + cchannels = ctl->values; + if (cmin > ctl->min) + cmin = ctl->min; + if (cmax < ctl->max) + cmax = ctl->max; + caps |= SM_CAP_GVOLUME; + } + ctl = &simple->ctls[CTL_PLAYBACK_SWITCH]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + caps |= SM_CAP_PSWITCH; + caps &= ~SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_PLAYBACK_ROUTE]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + caps |= SM_CAP_PSWITCH; + caps &= ~SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_CAPTURE_SWITCH]; + if (ctl->elem) { + if (cchannels < ctl->values) + cchannels = ctl->values; + caps |= SM_CAP_CSWITCH; + caps &= ~SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_CAPTURE_ROUTE]; + if (ctl->elem) { + if (cchannels < ctl->values) + cchannels = ctl->values; + caps |= SM_CAP_CSWITCH; + caps &= ~SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_PLAYBACK_VOLUME]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + if (pmin > ctl->min) + pmin = ctl->min; + if (pmax < ctl->max) + pmax = ctl->max; + caps |= SM_CAP_PVOLUME; + caps &= ~SM_CAP_GVOLUME; + } + ctl = &simple->ctls[CTL_CAPTURE_VOLUME]; + if (ctl->elem) { + if (cchannels < ctl->values) + cchannels = ctl->values; + if (cmin > ctl->min) + cmin = ctl->min; + if (cmax < ctl->max) + cmax = ctl->max; + caps |= SM_CAP_CVOLUME; + caps &= ~SM_CAP_GVOLUME; + } + ctl = &simple->ctls[CTL_CAPTURE_SOURCE]; + if (ctl->elem) { + if (cchannels < ctl->values) + cchannels = ctl->values; + caps |= SM_CAP_CSWITCH | SM_CAP_CSWITCH_EXCL; + caps &= ~SM_CAP_GSWITCH; + } + ctl = &simple->ctls[CTL_GLOBAL_ENUM]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + caps |= SM_CAP_PENUM | SM_CAP_CENUM; + } + ctl = &simple->ctls[CTL_PLAYBACK_ENUM]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + caps |= SM_CAP_PENUM; + } + ctl = &simple->ctls[CTL_CAPTURE_ENUM]; + if (ctl->elem) { + if (pchannels < ctl->values) + pchannels = ctl->values; + caps |= SM_CAP_CENUM; + } + if (pchannels > 32) + pchannels = 32; + if (cchannels > 32) + cchannels = 32; + if (caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) + caps |= SM_CAP_PSWITCH_JOIN; + if (caps & (SM_CAP_GVOLUME|SM_CAP_PVOLUME)) + caps |= SM_CAP_PVOLUME_JOIN; + if (caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) + caps |= SM_CAP_CSWITCH_JOIN; + if (caps & (SM_CAP_GVOLUME|SM_CAP_CVOLUME)) + caps |= SM_CAP_CVOLUME_JOIN; + if (pchannels > 1 || cchannels > 1) { + if (simple->ctls[CTL_SINGLE].elem && + simple->ctls[CTL_SINGLE].values > 1) { + if (caps & SM_CAP_GSWITCH) + caps &= ~(SM_CAP_PSWITCH_JOIN|SM_CAP_CSWITCH_JOIN); + else + caps &= ~(SM_CAP_PVOLUME_JOIN|SM_CAP_CVOLUME_JOIN); + } + if (simple->ctls[CTL_GLOBAL_ROUTE].elem || + (simple->ctls[CTL_GLOBAL_SWITCH].elem && + simple->ctls[CTL_GLOBAL_SWITCH].values > 1)) { + caps &= ~(SM_CAP_PSWITCH_JOIN|SM_CAP_CSWITCH_JOIN); + } + if (simple->ctls[CTL_GLOBAL_VOLUME].elem && + simple->ctls[CTL_GLOBAL_VOLUME].values > 1) { + caps &= ~(SM_CAP_PVOLUME_JOIN|SM_CAP_CVOLUME_JOIN); + } + } + if (pchannels > 1) { + if (simple->ctls[CTL_PLAYBACK_ROUTE].elem || + (simple->ctls[CTL_PLAYBACK_SWITCH].elem && + simple->ctls[CTL_PLAYBACK_SWITCH].values > 1)) { + caps &= ~SM_CAP_PSWITCH_JOIN; + } + if (simple->ctls[CTL_PLAYBACK_VOLUME].elem && + simple->ctls[CTL_PLAYBACK_VOLUME].values > 1) { + caps &= ~SM_CAP_PVOLUME_JOIN; + } + } + if (cchannels > 1) { + if (simple->ctls[CTL_CAPTURE_ROUTE].elem || + (simple->ctls[CTL_CAPTURE_SWITCH].elem && + simple->ctls[CTL_CAPTURE_SWITCH].values > 1) || + (simple->ctls[CTL_CAPTURE_SOURCE].elem && + simple->ctls[CTL_CAPTURE_SOURCE].values > 1)) { + caps &= ~SM_CAP_CSWITCH_JOIN; + } + if (simple->ctls[CTL_CAPTURE_VOLUME].elem && + simple->ctls[CTL_CAPTURE_VOLUME].values > 1) { + caps &= ~SM_CAP_CVOLUME_JOIN; + } + } + + /* exceptions */ + if ((caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH|SM_CAP_CSWITCH)) && + (caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH|SM_CAP_CSWITCH)) == (caps & SM_CAP_GSWITCH)) { + caps &= ~(SM_CAP_GSWITCH|SM_CAP_CSWITCH_JOIN|SM_CAP_CSWITCH_EXCL); + caps |= SM_CAP_PSWITCH; + } + + if ((caps & SM_CAP_GSWITCH) && + (caps & (SM_CAP_PSWITCH|SM_CAP_CSWITCH)) == 0) + caps |= SM_CAP_PSWITCH|SM_CAP_CSWITCH; + + if ((caps & SM_CAP_GVOLUME) && + (caps & (SM_CAP_PVOLUME|SM_CAP_CVOLUME)) == 0) + caps |= SM_CAP_PVOLUME|SM_CAP_CVOLUME; + + simple->selem.caps = caps; + simple->str[SM_PLAY].channels = pchannels; + if (!simple->str[SM_PLAY].range) { + simple->str[SM_PLAY].min = pmin != LONG_MAX ? pmin : 0; + simple->str[SM_PLAY].max = pmax != LONG_MIN ? pmax : 0; + } + simple->str[SM_CAPT].channels = cchannels; + if (!simple->str[SM_CAPT].range) { + simple->str[SM_CAPT].min = cmin != LONG_MAX ? cmin : 0; + simple->str[SM_CAPT].max = cmax != LONG_MIN ? cmax : 0; + } + return 0; +} + +#ifndef DOC_HIDDEN +static const struct suf { + const char *suffix; + selem_ctl_type_t type; +} suffixes[] = { + {" Playback Enum", CTL_PLAYBACK_ENUM}, + {" Playback Switch", CTL_PLAYBACK_SWITCH}, + {" Playback Route", CTL_PLAYBACK_ROUTE}, + {" Playback Volume", CTL_PLAYBACK_VOLUME}, + {" Capture Enum", CTL_CAPTURE_ENUM}, + {" Capture Switch", CTL_CAPTURE_SWITCH}, + {" Capture Route", CTL_CAPTURE_ROUTE}, + {" Capture Volume", CTL_CAPTURE_VOLUME}, + {" Enum", CTL_GLOBAL_ENUM}, + {" Switch", CTL_GLOBAL_SWITCH}, + {" Route", CTL_GLOBAL_ROUTE}, + {" Volume", CTL_GLOBAL_VOLUME}, + {NULL, 0} +}; +#endif + +/* Return base length or 0 on failure */ +static int base_len(const char *name, selem_ctl_type_t *type) +{ + const struct suf *p; + size_t nlen = strlen(name); + p = suffixes; + while (p->suffix) { + size_t slen = strlen(p->suffix); + size_t l; + if (nlen > slen) { + l = nlen - slen; + if (strncmp(name + l, p->suffix, slen) == 0 && + (l < 1 || name[l-1] != '-')) { /* 3D Control - Switch */ + *type = p->type; + return l; + } + } + p++; + } + + /* Special case - handle "Input Source" as a capture route. + * Note that it's *NO* capture source. A capture source is split over + * sub-elements, and multiple capture-sources will result in an error. + * That's why some drivers use "Input Source" as a workaround. + * Hence, this is a workaround for a workaround to get the things + * straight back again. Sigh. + */ + if (!strcmp(name, "Input Source")) { + *type = CTL_CAPTURE_ROUTE; + return strlen(name); + } + + return 0; +} + + +/* + * Simple Mixer Operations + */ + +static int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + if (s->selem.caps & SM_CAP_GVOLUME) + dir = SM_PLAY; + if ((unsigned int) channel >= s->str[dir].channels) + return 0; + if (value < s->str[dir].min || value > s->str[dir].max) + return 0; + if (s->selem.caps & + (dir == SM_PLAY ? SM_CAP_PVOLUME_JOIN : SM_CAP_CVOLUME_JOIN)) + channel = 0; + if (value != s->str[dir].vol[channel]) { + s->str[dir].vol[channel] = value; + return 1; + } + return 0; +} + +static int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + if ((unsigned int) channel >= s->str[dir].channels) + return 0; + if (s->selem.caps & + (dir == SM_PLAY ? SM_CAP_PSWITCH_JOIN : SM_CAP_CSWITCH_JOIN)) + channel = 0; + if (value) { + if (!(s->str[dir].sw & (1 << channel))) { + s->str[dir].sw |= 1 << channel; + return 1; + } + } else { + if (s->str[dir].sw & (1 << channel)) { + s->str[dir].sw &= ~(1 << channel); + return 1; + } + } + return 0; +} + +static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + + switch (cmd) { + + case SM_OPS_IS_ACTIVE: { + selem_ctl_type_t ctl; + for (ctl = CTL_SINGLE; ctl <= CTL_LAST; ctl++) + if (s->ctls[ctl].elem != NULL && s->ctls[ctl].inactive) + return 0; + return 1; + } + + case SM_OPS_IS_MONO: + return s->str[dir].channels == 1; + + case SM_OPS_IS_CHANNEL: + return (unsigned int) val < s->str[dir].channels; + + case SM_OPS_IS_ENUMERATED: + if (val == 1) { + if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM) && !(s->selem.caps & SM_CAP_CENUM) ) + return 1; + if (dir == SM_CAPT && (s->selem.caps & SM_CAP_CENUM) && !(s->selem.caps & SM_CAP_PENUM) ) + return 1; + return 0; + } + if (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) + return 1; + return 0; + + case SM_OPS_IS_ENUMCNT: + /* Both */ + if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) { + if (! s->ctls[CTL_GLOBAL_ENUM].elem) + return -EINVAL; + return s->ctls[CTL_GLOBAL_ENUM].max; + /* Only Playback */ + } else if (s->selem.caps & SM_CAP_PENUM ) { + if (! s->ctls[CTL_PLAYBACK_ENUM].elem) + return -EINVAL; + return s->ctls[CTL_PLAYBACK_ENUM].max; + /* Only Capture */ + } else if (s->selem.caps & SM_CAP_CENUM ) { + if (! s->ctls[CTL_CAPTURE_ENUM].elem) + return -EINVAL; + return s->ctls[CTL_CAPTURE_ENUM].max; + } + + } + + return 1; +} + +static int get_range_ops(snd_mixer_elem_t *elem, int dir, + long *min, long *max) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + *min = s->str[dir].min; + *max = s->str[dir].max; + return 0; +} + +static int set_range_ops(snd_mixer_elem_t *elem, int dir, + long min, long max) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + int err; + + s->str[dir].range = 1; + s->str[dir].min = min; + s->str[dir].max = max; + if ((err = selem_read(elem)) < 0) + return err; + return 0; +} + +static int get_volume_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, long *value) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + if (s->selem.caps & SM_CAP_GVOLUME) + dir = SM_PLAY; + if ((unsigned int) channel >= s->str[dir].channels) + return -EINVAL; + *value = s->str[dir].vol[channel]; + return 0; +} + +static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec); + +static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, + long volume, long *db_gain) +{ + if (init_db_range(ctl, rec) < 0) + return -EINVAL; + return snd_tlv_convert_to_dB(rec->db_info, rec->min, rec->max, + volume, db_gain); +} + +/* initialize dB range information, reading TLV via hcontrol + */ +static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec) +{ + snd_ctl_elem_info_t *info; + unsigned int *tlv = NULL; + const unsigned int tlv_size = 4096; + unsigned int *dbrec; + int db_size; + + if (rec->db_init_error) + return -EINVAL; + if (rec->db_initialized) + return 0; + + snd_ctl_elem_info_alloca(&info); + if (snd_hctl_elem_info(ctl, info) < 0) + goto error; + if (! snd_ctl_elem_info_is_tlv_readable(info)) + goto error; + tlv = malloc(tlv_size); + if (! tlv) + return -ENOMEM; + if (snd_hctl_elem_tlv_read(ctl, tlv, tlv_size) < 0) + goto error; + db_size = snd_tlv_parse_dB_info(tlv, tlv_size, &dbrec); + if (db_size < 0) + goto error; + rec->db_info = malloc(db_size); + if (!rec->db_info) + goto error; + memcpy(rec->db_info, dbrec, db_size); + free(tlv); + rec->db_initialized = 1; + return 0; + + error: + free(tlv); + rec->db_init_error = 1; + return -EINVAL; +} + +/* get selem_ctl for TLV access */ +static selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir) +{ + selem_ctl_t *c; + if (dir == SM_PLAY) + c = &s->ctls[CTL_PLAYBACK_VOLUME]; + else if (dir == SM_CAPT) + c = &s->ctls[CTL_CAPTURE_VOLUME]; + else + return NULL; + if (! c->elem) { + c = &s->ctls[CTL_GLOBAL_VOLUME]; + if (! c->elem) + return NULL; + } + if (c->type != SND_CTL_ELEM_TYPE_INTEGER) + return NULL; + return c; +} + +static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec, + long *min, long *max) +{ + if (init_db_range(ctl, rec) < 0) + return -EINVAL; + + return snd_tlv_get_dB_range(rec->db_info, rec->min, rec->max, min, max); +} + +static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir, + long *min, long *max) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_ctl_t *c; + + if (s->selem.caps & SM_CAP_GVOLUME) + dir = SM_PLAY; + c = get_selem_ctl(s, dir); + if (! c) + return -EINVAL; + return get_dB_range(c->elem, &s->str[dir], min, max); +} + +static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, + long db_gain, long *value, int xdir) +{ + if (init_db_range(ctl, rec) < 0) + return -EINVAL; + + return snd_tlv_convert_from_dB(rec->db_info, rec->min, rec->max, + db_gain, value, xdir); +} + +static int ask_vol_dB_ops(snd_mixer_elem_t *elem, + int dir, + long value, + long *dBvalue) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_ctl_t *c; + + c = get_selem_ctl(s, dir); + if (! c) + return -EINVAL; + int res = convert_to_dB(c->elem, &s->str[dir], value, dBvalue); + return res; +} + +static int get_dB_ops(snd_mixer_elem_t *elem, + int dir, + snd_mixer_selem_channel_id_t channel, + long *value) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_ctl_t *c; + int err; + long volume, db_gain; + + if (s->selem.caps & SM_CAP_GVOLUME) + dir = SM_PLAY; + c = get_selem_ctl(s, dir); + if (! c) + return -EINVAL; + if ((err = get_volume_ops(elem, dir, channel, &volume)) < 0) + goto _err; + if ((err = convert_to_dB(c->elem, &s->str[dir], volume, &db_gain)) < 0) + goto _err; + err = 0; + *value = db_gain; + _err: + return err; +} + +static int get_switch_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, int *value) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + if (s->selem.caps & SM_CAP_GSWITCH) + dir = SM_PLAY; + if ((unsigned int) channel >= s->str[dir].channels) + return -EINVAL; + *value = !!(s->str[dir].sw & (1 << channel)); + return 0; +} + +static int set_volume_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, long value) +{ + int changed; + changed = _snd_mixer_selem_set_volume(elem, dir, channel, value); + if (changed < 0) + return changed; + if (changed) + return selem_write(elem); + return 0; +} + +static int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir, + long dbValue, long *value, int xdir) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_ctl_t *c; + + if (s->selem.caps & SM_CAP_GVOLUME) + dir = SM_PLAY; + c = get_selem_ctl(s, dir); + if (! c) + return -EINVAL; + return convert_from_dB(c->elem, &s->str[dir], dbValue, value, xdir); +} + +static int set_dB_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, + long db_gain, int xdir) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_ctl_t *c; + long value; + int err; + + if (s->selem.caps & SM_CAP_GVOLUME) + dir = SM_PLAY; + c = get_selem_ctl(s, dir); + if (! c) + return -EINVAL; + err = convert_from_dB(c->elem, &s->str[dir], db_gain, &value, xdir); + if (err < 0) + return err; + return set_volume_ops(elem, dir, channel, value); +} + +static int set_switch_ops(snd_mixer_elem_t *elem, int dir, + snd_mixer_selem_channel_id_t channel, int value) +{ + int changed; + selem_none_t *s = snd_mixer_elem_get_private(elem); + if (s->selem.caps & SM_CAP_GSWITCH) + dir = SM_PLAY; + if (dir == SM_PLAY) { + if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH))) + return -EINVAL; + } else { + if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH))) + return -EINVAL; + } + changed = _snd_mixer_selem_set_switch(elem, dir, channel, value); + if (changed < 0) + return changed; + if (changed) + return selem_write(elem); + return 0; +} + +static int enum_item_name_ops(snd_mixer_elem_t *elem, + unsigned int item, + size_t maxlen, char *buf) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + snd_ctl_elem_info_t *info; + snd_hctl_elem_t *helem; + int type; + + type = CTL_GLOBAL_ENUM; + helem = s->ctls[type].elem; + if (!helem) { + type = CTL_PLAYBACK_ENUM; + helem = s->ctls[type].elem; + } + if (!helem) { + type = CTL_CAPTURE_ENUM; + helem = s->ctls[type].elem; + } + assert(helem); + if (item >= (unsigned int)s->ctls[type].max) + return -EINVAL; + snd_ctl_elem_info_alloca(&info); + snd_hctl_elem_info(helem, info); + snd_ctl_elem_info_set_item(info, item); + snd_hctl_elem_info(helem, info); + strncpy(buf, snd_ctl_elem_info_get_item_name(info), maxlen); + return 0; +} + +static int get_enum_item_ops(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int *itemp) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + snd_ctl_elem_value_t *ctl; + snd_hctl_elem_t *helem; + int err; + + if ((unsigned int) channel >= s->str[0].channels) + return -EINVAL; + helem = s->ctls[CTL_GLOBAL_ENUM].elem; + if (!helem) helem = s->ctls[CTL_PLAYBACK_ENUM].elem; + if (!helem) helem = s->ctls[CTL_CAPTURE_ENUM].elem; + assert(helem); + snd_ctl_elem_value_alloca(&ctl); + err = snd_hctl_elem_read(helem, ctl); + if (! err) + *itemp = snd_ctl_elem_value_get_enumerated(ctl, channel); + return err; +} + +static int set_enum_item_ops(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int item) +{ + selem_none_t *s = snd_mixer_elem_get_private(elem); + snd_ctl_elem_value_t *ctl; + snd_hctl_elem_t *helem; + int err; + int type; + + if ((unsigned int) channel >= s->str[0].channels) { + return -EINVAL; + } + type = CTL_GLOBAL_ENUM; + helem = s->ctls[type].elem; + if (!helem) { + type = CTL_PLAYBACK_ENUM; + helem = s->ctls[type].elem; + } + if (!helem) { + type = CTL_CAPTURE_ENUM; + helem = s->ctls[type].elem; + } + assert(helem); + if (item >= (unsigned int)s->ctls[type].max) { + return -EINVAL; + } + snd_ctl_elem_value_alloca(&ctl); + err = snd_hctl_elem_read(helem, ctl); + if (err < 0) { + return err; + } + snd_ctl_elem_value_set_enumerated(ctl, channel, item); + return snd_hctl_elem_write(helem, ctl); +} + +static struct sm_elem_ops simple_none_ops = { + .is = is_ops, + .get_range = get_range_ops, + .get_dB_range = get_dB_range_ops, + .set_range = set_range_ops, + .ask_vol_dB = ask_vol_dB_ops, + .ask_dB_vol = ask_dB_vol_ops, + .get_volume = get_volume_ops, + .get_dB = get_dB_ops, + .set_volume = set_volume_ops, + .set_dB = set_dB_ops, + .get_switch = get_switch_ops, + .set_switch = set_switch_ops, + .enum_item_name = enum_item_name_ops, + .get_enum_item = get_enum_item_ops, + .set_enum_item = set_enum_item_ops +}; + +static int simple_add1(snd_mixer_class_t *class, const char *name, + snd_hctl_elem_t *helem, selem_ctl_type_t type, + unsigned int value) +{ + snd_mixer_elem_t *melem; + snd_mixer_selem_id_t *id; + int new = 0; + int err; + snd_ctl_elem_info_t *info; + selem_none_t *simple; + const char *name1; + snd_ctl_elem_type_t ctype; + unsigned long values; + + snd_ctl_elem_info_alloca(&info); + err = snd_hctl_elem_info(helem, info); + if (err < 0) + return err; + ctype = snd_ctl_elem_info_get_type(info); + values = snd_ctl_elem_info_get_count(info); + switch (type) { + case CTL_SINGLE: + if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) + type = CTL_GLOBAL_ENUM; + else if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN && + ctype != SND_CTL_ELEM_TYPE_INTEGER) + return 0; + break; + case CTL_GLOBAL_ROUTE: + case CTL_PLAYBACK_ROUTE: + case CTL_CAPTURE_ROUTE: + { + unsigned int n; + if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) { + if (type == CTL_PLAYBACK_ROUTE) + type = CTL_PLAYBACK_ENUM; + else if (type == CTL_CAPTURE_ROUTE) + type = CTL_CAPTURE_ENUM; + else + type = CTL_GLOBAL_ENUM; + break; + } + if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) + return 0; +#ifdef HAVE_SOFT_FLOAT + /* up to 256 channels */ + for (n = 1; n < 256; n++) + if (n * n == values) + break; +#else + n = sqrt((double)values); +#endif + if (n * n != values) + return 0; + values = n; + break; + } + case CTL_GLOBAL_SWITCH: + case CTL_PLAYBACK_SWITCH: + case CTL_CAPTURE_SWITCH: + if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) { + if (type == CTL_PLAYBACK_SWITCH) + type = CTL_PLAYBACK_ENUM; + else if (type == CTL_CAPTURE_SWITCH) + type = CTL_CAPTURE_ENUM; + else + type = CTL_GLOBAL_ENUM; + break; + } + if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) + return 0; + break; + case CTL_GLOBAL_VOLUME: + case CTL_PLAYBACK_VOLUME: + case CTL_CAPTURE_VOLUME: + if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) { + if (type == CTL_PLAYBACK_VOLUME) + type = CTL_PLAYBACK_ENUM; + else if (type == CTL_CAPTURE_VOLUME) + type = CTL_CAPTURE_ENUM; + else + type = CTL_GLOBAL_ENUM; + break; + } + if (ctype != SND_CTL_ELEM_TYPE_INTEGER) + return 0; + break; + case CTL_CAPTURE_SOURCE: + if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED) + return 0; + break; + case CTL_GLOBAL_ENUM: + case CTL_PLAYBACK_ENUM: + case CTL_CAPTURE_ENUM: + if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED) + return 0; + break; + default: + assert(0); + break; + } + name1 = get_short_name(name); + if (snd_mixer_selem_id_malloc(&id)) + return -ENOMEM; + snd_mixer_selem_id_set_name(id, name1); + snd_mixer_selem_id_set_index(id, snd_hctl_elem_get_index(helem)); + melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id); + if (!melem) { + simple = calloc(1, sizeof(*simple)); + if (!simple) { + snd_mixer_selem_id_free(id); + return -ENOMEM; + } + simple->selem.id = id; + simple->selem.ops = &simple_none_ops; + err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE, + get_compare_weight(snd_mixer_selem_id_get_name(simple->selem.id), snd_mixer_selem_id_get_index(simple->selem.id)), + simple, selem_free); + if (err < 0) { + snd_mixer_selem_id_free(id); + free(simple); + return err; + } + new = 1; + } else { + simple = snd_mixer_elem_get_private(melem); + snd_mixer_selem_id_free(id); + } + if (simple->ctls[type].elem) { + SNDERR("helem (%s,'%s',%u,%u,%u) appears twice or more", + snd_ctl_elem_iface_name(snd_hctl_elem_get_interface(helem)), + snd_hctl_elem_get_name(helem), + snd_hctl_elem_get_index(helem), + snd_hctl_elem_get_device(helem), + snd_hctl_elem_get_subdevice(helem)); + err = -EINVAL; + goto __error; + } + simple->ctls[type].elem = helem; + simple->ctls[type].type = snd_ctl_elem_info_get_type(info); + simple->ctls[type].inactive = snd_ctl_elem_info_is_inactive(info); + simple->ctls[type].values = values; + if ( (type == CTL_GLOBAL_ENUM) || + (type == CTL_PLAYBACK_ENUM) || + (type == CTL_CAPTURE_ENUM) ) { + simple->ctls[type].min = 0; + simple->ctls[type].max = snd_ctl_elem_info_get_items(info); + } else { + if (ctype == SND_CTL_ELEM_TYPE_INTEGER) { + simple->ctls[type].min = snd_ctl_elem_info_get_min(info); + simple->ctls[type].max = snd_ctl_elem_info_get_max(info); + } + } + switch (type) { + case CTL_CAPTURE_SOURCE: + simple->capture_item = value; + break; + default: + break; + } + err = snd_mixer_elem_attach(melem, helem); + if (err < 0) + goto __error; + err = simple_update(melem); + if (err < 0) { + if (new) + goto __error; + return err; + } + if (new) + err = snd_mixer_elem_add(melem, class); + else + err = snd_mixer_elem_info(melem); + if (err < 0) + return err; + err = selem_read(melem); + if (err < 0) + return err; + if (err) + err = snd_mixer_elem_value(melem); + return err; + __error: + if (new) + snd_mixer_elem_free(melem); + return -EINVAL; +} + +static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) +{ + const char *name = snd_hctl_elem_get_name(helem); + size_t len; + selem_ctl_type_t type = CTL_SINGLE; /* to shut up warning */ + if (snd_hctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER) + return 0; + if (strcmp(name, "Capture Source") == 0) { + snd_ctl_elem_info_t *info; + unsigned int k, items; + int err; + snd_ctl_elem_info_alloca(&info); + err = snd_hctl_elem_info(helem, info); + assert(err >= 0); + if (snd_ctl_elem_info_get_type(info) != SND_CTL_ELEM_TYPE_ENUMERATED) + return 0; + items = snd_ctl_elem_info_get_items(info); + for (k = 0; k < items; ++k) { + const char *n; + snd_ctl_elem_info_set_item(info, k); + err = snd_hctl_elem_info(helem, info); + if (err < 0) + return err; + n = snd_ctl_elem_info_get_item_name(info); + err = simple_add1(class, n, helem, CTL_CAPTURE_SOURCE, k); + if (err < 0) + return err; + } + return 0; + } + len = base_len(name, &type); + if (len == 0) { + return simple_add1(class, name, helem, CTL_SINGLE, 0); + } else { + char ename[128]; + if (len >= sizeof(ename)) + len = sizeof(ename) - 1; + memcpy(ename, name, len); + ename[len] = 0; + /* exception: Capture Volume and Capture Switch */ + if (type == CTL_GLOBAL_VOLUME && !strcmp(ename, "Capture")) + type = CTL_CAPTURE_VOLUME; + else if (type == CTL_GLOBAL_SWITCH && !strcmp(ename, "Capture")) + type = CTL_CAPTURE_SWITCH; + return simple_add1(class, ename, helem, type, 0); + } +} + +static int simple_event_remove(snd_hctl_elem_t *helem, + snd_mixer_elem_t *melem) +{ + selem_none_t *simple = snd_mixer_elem_get_private(melem); + int err; + int k; + for (k = 0; k <= CTL_LAST; k++) { + if (simple->ctls[k].elem == helem) + break; + } + assert(k <= CTL_LAST); + simple->ctls[k].elem = NULL; + err = snd_mixer_elem_detach(melem, helem); + if (err < 0) + return err; + if (snd_mixer_elem_empty(melem)) + return snd_mixer_elem_remove(melem); + err = simple_update(melem); + return snd_mixer_elem_info(melem); +} + +static int simple_event(snd_mixer_class_t *class, unsigned int mask, + snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) +{ + int err; + if (mask == SND_CTL_EVENT_MASK_REMOVE) + return simple_event_remove(helem, melem); + if (mask & SND_CTL_EVENT_MASK_ADD) { + err = simple_event_add(class, helem); + if (err < 0) + return err; + } + if (mask & SND_CTL_EVENT_MASK_INFO) { + err = simple_event_remove(helem, melem); + if (err < 0) + return err; + err = simple_event_add(class, helem); + if (err < 0) + return err; + return 0; + } + if (mask & SND_CTL_EVENT_MASK_VALUE) { + err = selem_read(melem); + if (err < 0) + return err; + if (err) { + err = snd_mixer_elem_value(melem); + if (err < 0) + return err; + } + } + return 0; +} + +/** + * \brief Register mixer simple element class - none abstraction + * \param mixer Mixer handle + * \param options Options container + * \param classp Pointer to returned mixer simple element class handle (or NULL) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_simple_none_register(snd_mixer_t *mixer, + struct snd_mixer_selem_regopt *options ATTRIBUTE_UNUSED, + snd_mixer_class_t **classp) +{ + snd_mixer_class_t *class; + int err; + + if (snd_mixer_class_malloc(&class)) + return -ENOMEM; + snd_mixer_class_set_event(class, simple_event); + snd_mixer_class_set_compare(class, snd_mixer_selem_compare); + err = snd_mixer_class_register(class, mixer); + if (err < 0) { + free(class); + return err; + } + if (classp) + *classp = class; + return 0; +} diff --git a/src/names.c b/src/names.c new file mode 100644 index 0000000..e7a6887 --- /dev/null +++ b/src/names.c @@ -0,0 +1,65 @@ +/** + * \file names.c + * \ingroup Configuration + * \brief Configuration helper functions - device names + * \author Jaroslav Kysela + * \date 2005 + * + * Provide a list of device names for applications. + * + * See the \ref conf page for more details. + */ +/* + * Configuration helper functions - device names + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "local.h" + +/** + * \brief Give a list of device names and associated comments for selected interface + * \param iface a string identifying interface ("pcm", "ctl", "seq", "rawmidi") + * \param list result - a pointer to list + * \return A non-negative value if successful, otherwise a negative error code. + * \deprecated Since 1.0.14 + * + * The global configuration files are specified in the environment variable + * \c ALSA_NAMES_FILE. + */ +int snd_names_list(const char *iface ATTRIBUTE_UNUSED, + snd_devname_t **list ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} +link_warning(snd_names_list, "Warning: snd_names_list is deprecated, use snd_device_name_hint"); + +/** + * \brief Release the list of device names + * \param list the name list to release + * \deprecated Since 1.0.14 + * + * Releases the list of device names allocated via #snd_names_list(). + */ +void snd_names_list_free(snd_devname_t *list ATTRIBUTE_UNUSED) +{ +} +link_warning(snd_names_list_free, "Warning: snd_names_list_free is deprecated, use snd_device_name_free_hint"); diff --git a/src/output.c b/src/output.c new file mode 100644 index 0000000..adc461a --- /dev/null +++ b/src/output.c @@ -0,0 +1,380 @@ +/** + * \file output.c + * \brief Generic stdio-like output interface + * \author Abramo Bagnara + * \date 2000 + * + * Generic stdio-like output interface + */ +/* + * Output object + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "local.h" + +#ifndef DOC_HIDDEN +typedef struct _snd_output_ops { + int (*close)(snd_output_t *output); + int (*print)(snd_output_t *output, const char *format, va_list args); + int (*puts)(snd_output_t *output, const char *str); + int (*putch)(snd_output_t *output, int c); + int (*flush)(snd_output_t *output); +} snd_output_ops_t; + +struct _snd_output { + snd_output_type_t type; + const snd_output_ops_t *ops; + void *private_data; +}; +#endif + +/** + * \brief Closes an output handle. + * \param output The output handle to be closed. + * \return Zero if successful, otherwise a negative error code. + */ +int snd_output_close(snd_output_t *output) +{ + int err = output->ops->close(output); + free(output); + return err; +} + +/** + * \brief Writes formatted output (like \c fprintf(3)) to an output handle. + * \param output The output handle. + * \param format Format string in \c fprintf format. + * \param ... Other \c fprintf arguments. + * \return The number of characters written, or a negative error code. + */ +int snd_output_printf(snd_output_t *output, const char *format, ...) +{ + int result; + va_list args; + va_start(args, format); + result = output->ops->print(output, format, args); + va_end(args); + return result; +} + +/** + * \brief Writes formatted output (like \c fprintf(3)) to an output handle. + * \param output The output handle. + * \param format Format string in \c fprintf format. + * \param args Other \c fprintf arguments. + * \return The number of characters written, or a negative error code. + */ +int snd_output_vprintf(snd_output_t *output, const char *format, va_list args) +{ + return output->ops->print(output, format, args); +} + +/** + * \brief Writes a string to an output handle (like \c fputs(3)). + * \param output The output handle. + * \param str Pointer to the string. + * \return Zero if successful, otherwise a negative error code or \c EOF. + */ +int snd_output_puts(snd_output_t *output, const char *str) +{ + return output->ops->puts(output, str); +} + +/** + * \brief Writes a character to an output handle (like \c putc(3)). + * \param output The output handle. + * \param c The character. + * \return Zero if successful, otherwise a negative error code or \c EOF. + */ +int snd_output_putc(snd_output_t *output, int c) +{ + return output->ops->putch(output, c); +} + +/** + * \brief Flushes an output handle (like fflush(3)). + * \param output The output handle. + * \return Zero if successful, otherwise \c EOF. + * + * If the underlying destination is a stdio stream, this function calls + * \c fflush. If the underlying destination is a memory buffer, the write + * position is reset to the beginning of the buffer. \c =:-o + */ +int snd_output_flush(snd_output_t *output) +{ + return output->ops->flush(output); +} + +#ifndef DOC_HIDDEN +typedef struct _snd_output_stdio { + int close; + FILE *fp; +} snd_output_stdio_t; + +static int snd_output_stdio_close(snd_output_t *output) +{ + snd_output_stdio_t *stdio = output->private_data; + if (stdio->close) + fclose(stdio->fp); + free(stdio); + return 0; +} + +static int snd_output_stdio_print(snd_output_t *output, const char *format, va_list args) +{ + snd_output_stdio_t *stdio = output->private_data; + return vfprintf(stdio->fp, format, args); +} + +static int snd_output_stdio_puts(snd_output_t *output, const char *str) +{ + snd_output_stdio_t *stdio = output->private_data; + return fputs(str, stdio->fp); +} + +static int snd_output_stdio_putc(snd_output_t *output, int c) +{ + snd_output_stdio_t *stdio = output->private_data; + return putc(c, stdio->fp); +} + +static int snd_output_stdio_flush(snd_output_t *output) +{ + snd_output_stdio_t *stdio = output->private_data; + return fflush(stdio->fp); +} + +static const snd_output_ops_t snd_output_stdio_ops = { + .close = snd_output_stdio_close, + .print = snd_output_stdio_print, + .puts = snd_output_stdio_puts, + .putch = snd_output_stdio_putc, + .flush = snd_output_stdio_flush, +}; + +#endif + +/** + * \brief Creates a new output object using an existing stdio \c FILE pointer. + * \param outputp The function puts the pointer to the new output object + * at the address specified by \p outputp. + * \param fp The \c FILE pointer to write to. Characters are written + * to the file starting at the current file position. + * \param _close Close flag. Set this to 1 if #snd_output_close should close + * \p fp by calling \c fclose. + * \return Zero if successful, otherwise a negative error code. + */ +int snd_output_stdio_attach(snd_output_t **outputp, FILE *fp, int _close) +{ + snd_output_t *output; + snd_output_stdio_t *stdio; + assert(outputp && fp); + stdio = calloc(1, sizeof(*stdio)); + if (!stdio) + return -ENOMEM; + output = calloc(1, sizeof(*output)); + if (!output) { + free(stdio); + return -ENOMEM; + } + stdio->fp = fp; + stdio->close = _close; + output->type = SND_OUTPUT_STDIO; + output->ops = &snd_output_stdio_ops; + output->private_data = stdio; + *outputp = output; + return 0; +} + +/** + * \brief Creates a new output object writing to a file. + * \param outputp The function puts the pointer to the new output object + * at the address specified by \p outputp. + * \param file The name of the file to open. + * \param mode The open mode, like \c fopen(3). + * \return Zero if successful, otherwise a negative error code. + */ +int snd_output_stdio_open(snd_output_t **outputp, const char *file, const char *mode) +{ + int err; + FILE *fp = fopen(file, mode); + if (!fp) { + //SYSERR("fopen"); + return -errno; + } + err = snd_output_stdio_attach(outputp, fp, 1); + if (err < 0) + fclose(fp); + return err; +} + +#ifndef DOC_HIDDEN + +typedef struct _snd_output_buffer { + unsigned char *buf; + size_t alloc; + size_t size; +} snd_output_buffer_t; + +static int snd_output_buffer_close(snd_output_t *output) +{ + snd_output_buffer_t *buffer = output->private_data; + free(buffer->buf); + free(buffer); + return 0; +} + +static int snd_output_buffer_need(snd_output_t *output, size_t size) +{ + snd_output_buffer_t *buffer = output->private_data; + size_t _free = buffer->alloc - buffer->size; + size_t alloc; + unsigned char *buf; + + if (_free >= size) + return _free; + if (buffer->alloc == 0) + alloc = 256; + else + alloc = buffer->alloc; + while (alloc < buffer->size + size) + alloc *= 2; + buf = realloc(buffer->buf, alloc); + if (!buf) + return -ENOMEM; + buffer->buf = buf; + buffer->alloc = alloc; + return buffer->alloc - buffer->size; +} + +static int snd_output_buffer_print(snd_output_t *output, const char *format, va_list args) +{ + snd_output_buffer_t *buffer = output->private_data; + size_t size = 256; + int result; + result = snd_output_buffer_need(output, size); + if (result < 0) + return result; + result = vsnprintf((char *)buffer->buf + buffer->size, size, format, args); + assert(result >= 0); + if ((size_t)result <= size) { + buffer->size += result; + return result; + } + size = result; + result = snd_output_buffer_need(output, size); + if (result < 0) + return result; + result = vsnprintf((char *)buffer->buf + buffer->size, result, format, args); + assert(result == (int)size); + buffer->size += result; + return result; +} + +static int snd_output_buffer_puts(snd_output_t *output, const char *str) +{ + snd_output_buffer_t *buffer = output->private_data; + size_t size = strlen(str); + int err; + err = snd_output_buffer_need(output, size); + if (err < 0) + return err; + memcpy(buffer->buf + buffer->size, str, size); + buffer->size += size; + return size; +} + +static int snd_output_buffer_putc(snd_output_t *output, int c) +{ + snd_output_buffer_t *buffer = output->private_data; + int err; + err = snd_output_buffer_need(output, 1); + if (err < 0) + return err; + buffer->buf[buffer->size++] = c; + return 0; +} + +static int snd_output_buffer_flush(snd_output_t *output ATTRIBUTE_UNUSED) +{ + snd_output_buffer_t *buffer = output->private_data; + buffer->size = 0; + return 0; +} + +static const snd_output_ops_t snd_output_buffer_ops = { + .close = snd_output_buffer_close, + .print = snd_output_buffer_print, + .puts = snd_output_buffer_puts, + .putch = snd_output_buffer_putc, + .flush = snd_output_buffer_flush, +}; +#endif + +/** + * \brief Returns the address of the buffer of a #SND_OUTPUT_BUFFER output handle. + * \param output The output handle. + * \param buf The functions puts the current address of the buffer at the + * address specified by \p buf. + * \return The current size of valid data in the buffer. + * + * The address of the buffer may become invalid when output functions or + * #snd_output_close are called. + */ +size_t snd_output_buffer_string(snd_output_t *output, char **buf) +{ + snd_output_buffer_t *buffer = output->private_data; + *buf = (char *)buffer->buf; + return buffer->size; +} + +/** + * \brief Creates a new output object with an auto-extending memory buffer. + * \param outputp The function puts the pointer to the new output object + * at the address specified by \p outputp. + * \return Zero if successful, otherwise a negative error code. + */ +int snd_output_buffer_open(snd_output_t **outputp) +{ + snd_output_t *output; + snd_output_buffer_t *buffer; + assert(outputp); + buffer = calloc(1, sizeof(*buffer)); + if (!buffer) + return -ENOMEM; + output = calloc(1, sizeof(*output)); + if (!output) { + free(buffer); + return -ENOMEM; + } + buffer->buf = NULL; + buffer->alloc = 0; + buffer->size = 0; + output->type = SND_OUTPUT_BUFFER; + output->ops = &snd_output_buffer_ops; + output->private_data = buffer; + *outputp = output; + return 0; +} + diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am new file mode 100644 index 0000000..28faa54 --- /dev/null +++ b/src/pcm/Makefile.am @@ -0,0 +1,117 @@ +SUBDIRS = +DIST_SUBDIRS = scopes + +EXTRA_LTLIBRARIES = libpcm.la + +libpcm_la_SOURCES = atomic.c mask.c interval.c \ + pcm.c pcm_params.c pcm_simple.c \ + pcm_hw.c pcm_misc.c pcm_mmap.c pcm_symbols.c + +if BUILD_PCM_PLUGIN +libpcm_la_SOURCES += pcm_generic.c pcm_plugin.c +endif +if BUILD_PCM_PLUGIN_COPY +libpcm_la_SOURCES += pcm_copy.c +endif +if BUILD_PCM_PLUGIN_LINEAR +libpcm_la_SOURCES += pcm_linear.c +endif +if BUILD_PCM_PLUGIN_ROUTE +libpcm_la_SOURCES += pcm_route.c +endif +if BUILD_PCM_PLUGIN_MULAW +libpcm_la_SOURCES += pcm_mulaw.c +endif +if BUILD_PCM_PLUGIN_ALAW +libpcm_la_SOURCES += pcm_alaw.c +endif +if BUILD_PCM_PLUGIN_ADPCM +libpcm_la_SOURCES += pcm_adpcm.c +endif +if BUILD_PCM_PLUGIN_RATE +libpcm_la_SOURCES += pcm_rate.c pcm_rate_linear.c +endif +if BUILD_PCM_PLUGIN_PLUG +libpcm_la_SOURCES += pcm_plug.c +endif +if BUILD_PCM_PLUGIN_MULTI +libpcm_la_SOURCES += pcm_multi.c +endif +if BUILD_PCM_PLUGIN_SHM +libpcm_la_SOURCES += pcm_shm.c +endif +if BUILD_PCM_PLUGIN_FILE +libpcm_la_SOURCES += pcm_file.c +endif +if BUILD_PCM_PLUGIN_NULL +libpcm_la_SOURCES += pcm_null.c +endif +if BUILD_PCM_PLUGIN_EMPTY +libpcm_la_SOURCES += pcm_empty.c +endif +if BUILD_PCM_PLUGIN_SHARE +libpcm_la_SOURCES += pcm_share.c +endif +if BUILD_PCM_PLUGIN_METER +libpcm_la_SOURCES += pcm_meter.c +endif +if BUILD_PCM_PLUGIN_HOOKS +libpcm_la_SOURCES += pcm_hooks.c +endif +if BUILD_PCM_PLUGIN_LFLOAT +libpcm_la_SOURCES += pcm_lfloat.c +endif +if BUILD_PCM_PLUGIN_LADSPA +libpcm_la_SOURCES += pcm_ladspa.c +endif +if BUILD_PCM_PLUGIN_DMIX +libpcm_la_SOURCES += pcm_dmix.c +endif +if BUILD_PCM_PLUGIN_DSHARE +libpcm_la_SOURCES += pcm_dshare.c +endif +if BUILD_PCM_PLUGIN_DSNOOP +libpcm_la_SOURCES += pcm_dsnoop.c +endif +if BUILD_PCM_PLUGIN_DMIX +libpcm_la_SOURCES += pcm_direct.c +else +if BUILD_PCM_PLUGIN_DSHARE +libpcm_la_SOURCES += pcm_direct.c +else +if BUILD_PCM_PLUGIN_DSNOOP +libpcm_la_SOURCES += pcm_direct.c +endif +endif +endif +if BUILD_PCM_PLUGIN_ASYM +libpcm_la_SOURCES += pcm_asym.c +endif +if BUILD_PCM_PLUGIN_IEC958 +libpcm_la_SOURCES += pcm_iec958.c +endif +if BUILD_PCM_PLUGIN_SOFTVOL +libpcm_la_SOURCES += pcm_softvol.c +endif +if BUILD_PCM_PLUGIN_EXTPLUG +libpcm_la_SOURCES += pcm_extplug.c +endif +if BUILD_PCM_PLUGIN_IOPLUG +libpcm_la_SOURCES += pcm_ioplug.c +endif +if BUILD_PCM_PLUGIN_MMAP_EMUL +libpcm_la_SOURCES += pcm_mmap_emul.c +endif + +EXTRA_DIST = pcm_dmix_i386.c pcm_dmix_x86_64.c pcm_dmix_generic.c + +noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \ + interval.h interval_inline.h plugin_ops.h ladspa.h \ + pcm_direct.h pcm_dmix_i386.h pcm_dmix_x86_64.h \ + pcm_generic.h pcm_ext_parm.h + +alsadir = $(datadir)/alsa + +all: libpcm.la + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/pcm/Makefile.in b/src/pcm/Makefile.in new file mode 100644 index 0000000..3118c5b --- /dev/null +++ b/src/pcm/Makefile.in @@ -0,0 +1,786 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_PCM_PLUGIN_TRUE@am__append_1 = pcm_generic.c pcm_plugin.c +@BUILD_PCM_PLUGIN_COPY_TRUE@am__append_2 = pcm_copy.c +@BUILD_PCM_PLUGIN_LINEAR_TRUE@am__append_3 = pcm_linear.c +@BUILD_PCM_PLUGIN_ROUTE_TRUE@am__append_4 = pcm_route.c +@BUILD_PCM_PLUGIN_MULAW_TRUE@am__append_5 = pcm_mulaw.c +@BUILD_PCM_PLUGIN_ALAW_TRUE@am__append_6 = pcm_alaw.c +@BUILD_PCM_PLUGIN_ADPCM_TRUE@am__append_7 = pcm_adpcm.c +@BUILD_PCM_PLUGIN_RATE_TRUE@am__append_8 = pcm_rate.c pcm_rate_linear.c +@BUILD_PCM_PLUGIN_PLUG_TRUE@am__append_9 = pcm_plug.c +@BUILD_PCM_PLUGIN_MULTI_TRUE@am__append_10 = pcm_multi.c +@BUILD_PCM_PLUGIN_SHM_TRUE@am__append_11 = pcm_shm.c +@BUILD_PCM_PLUGIN_FILE_TRUE@am__append_12 = pcm_file.c +@BUILD_PCM_PLUGIN_NULL_TRUE@am__append_13 = pcm_null.c +@BUILD_PCM_PLUGIN_EMPTY_TRUE@am__append_14 = pcm_empty.c +@BUILD_PCM_PLUGIN_SHARE_TRUE@am__append_15 = pcm_share.c +@BUILD_PCM_PLUGIN_METER_TRUE@am__append_16 = pcm_meter.c +@BUILD_PCM_PLUGIN_HOOKS_TRUE@am__append_17 = pcm_hooks.c +@BUILD_PCM_PLUGIN_LFLOAT_TRUE@am__append_18 = pcm_lfloat.c +@BUILD_PCM_PLUGIN_LADSPA_TRUE@am__append_19 = pcm_ladspa.c +@BUILD_PCM_PLUGIN_DMIX_TRUE@am__append_20 = pcm_dmix.c +@BUILD_PCM_PLUGIN_DSHARE_TRUE@am__append_21 = pcm_dshare.c +@BUILD_PCM_PLUGIN_DSNOOP_TRUE@am__append_22 = pcm_dsnoop.c +@BUILD_PCM_PLUGIN_DMIX_TRUE@am__append_23 = pcm_direct.c +@BUILD_PCM_PLUGIN_DMIX_FALSE@@BUILD_PCM_PLUGIN_DSHARE_TRUE@am__append_24 = pcm_direct.c +@BUILD_PCM_PLUGIN_DMIX_FALSE@@BUILD_PCM_PLUGIN_DSHARE_FALSE@@BUILD_PCM_PLUGIN_DSNOOP_TRUE@am__append_25 = pcm_direct.c +@BUILD_PCM_PLUGIN_ASYM_TRUE@am__append_26 = pcm_asym.c +@BUILD_PCM_PLUGIN_IEC958_TRUE@am__append_27 = pcm_iec958.c +@BUILD_PCM_PLUGIN_SOFTVOL_TRUE@am__append_28 = pcm_softvol.c +@BUILD_PCM_PLUGIN_EXTPLUG_TRUE@am__append_29 = pcm_extplug.c +@BUILD_PCM_PLUGIN_IOPLUG_TRUE@am__append_30 = pcm_ioplug.c +@BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE@am__append_31 = pcm_mmap_emul.c +subdir = src/pcm +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libpcm_la_LIBADD = +am__libpcm_la_SOURCES_DIST = atomic.c mask.c interval.c pcm.c \ + pcm_params.c pcm_simple.c pcm_hw.c pcm_misc.c pcm_mmap.c \ + pcm_symbols.c pcm_generic.c pcm_plugin.c pcm_copy.c \ + pcm_linear.c pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \ + pcm_rate.c pcm_rate_linear.c pcm_plug.c pcm_multi.c pcm_shm.c \ + pcm_file.c pcm_null.c pcm_empty.c pcm_share.c pcm_meter.c \ + pcm_hooks.c pcm_lfloat.c pcm_ladspa.c pcm_dmix.c pcm_dshare.c \ + pcm_dsnoop.c pcm_direct.c pcm_asym.c pcm_iec958.c \ + pcm_softvol.c pcm_extplug.c pcm_ioplug.c pcm_mmap_emul.c +@BUILD_PCM_PLUGIN_TRUE@am__objects_1 = pcm_generic.lo pcm_plugin.lo +@BUILD_PCM_PLUGIN_COPY_TRUE@am__objects_2 = pcm_copy.lo +@BUILD_PCM_PLUGIN_LINEAR_TRUE@am__objects_3 = pcm_linear.lo +@BUILD_PCM_PLUGIN_ROUTE_TRUE@am__objects_4 = pcm_route.lo +@BUILD_PCM_PLUGIN_MULAW_TRUE@am__objects_5 = pcm_mulaw.lo +@BUILD_PCM_PLUGIN_ALAW_TRUE@am__objects_6 = pcm_alaw.lo +@BUILD_PCM_PLUGIN_ADPCM_TRUE@am__objects_7 = pcm_adpcm.lo +@BUILD_PCM_PLUGIN_RATE_TRUE@am__objects_8 = pcm_rate.lo \ +@BUILD_PCM_PLUGIN_RATE_TRUE@ pcm_rate_linear.lo +@BUILD_PCM_PLUGIN_PLUG_TRUE@am__objects_9 = pcm_plug.lo +@BUILD_PCM_PLUGIN_MULTI_TRUE@am__objects_10 = pcm_multi.lo +@BUILD_PCM_PLUGIN_SHM_TRUE@am__objects_11 = pcm_shm.lo +@BUILD_PCM_PLUGIN_FILE_TRUE@am__objects_12 = pcm_file.lo +@BUILD_PCM_PLUGIN_NULL_TRUE@am__objects_13 = pcm_null.lo +@BUILD_PCM_PLUGIN_EMPTY_TRUE@am__objects_14 = pcm_empty.lo +@BUILD_PCM_PLUGIN_SHARE_TRUE@am__objects_15 = pcm_share.lo +@BUILD_PCM_PLUGIN_METER_TRUE@am__objects_16 = pcm_meter.lo +@BUILD_PCM_PLUGIN_HOOKS_TRUE@am__objects_17 = pcm_hooks.lo +@BUILD_PCM_PLUGIN_LFLOAT_TRUE@am__objects_18 = pcm_lfloat.lo +@BUILD_PCM_PLUGIN_LADSPA_TRUE@am__objects_19 = pcm_ladspa.lo +@BUILD_PCM_PLUGIN_DMIX_TRUE@am__objects_20 = pcm_dmix.lo +@BUILD_PCM_PLUGIN_DSHARE_TRUE@am__objects_21 = pcm_dshare.lo +@BUILD_PCM_PLUGIN_DSNOOP_TRUE@am__objects_22 = pcm_dsnoop.lo +@BUILD_PCM_PLUGIN_DMIX_TRUE@am__objects_23 = pcm_direct.lo +@BUILD_PCM_PLUGIN_DMIX_FALSE@@BUILD_PCM_PLUGIN_DSHARE_TRUE@am__objects_24 = pcm_direct.lo +@BUILD_PCM_PLUGIN_DMIX_FALSE@@BUILD_PCM_PLUGIN_DSHARE_FALSE@@BUILD_PCM_PLUGIN_DSNOOP_TRUE@am__objects_25 = pcm_direct.lo +@BUILD_PCM_PLUGIN_ASYM_TRUE@am__objects_26 = pcm_asym.lo +@BUILD_PCM_PLUGIN_IEC958_TRUE@am__objects_27 = pcm_iec958.lo +@BUILD_PCM_PLUGIN_SOFTVOL_TRUE@am__objects_28 = pcm_softvol.lo +@BUILD_PCM_PLUGIN_EXTPLUG_TRUE@am__objects_29 = pcm_extplug.lo +@BUILD_PCM_PLUGIN_IOPLUG_TRUE@am__objects_30 = pcm_ioplug.lo +@BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE@am__objects_31 = pcm_mmap_emul.lo +am_libpcm_la_OBJECTS = atomic.lo mask.lo interval.lo pcm.lo \ + pcm_params.lo pcm_simple.lo pcm_hw.lo pcm_misc.lo pcm_mmap.lo \ + pcm_symbols.lo $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) $(am__objects_8) \ + $(am__objects_9) $(am__objects_10) $(am__objects_11) \ + $(am__objects_12) $(am__objects_13) $(am__objects_14) \ + $(am__objects_15) $(am__objects_16) $(am__objects_17) \ + $(am__objects_18) $(am__objects_19) $(am__objects_20) \ + $(am__objects_21) $(am__objects_22) $(am__objects_23) \ + $(am__objects_24) $(am__objects_25) $(am__objects_26) \ + $(am__objects_27) $(am__objects_28) $(am__objects_29) \ + $(am__objects_30) $(am__objects_31) +libpcm_la_OBJECTS = $(am_libpcm_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libpcm_la_SOURCES) +DIST_SOURCES = $(am__libpcm_la_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +HEADERS = $(noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = +DIST_SUBDIRS = scopes +EXTRA_LTLIBRARIES = libpcm.la +libpcm_la_SOURCES = atomic.c mask.c interval.c pcm.c pcm_params.c \ + pcm_simple.c pcm_hw.c pcm_misc.c pcm_mmap.c pcm_symbols.c \ + $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) $(am__append_6) \ + $(am__append_7) $(am__append_8) $(am__append_9) \ + $(am__append_10) $(am__append_11) $(am__append_12) \ + $(am__append_13) $(am__append_14) $(am__append_15) \ + $(am__append_16) $(am__append_17) $(am__append_18) \ + $(am__append_19) $(am__append_20) $(am__append_21) \ + $(am__append_22) $(am__append_23) $(am__append_24) \ + $(am__append_25) $(am__append_26) $(am__append_27) \ + $(am__append_28) $(am__append_29) $(am__append_30) \ + $(am__append_31) +EXTRA_DIST = pcm_dmix_i386.c pcm_dmix_x86_64.c pcm_dmix_generic.c +noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \ + interval.h interval_inline.h plugin_ops.h ladspa.h \ + pcm_direct.h pcm_dmix_i386.h pcm_dmix_x86_64.h \ + pcm_generic.h pcm_ext_parm.h + +alsadir = $(datadir)/alsa +INCLUDES = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/pcm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/pcm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libpcm.la: $(libpcm_la_OBJECTS) $(libpcm_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libpcm_la_OBJECTS) $(libpcm_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interval.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mask.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_adpcm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_alaw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_asym.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_copy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_direct.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_dmix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_dshare.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_dsnoop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_empty.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_extplug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_hooks.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_iec958.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_ioplug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_ladspa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_lfloat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_linear.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_meter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_mmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_mmap_emul.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_mulaw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_multi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_null.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_params.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_plug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_rate.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_rate_linear.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_route.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_share.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_shm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_simple.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_softvol.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_symbols.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am + + +all: libpcm.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/pcm/atomic.c b/src/pcm/atomic.c new file mode 100644 index 0000000..7565945 --- /dev/null +++ b/src/pcm/atomic.c @@ -0,0 +1,43 @@ +/* + * Atomic read/write + * Copyright (c) 2001 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "iatomic.h" + +void snd_atomic_read_wait(snd_atomic_read_t *t) +{ + volatile const snd_atomic_write_t *w = t->write; + unsigned int loops = 0; + struct timespec ts; + while (w->begin != w->end) { + if (loops < MAX_SPIN_COUNT) { + sched_yield(); + loops++; + continue; + } + loops = 0; + ts.tv_sec = 0; + ts.tv_nsec = SPIN_SLEEP_DURATION; + nanosleep(&ts, NULL); + } +} + diff --git a/src/pcm/interval.c b/src/pcm/interval.c new file mode 100644 index 0000000..6e39808 --- /dev/null +++ b/src/pcm/interval.c @@ -0,0 +1,441 @@ +/* + * Interval functions + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define SND_INTERVAL_C +#define SND_INTERVAL_INLINE + +#include +#include +#include "pcm_local.h" + +static inline void div64_32(u_int64_t *n, u_int32_t d, u_int32_t *rem) +{ + *rem = *n % d; + *n /= d; +} + +static inline unsigned int div32(unsigned int a, unsigned int b, + unsigned int *r) +{ + if (b == 0) { + *r = 0; + return UINT_MAX; + } + *r = a % b; + return a / b; +} + +static inline unsigned int div_down(unsigned int a, unsigned int b) +{ + if (b == 0) + return UINT_MAX; + return a / b; +} + +static inline unsigned int div_up(unsigned int a, unsigned int b) +{ + unsigned int r; + unsigned int q; + if (b == 0) + return UINT_MAX; + q = div32(a, b, &r); + if (r) + ++q; + return q; +} + +static inline unsigned int mul(unsigned int a, unsigned int b) +{ + if (a == 0) + return 0; + if (div_down(UINT_MAX, a) < b) + return UINT_MAX; + return a * b; +} + +static inline unsigned int add(unsigned int a, unsigned int b) +{ + if (a >= UINT_MAX - b) + return UINT_MAX; + return a + b; +} + +static inline unsigned int sub(unsigned int a, unsigned int b) +{ + if (a > b) + return a - b; + return 0; +} + +static inline unsigned int muldiv32(unsigned int a, unsigned int b, + unsigned int c, unsigned int *r) +{ + u_int64_t n = (u_int64_t) a * b; + if (c == 0) { + assert(n > 0); + *r = 0; + return UINT_MAX; + } + div64_32(&n, c, r); + if (n >= UINT_MAX) { + *r = 0; + return UINT_MAX; + } + return n; +} + +int snd_interval_refine_min(snd_interval_t *i, unsigned int min, int openmin) +{ + int changed = 0; + if (snd_interval_empty(i)) + return -ENOENT; + if (i->min < min) { + i->min = min; + i->openmin = openmin; + changed = 1; + } else if (i->min == min && !i->openmin && openmin) { + i->openmin = 1; + changed = 1; + } + if (i->integer) { + if (i->openmin) { + i->min++; + i->openmin = 0; + } + } + if (snd_interval_checkempty(i)) { + snd_interval_none(i); + return -EINVAL; + } + return changed; +} + +int snd_interval_refine_max(snd_interval_t *i, unsigned int max, int openmax) +{ + int changed = 0; + if (snd_interval_empty(i)) + return -ENOENT; + if (i->max > max) { + i->max = max; + i->openmax = openmax; + changed = 1; + } else if (i->max == max && !i->openmax && openmax) { + i->openmax = 1; + changed = 1; + } + if (i->integer) { + if (i->openmax) { + i->max--; + i->openmax = 0; + } + } + if (snd_interval_checkempty(i)) { + snd_interval_none(i); + return -EINVAL; + } + return changed; +} + +/* r <- v */ +int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v) +{ + int changed = 0; + if (snd_interval_empty(i)) + return -ENOENT; + if (i->min < v->min) { + i->min = v->min; + i->openmin = v->openmin; + changed = 1; + } else if (i->min == v->min && !i->openmin && v->openmin) { + i->openmin = 1; + changed = 1; + } + if (i->max > v->max) { + i->max = v->max; + i->openmax = v->openmax; + changed = 1; + } else if (i->max == v->max && !i->openmax && v->openmax) { + i->openmax = 1; + changed = 1; + } + if (!i->integer && v->integer) { + i->integer = 1; + changed = 1; + } + if (i->integer) { + if (i->openmin) { + i->min++; + i->openmin = 0; + } + if (i->openmax) { + i->max--; + i->openmax = 0; + } + } else if (!i->openmin && !i->openmax && i->min == i->max) + i->integer = 1; + if (snd_interval_checkempty(i)) { + snd_interval_none(i); + return -EINVAL; + } + return changed; +} + +int snd_interval_refine_first(snd_interval_t *i) +{ + if (snd_interval_empty(i)) + return -ENOENT; + if (snd_interval_single(i)) + return 0; + i->max = i->min; + i->openmax = i->openmin; + if (i->openmax) + i->max++; + return 1; +} + +int snd_interval_refine_last(snd_interval_t *i) +{ + if (snd_interval_empty(i)) + return -ENOENT; + if (snd_interval_single(i)) + return 0; + i->min = i->max; + i->openmin = i->openmax; + if (i->openmin) + i->min--; + return 1; +} + +int snd_interval_refine_set(snd_interval_t *i, unsigned int val) +{ + snd_interval_t t; + t.empty = 0; + t.min = t.max = val; + t.openmin = t.openmax = 0; + t.integer = 1; + return snd_interval_refine(i, &t); +} + +void snd_interval_add(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c) +{ + if (a->empty || b->empty) { + snd_interval_none(c); + return; + } + c->empty = 0; + c->min = add(a->min, b->min); + c->openmin = (a->openmin || b->openmin); + c->max = add(a->max, b->max); + c->openmax = (a->openmax || b->openmax); + c->integer = (a->integer && b->integer); +} + +void snd_interval_sub(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c) +{ + if (a->empty || b->empty) { + snd_interval_none(c); + return; + } + c->empty = 0; + c->min = sub(a->min, b->max); + c->openmin = (a->openmin || b->openmax); + c->max = add(a->max, b->min); + c->openmax = (a->openmax || b->openmin); + c->integer = (a->integer && b->integer); +} + +void snd_interval_mul(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c) +{ + if (a->empty || b->empty) { + snd_interval_none(c); + return; + } + c->empty = 0; + c->min = mul(a->min, b->min); + c->openmin = (a->openmin || b->openmin); + c->max = mul(a->max, b->max); + c->openmax = (a->openmax || b->openmax); + c->integer = (a->integer && b->integer); +} + +void snd_interval_div(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c) +{ + unsigned int r; + if (a->empty || b->empty) { + snd_interval_none(c); + return; + } + c->empty = 0; + c->min = div32(a->min, b->max, &r); + c->openmin = (r || a->openmin || b->openmax); + if (b->min > 0) { + c->max = div32(a->max, b->min, &r); + if (r) { + c->max++; + c->openmax = 1; + } else + c->openmax = (a->openmax || b->openmin); + } else { + c->max = UINT_MAX; + c->openmax = 0; + } + c->integer = 0; +} + +/* a * b / c */ +void snd_interval_muldiv(const snd_interval_t *a, const snd_interval_t *b, + const snd_interval_t *c, snd_interval_t *d) +{ + unsigned int r; + if (a->empty || b->empty || c->empty) { + snd_interval_none(d); + return; + } + d->empty = 0; + d->min = muldiv32(a->min, b->min, c->max, &r); + d->openmin = (r || a->openmin || b->openmin || c->openmax); + d->max = muldiv32(a->max, b->max, c->min, &r); + if (r) { + d->max++; + d->openmax = 1; + } else + d->openmax = (a->openmax || b->openmax || c->openmin); + d->integer = 0; +} + +/* a * b / k */ +void snd_interval_muldivk(const snd_interval_t *a, const snd_interval_t *b, + unsigned int k, snd_interval_t *c) +{ + unsigned int r; + if (a->empty || b->empty) { + snd_interval_none(c); + return; + } + c->empty = 0; + c->min = muldiv32(a->min, b->min, k, &r); + c->openmin = (r || a->openmin || b->openmin); + c->max = muldiv32(a->max, b->max, k, &r); + if (r) { + c->max++; + c->openmax = 1; + } else + c->openmax = (a->openmax || b->openmax); + c->integer = 0; +} + +/* a * k / b */ +void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k, + const snd_interval_t *b, snd_interval_t *c) +{ + unsigned int r; + if (a->empty || b->empty) { + snd_interval_none(c); + return; + } + c->empty = 0; + c->min = muldiv32(a->min, k, b->max, &r); + c->openmin = (r || a->openmin || b->openmax); + if (b->min > 0) { + c->max = muldiv32(a->max, k, b->min, &r); + if (r) { + c->max++; + c->openmax = 1; + } else + c->openmax = (a->openmax || b->openmin); + } else { + c->max = UINT_MAX; + c->openmax = 0; + } + c->integer = 0; +} + +void snd_interval_print(const snd_interval_t *i, snd_output_t *out) +{ + if (snd_interval_empty(i)) + snd_output_printf(out, "NONE"); + else if (i->min == 0 && i->openmin == 0 && + i->max == UINT_MAX && i->openmax == 0) + snd_output_printf(out, "ALL"); + else if (snd_interval_single(i) && i->integer) + snd_output_printf(out, "%u", snd_interval_value(i)); + else + snd_output_printf(out, "%c%u %u%c", + i->openmin ? '(' : '[', + i->min, i->max, + i->openmax ? ')' : ']'); +} + +#if 0 +static void boundary_abs(int a, int adir, int *b, int *bdir) +{ + if (a < 0 || (a == 0 && adir < 0)) { + *b = -a; + *bdir = -adir; + } else { + *b = a; + *bdir = adir; + } +} +#endif + +void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir) +{ + adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); + bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); + *c = a - b; + *cdir = adir - bdir; + if (*cdir == -2) { + assert(*c > INT_MIN); + (*c)--; + } else if (*cdir == 2) { + assert(*c < INT_MAX); + (*c)++; + } +} + +int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir) +{ + assert(a > 0 || adir >= 0); + assert(b > 0 || bdir >= 0); + if (adir < 0) { + a--; + adir = 1; + } else if (adir > 0) + adir = 1; + if (bdir < 0) { + b--; + bdir = 1; + } else if (bdir > 0) + bdir = 1; + return a < b || (a == b && adir < bdir); +} + +/* Return 1 if min is nearer to best than max */ +int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir) +{ + int dmin, dmindir; + int dmax, dmaxdir; + boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir); + boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); + return boundary_lt(dmin, dmindir, dmax, dmaxdir); +} + diff --git a/src/pcm/interval.h b/src/pcm/interval.h new file mode 100644 index 0000000..330b056 --- /dev/null +++ b/src/pcm/interval.h @@ -0,0 +1,80 @@ +/* + * Interval header + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +typedef struct _snd_interval snd_interval_t; + +#ifdef SND_INTERVAL_INLINE +#include "interval_inline.h" +#else +void snd_interval_any(snd_interval_t *i); +void snd_interval_none(snd_interval_t *i); +int snd_interval_setinteger(snd_interval_t *i); +int snd_interval_empty(const snd_interval_t *i); +int snd_interval_single(const snd_interval_t *i); +int snd_interval_value(const snd_interval_t *i); +void snd_interval_set_value(snd_interval_t *i, unsigned int val); +int snd_interval_min(const snd_interval_t *i); +int snd_interval_max(const snd_interval_t *i); +void snd_interval_set_minmax(snd_interval_t *i, unsigned int min, unsigned int max); +int snd_interval_test(const snd_interval_t *i, unsigned int val); +void snd_interval_copy(snd_interval_t *dst, const snd_interval_t *src); +void snd_interval_floor(snd_interval_t *i); +void snd_interval_unfloor(snd_interval_t *i); +int snd_interval_always_eq(const snd_interval_t *i1, const snd_interval_t *i2); +int snd_interval_never_eq(const snd_interval_t *i1, const snd_interval_t *i2); +#endif + +/* make local functions really local */ +#define snd_interval_add snd1_interval_add +#define snd_interval_sub snd1_interval_sub +#define snd_interval_mul snd1_interval_mul +#define snd_interval_div snd1_interval_div +#define snd_interval_muldiv snd1_interval_muldiv +#define snd_interval_muldivk snd1_interval_muldivk +#define snd_interval_mulkdiv snd1_interval_mulkdiv +#define snd_interval_print snd1_interval_print +#define snd_interval_refine_min snd1_interval_refine_min +#define snd_interval_refine_max snd1_interval_refine_max +#define snd_interval_refine snd1_interval_refine +#define snd_interval_refine_first snd1_interval_refine_first +#define snd_interval_refine_last snd1_interval_refine_last +#define snd_interval_refine_set snd1_interval_refine_set + +void snd_interval_add(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c); +void snd_interval_sub(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c); +void snd_interval_mul(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c); +void snd_interval_div(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c); +void snd_interval_muldiv(const snd_interval_t *a, const snd_interval_t *b, + const snd_interval_t *c, snd_interval_t *d); +void snd_interval_muldivk(const snd_interval_t *a, const snd_interval_t *b, + unsigned int k, snd_interval_t *c); +void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k, + const snd_interval_t *b, snd_interval_t *c); +void snd_interval_print(const snd_interval_t *i, snd_output_t *out); +int snd_interval_refine_min(snd_interval_t *i, unsigned int min, int openmin); +int snd_interval_refine_max(snd_interval_t *i, unsigned int max, int openmax); +int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v); +int snd_interval_refine_first(snd_interval_t *i); +int snd_interval_refine_last(snd_interval_t *i); +int snd_interval_refine_set(snd_interval_t *i, unsigned int val); +void boundary_sub(int a, int adir, int b, int bdir, int *c, int *cdir); +int boundary_lt(unsigned int a, int adir, unsigned int b, int bdir); +int boundary_nearer(int min, int mindir, int best, int bestdir, int max, int maxdir); diff --git a/src/pcm/interval_inline.h b/src/pcm/interval_inline.h new file mode 100644 index 0000000..bf6b784 --- /dev/null +++ b/src/pcm/interval_inline.h @@ -0,0 +1,157 @@ +/* + * Interval inlines + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define INTERVAL_INLINE static inline + +INTERVAL_INLINE void snd_interval_any(snd_interval_t *i) +{ + i->min = 0; + i->openmin = 0; + i->max = UINT_MAX; + i->openmax = 0; + i->integer = 0; + i->empty = 0; +} + +INTERVAL_INLINE void snd_interval_none(snd_interval_t *i) +{ + i->empty = 1; +} + +INTERVAL_INLINE int snd_interval_checkempty(const snd_interval_t *i) +{ + return (i->min > i->max || + (i->min == i->max && (i->openmin || i->openmax))); +} + +INTERVAL_INLINE int snd_interval_empty(const snd_interval_t *i) +{ + return i->empty; +} + +INTERVAL_INLINE int snd_interval_single(const snd_interval_t *i) +{ + assert(!snd_interval_empty(i)); + return (i->min == i->max || + (i->min + 1 == i->max && i->openmax)); +} + +INTERVAL_INLINE int snd_interval_value(const snd_interval_t *i) +{ + assert(snd_interval_single(i)); + return i->min; +} + +INTERVAL_INLINE void snd_interval_set_value(snd_interval_t *i, unsigned int val) +{ + i->openmax = i->openmin = 0; + i->min = i->max = val; + i->integer = 0; + i->empty = 0; +} + +INTERVAL_INLINE int snd_interval_min(const snd_interval_t *i) +{ + assert(!snd_interval_empty(i)); + return i->min; +} + +INTERVAL_INLINE int snd_interval_max(const snd_interval_t *i) +{ + assert(!snd_interval_empty(i)); + return i->max; +} + +INTERVAL_INLINE void snd_interval_set_minmax(snd_interval_t *i, unsigned int min, unsigned int max) +{ + i->openmax = i->openmin = 0; + i->min = min; + i->max = max; + i->integer = 0; + i->empty = 0; +} + +INTERVAL_INLINE int snd_interval_test(const snd_interval_t *i, unsigned int val) +{ + return !((i->min > val || (i->min == val && i->openmin) || + i->max < val || (i->max == val && i->openmax))); +} + +INTERVAL_INLINE void snd_interval_copy(snd_interval_t *d, const snd_interval_t *s) +{ + *d = *s; +} + +INTERVAL_INLINE int snd_interval_setinteger(snd_interval_t *i) +{ + if (i->integer) + return 0; + if (i->openmin && i->openmax && i->min == i->max) + return -EINVAL; + i->integer = 1; + return 1; +} + +INTERVAL_INLINE void snd_interval_floor(snd_interval_t *i) +{ + if (i->integer || snd_interval_empty(i)) + return; + i->openmin = 0; + if (i->openmax) { + i->max--; + i->openmax = 0; + } + i->integer = 1; +} + +INTERVAL_INLINE void snd_interval_unfloor(snd_interval_t *i) +{ + if (snd_interval_empty(i)) + return; + if (i->max == UINT_MAX) + return; + if (i->openmax) + return; + i->max++; + i->openmax = 1; + i->integer = 0; +} + + +INTERVAL_INLINE int snd_interval_always_eq(const snd_interval_t *i1, const snd_interval_t *i2) +{ + return snd_interval_single(i1) && snd_interval_single(i2) && + snd_interval_value(i1) == snd_interval_value(i2); +} + +INTERVAL_INLINE int snd_interval_never_eq(const snd_interval_t *i1, const snd_interval_t *i2) +{ + + return (i1->max < i2->min || + (i1->max == i2->min && + (i1->openmax || i1->openmin)) || + i1->min > i2->max || + (i1->min == i2->max && + (i1->openmin || i2->openmax))); +} + + + diff --git a/src/pcm/ladspa.h b/src/pcm/ladspa.h new file mode 100644 index 0000000..5c30a8a --- /dev/null +++ b/src/pcm/ladspa.h @@ -0,0 +1,603 @@ +/* ladspa.h + + Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. + Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + Stefan Westerfeld. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. */ + +#ifndef LADSPA_INCLUDED +#define LADSPA_INCLUDED + +#define LADSPA_VERSION "1.1" +#define LADSPA_VERSION_MAJOR 1 +#define LADSPA_VERSION_MINOR 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ + +/* Overview: + + There is a large number of synthesis packages in use or development + on the Linux platform at this time. This API (`The Linux Audio + Developer's Simple Plugin API') attempts to give programmers the + ability to write simple `plugin' audio processors in C/C++ and link + them dynamically (`plug') into a range of these packages (`hosts'). + It should be possible for any host and any plugin to communicate + completely through this interface. + + This API is deliberately short and simple. To achieve compatibility + with a range of promising Linux sound synthesis packages it + attempts to find the `greatest common divisor' in their logical + behaviour. Having said this, certain limiting decisions are + implicit, notably the use of a fixed type (LADSPA_Data) for all + data transfer and absence of a parameterised `initialisation' + phase. See below for the LADSPA_Data typedef. + + Plugins are expected to distinguish between control and audio + data. Plugins have `ports' that are inputs or outputs for audio or + control data and each plugin is `run' for a `block' corresponding + to a short time interval measured in samples. Audio data is + communicated using arrays of LADSPA_Data, allowing a block of audio + to be processed by the plugin in a single pass. Control data is + communicated using single LADSPA_Data values. Control data has a + single value at the start of a call to the `run()' or `run_adding()' + function, and may be considered to remain this value for its + duration. The plugin may assume that all its input and output ports + have been connected to the relevant data location (see the + `connect_port()' function below) before it is asked to run. + + Plugins will reside in shared object files suitable for dynamic + linking by dlopen() and family. The file will provide a number of + `plugin types' that can be used to instantiate actual plugins + (sometimes known as `plugin instances') that can be connected + together to perform tasks. + + This API contains very limited error-handling. */ + +/*****************************************************************************/ + +/* Fundamental data type passed in and out of plugin. This data type + is used to communicate audio samples and control values. It is + assumed that the plugin will work sensibly given any numeric input + value although it may have a preferred range (see hints below). + + For audio it is generally assumed that 1.0f is the `0dB' reference + amplitude and is a `normal' signal level. */ + +typedef float LADSPA_Data; + +/*****************************************************************************/ + +/* Special Plugin Properties: + + Optional features of the plugin type are encapsulated in the + LADSPA_Properties type. This is assembled by ORing individual + properties together. */ + +typedef int LADSPA_Properties; + +/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a + real-time dependency (e.g. listens to a MIDI device) and so its + output must not be cached or subject to significant latency. */ +#define LADSPA_PROPERTY_REALTIME 0x1 + +/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin + may cease to work correctly if the host elects to use the same data + location for both input and output (see connect_port()). This + should be avoided as enabling this flag makes it impossible for + hosts to use the plugin to process audio `in-place.' */ +#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 + +/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin + is capable of running not only in a conventional host but also in a + `hard real-time' environment. To qualify for this the plugin must + satisfy all of the following: + + (1) The plugin must not use malloc(), free() or other heap memory + management within its run() or run_adding() functions. All new + memory used in run() must be managed via the stack. These + restrictions only apply to the run() function. + + (2) The plugin will not attempt to make use of any library + functions with the exceptions of functions in the ANSI standard C + and C maths libraries, which the host is expected to provide. + + (3) The plugin will not access files, devices, pipes, sockets, IPC + or any other mechanism that might result in process or thread + blocking. + + (4) The plugin will take an amount of time to execute a run() or + run_adding() call approximately of form (A+B*SampleCount) where A + and B depend on the machine and host in use. This amount of time + may not depend on input signals or plugin state. The host is left + the responsibility to perform timings to estimate upper bounds for + A and B. */ +#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 + +#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) +#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) +#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) + +/*****************************************************************************/ + +/* Plugin Ports: + + Plugins have `ports' that are inputs or outputs for audio or + data. Ports can communicate arrays of LADSPA_Data (for audio + inputs/outputs) or single LADSPA_Data values (for control + input/outputs). This information is encapsulated in the + LADSPA_PortDescriptor type which is assembled by ORing individual + properties together. + + Note that a port must be an input or an output port but not both + and that a port must be a control or audio port but not both. */ + +typedef int LADSPA_PortDescriptor; + +/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ +#define LADSPA_PORT_INPUT 0x1 + +/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ +#define LADSPA_PORT_OUTPUT 0x2 + +/* Property LADSPA_PORT_CONTROL indicates that the port is a control + port. */ +#define LADSPA_PORT_CONTROL 0x4 + +/* Property LADSPA_PORT_AUDIO indicates that the port is a audio + port. */ +#define LADSPA_PORT_AUDIO 0x8 + +#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) +#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) +#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) +#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) + +/*****************************************************************************/ + +/* Plugin Port Range Hints: + + The host may wish to provide a representation of data entering or + leaving a plugin (e.g. to generate a GUI automatically). To make + this more meaningful, the plugin should provide `hints' to the host + describing the usual values taken by the data. + + Note that these are only hints. The host may ignore them and the + plugin must not assume that data supplied to it is meaningful. If + the plugin receives invalid input data it is expected to continue + to run without failure and, where possible, produce a sensible + output (e.g. a high-pass filter given a negative cutoff frequency + might switch to an all-pass mode). + + Hints are meaningful for all input and output ports but hints for + input control ports are expected to be particularly useful. + + More hint information is encapsulated in the + LADSPA_PortRangeHintDescriptor type which is assembled by ORing + individual hint types together. Hints may require further + LowerBound and UpperBound information. + + All the hint information for a particular port is aggregated in the + LADSPA_PortRangeHint structure. */ + +typedef int LADSPA_PortRangeHintDescriptor; + +/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) lower + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of LowerBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_BELOW 0x1 + +/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) upper + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of UpperBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_ABOVE 0x2 + +/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be + considered a Boolean toggle. Data less than or equal to zero should + be considered `off' or `false,' and data above zero should be + considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in + conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or + LADSPA_HINT_DEFAULT_1. */ +#define LADSPA_HINT_TOGGLED 0x4 + +/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified + should be interpreted as multiples of the sample rate. For + instance, a frequency range from 0Hz to the Nyquist frequency (half + the sample rate) could be requested by this hint in conjunction + with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds + at all must support this hint to retain meaning. */ +#define LADSPA_HINT_SAMPLE_RATE 0x8 + +/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the + user will find it more intuitive to view values using a logarithmic + scale. This is particularly useful for frequencies and gains. */ +#define LADSPA_HINT_LOGARITHMIC 0x10 + +/* Hint LADSPA_HINT_INTEGER indicates that a user interface would + probably wish to provide a stepped control taking only integer + values. Any bounds set should be slightly wider than the actual + integer range required to avoid floating point rounding errors. For + instance, the integer set {0,1,2,3} might be described as [-0.1, + 3.1]. */ +#define LADSPA_HINT_INTEGER 0x20 + +/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal' + value for the port that is sensible as a default. For instance, + this value is suitable for use as an initial value in a user + interface or as a value the host might assign to a control port + when the user has not provided one. Defaults are encoded using a + mask so only one default may be specified for a port. Some of the + hints make use of lower and upper bounds, in which case the + relevant bound or bounds must be available and + LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting + default must be rounded if LADSPA_HINT_INTEGER is present. Default + values were introduced in LADSPA v1.1. */ +#define LADSPA_HINT_DEFAULT_MASK 0x3C0 + +/* This default values indicates that no default is provided. */ +#define LADSPA_HINT_DEFAULT_NONE 0x0 + +/* This default hint indicates that the suggested lower bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 + +/* This default hint indicates that a low value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + + log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper + * 0.25). */ +#define LADSPA_HINT_DEFAULT_LOW 0x80 + +/* This default hint indicates that a middle value between the + suggested lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + + log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * + 0.5). */ +#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 + +/* This default hint indicates that a high value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + + log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper + * 0.75). */ +#define LADSPA_HINT_DEFAULT_HIGH 0x100 + +/* This default hint indicates that the suggested upper bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 + +/* This default hint indicates that the number 0 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_0 0x200 + +/* This default hint indicates that the number 1 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_1 0x240 + +/* This default hint indicates that the number 100 should be used. */ +#define LADSPA_HINT_DEFAULT_100 0x280 + +/* This default hint indicates that the Hz frequency of `concert A' + should be used. This will be 440 unless the host uses an unusual + tuning convention, in which case it may be within a few Hz. */ +#define LADSPA_HINT_DEFAULT_440 0x2C0 + +#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) +#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) +#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) +#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) +#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) +#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) + +#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) +#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MINIMUM) +#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_LOW) +#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MIDDLE) +#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_HIGH) +#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MAXIMUM) +#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_0) +#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_1) +#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_100) +#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_440) + +typedef struct _LADSPA_PortRangeHint { + + /* Hints about the port. */ + LADSPA_PortRangeHintDescriptor HintDescriptor; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data LowerBound; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data UpperBound; + +} LADSPA_PortRangeHint; + +/*****************************************************************************/ + +/* Plugin Handles: + + This plugin handle indicates a particular instance of the plugin + concerned. It is valid to compare this to NULL (0 for C++) but + otherwise the host should not attempt to interpret it. The plugin + may use it to reference internal instance data. */ + +typedef void * LADSPA_Handle; + +/*****************************************************************************/ + +/* Descriptor for a Type of Plugin: + + This structure is used to describe a plugin type. It provides a + number of functions to examine the type, instantiate it, link it to + buffers and workspaces and to run it. */ + +typedef struct _LADSPA_Descriptor { + + /* This numeric identifier indicates the plugin type + uniquely. Plugin programmers may reserve ranges of IDs from a + central body to avoid clashes. Hosts may assume that IDs are + below 0x1000000. */ + unsigned long UniqueID; + + /* This identifier can be used as a unique, case-sensitive + identifier for the plugin type within the plugin file. Plugin + types should be identified by file and label rather than by index + or plugin name, which may be changed in new plugin + versions. Labels must not contain white-space characters. */ + const char * Label; + + /* This indicates a number of properties of the plugin. */ + LADSPA_Properties Properties; + + /* This member points to the null-terminated name of the plugin + (e.g. "Sine Oscillator"). */ + const char * Name; + + /* This member points to the null-terminated string indicating the + maker of the plugin. This can be an empty string but not NULL. */ + const char * Maker; + + /* This member points to the null-terminated string indicating any + copyright applying to the plugin. If no Copyright applies the + string "None" should be used. */ + const char * Copyright; + + /* This indicates the number of ports (input AND output) present on + the plugin. */ + unsigned long PortCount; + + /* This member indicates an array of port descriptors. Valid indices + vary from 0 to PortCount-1. */ + const LADSPA_PortDescriptor * PortDescriptors; + + /* This member indicates an array of null-terminated strings + describing ports (e.g. "Frequency (Hz)"). Valid indices vary from + 0 to PortCount-1. */ + const char * const * PortNames; + + /* This member indicates an array of range hints for each port (see + above). Valid indices vary from 0 to PortCount-1. */ + const LADSPA_PortRangeHint * PortRangeHints; + + /* This may be used by the plugin developer to pass any custom + implementation data into an instantiate call. It must not be used + or interpreted by the host. It is expected that most plugin + writers will not use this facility as LADSPA_Handle should be + used to hold instance data. */ + void * ImplementationData; + + /* This member is a function pointer that instantiates a plugin. A + handle is returned indicating the new plugin instance. The + instantiation function accepts a sample rate as a parameter. The + plugin descriptor from which this instantiate function was found + must also be passed. This function must return NULL if + instantiation fails. + + Note that instance initialisation should generally occur in + activate() rather than here. */ + LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, + unsigned long SampleRate); + + /* This member is a function pointer that connects a port on an + instantiated plugin to a memory location at which a block of data + for the port will be read/written. The data location is expected + to be an array of LADSPA_Data for audio ports or a single + LADSPA_Data value for control ports. Memory issues will be + managed by the host. The plugin must read/write the data at these + locations every time run() or run_adding() is called and the data + present at the time of this connection call should not be + considered meaningful. + + connect_port() may be called more than once for a plugin instance + to allow the host to change the buffers that the plugin is + reading or writing. These calls may be made before or after + activate() or deactivate() calls. + + connect_port() must be called at least once for each port before + run() or run_adding() is called. When working with blocks of + LADSPA_Data the plugin should pay careful attention to the block + size passed to the run function as the block allocated may only + just be large enough to contain the block of samples. + + Plugin writers should be aware that the host may elect to use the + same buffer for more than one port and even use the same buffer + for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). + However, overlapped buffers or use of a single buffer for both + audio and control data may result in unexpected behaviour. */ + void (*connect_port)(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation); + + /* This member is a function pointer that initialises a plugin + instance and activates it for use. This is separated from + instantiate() to aid real-time support and so that hosts can + reinitialise a plugin instance by calling deactivate() and then + activate(). In this case the plugin instance must reset all state + information dependent on the history of the plugin instance + except for any data locations provided by connect_port() and any + gain set by set_run_adding_gain(). If there is nothing for + activate() to do then the plugin writer may provide a NULL rather + than an empty function. + + When present, hosts must call this function once before run() (or + run_adding()) is called for the first time. This call should be + made as close to the run() call as possible and indicates to + real-time plugins that they are now live. Plugins should not rely + on a prompt call to run() after activate(). activate() may not be + called again unless deactivate() is called first. Note that + connect_port() may be called before or after a call to + activate(). */ + void (*activate)(LADSPA_Handle Instance); + + /* This method is a function pointer that runs an instance of a + plugin for a block. Two parameters are required: the first is a + handle to the particular instance to be run and the second + indicates the block size (in samples) for which the plugin + instance may run. + + Note that if an activate() function exists then it must be called + before run() or run_adding(). If deactivate() is called for a + plugin instance then the plugin instance may not be reused until + activate() has been called again. + + If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE + then there are various things that the plugin should not do + within the run() or run_adding() functions (see above). */ + void (*run)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that runs an instance of a + plugin for a block. This has identical behaviour to run() except + in the way data is output from the plugin. When run() is used, + values are written directly to the memory areas associated with + the output ports. However when run_adding() is called, values + must be added to the values already present in the memory + areas. Furthermore, output values written must be scaled by the + current gain set by set_run_adding_gain() (see below) before + addition. + + run_adding() is optional. When it is not provided by a plugin, + this function pointer must be set to NULL. When it is provided, + the function set_run_adding_gain() must be provided also. */ + void (*run_adding)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that sets the output gain for + use when run_adding() is called (see above). If this function is + never called the gain is assumed to default to 1. Gain + information should be retained when activate() or deactivate() + are called. + + This function should be provided by the plugin if and only if the + run_adding() function is provided. When it is absent this + function pointer must be set to NULL. */ + void (*set_run_adding_gain)(LADSPA_Handle Instance, + LADSPA_Data Gain); + + /* This is the counterpart to activate() (see above). If there is + nothing for deactivate() to do then the plugin writer may provide + a NULL rather than an empty function. + + Hosts must deactivate all activated units after they have been + run() (or run_adding()) for the last time. This call should be + made as close to the last run() call as possible and indicates to + real-time plugins that they are no longer live. Plugins should + not rely on prompt deactivation. Note that connect_port() may be + called before or after a call to deactivate(). + + Deactivation is not similar to pausing as the plugin instance + will be reinitialised when activate() is called to reuse it. */ + void (*deactivate)(LADSPA_Handle Instance); + + /* Once an instance of a plugin has been finished with it can be + deleted using the following function. The instance handle passed + ceases to be valid after this call. + + If activate() was called for a plugin instance then a + corresponding call to deactivate() must be made before cleanup() + is called. */ + void (*cleanup)(LADSPA_Handle Instance); + +} LADSPA_Descriptor; + +/**********************************************************************/ + +/* Accessing a Plugin: */ + +/* The exact mechanism by which plugins are loaded is host-dependent, + however all most hosts will need to know is the name of shared + object file containing the plugin types. To allow multiple hosts to + share plugin types, hosts may wish to check for environment + variable LADSPA_PATH. If present, this should contain a + colon-separated path indicating directories that should be searched + (in order) when loading plugin types. + + A plugin programmer must include a function called + "ladspa_descriptor" with the following function prototype within + the shared object file. This function will have C-style linkage (if + you are using C++ this is taken care of by the `extern "C"' clause + at the top of the file). + + A host will find the plugin shared object file by one means or + another, find the ladspa_descriptor() function, call it, and + proceed from there. + + Plugin types are accessed by index (not ID) using values from 0 + upwards. Out of range indexes must result in this function + returning NULL, so the plugin count can be determined by checking + for the least index that results in NULL being returned. */ + +const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); + +/* Datatype corresponding to the ladspa_descriptor() function. */ +typedef const LADSPA_Descriptor * +(*LADSPA_Descriptor_Function)(unsigned long Index); + +/**********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* LADSPA_INCLUDED */ + +/* EOF */ diff --git a/src/pcm/mask.c b/src/pcm/mask.c new file mode 100644 index 0000000..ebf1072 --- /dev/null +++ b/src/pcm/mask.c @@ -0,0 +1,28 @@ +/* + * Mask functions + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define SND_MASK_C +#define SND_MASK_INLINE + +#include +#include +#include "pcm_local.h" + diff --git a/src/pcm/mask.h b/src/pcm/mask.h new file mode 100644 index 0000000..ab80f20 --- /dev/null +++ b/src/pcm/mask.h @@ -0,0 +1,57 @@ +/* + * Mask header + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +typedef struct _snd_mask snd_mask_t; + +#define SND_MASK_MAX 64 + +#ifdef SND_MASK_INLINE +#include "mask_inline.h" +#else +void snd_mask_none(snd_mask_t *mask); +void snd_mask_any(snd_mask_t *mask); +void snd_mask_load(snd_mask_t *mask, unsigned int msk); +int snd_mask_empty(const snd_mask_t *mask); +int snd_mask_full(const snd_mask_t *mask); +void snd_mask_set(snd_mask_t *mask, unsigned int val); +void snd_mask_reset(snd_mask_t *mask, unsigned int val); +void snd_mask_copy(snd_mask_t *mask, const snd_mask_t *v); +int snd_mask_test(const snd_mask_t *mask, unsigned int val); +void snd_mask_intersect(snd_mask_t *mask, const snd_mask_t *v); +void snd_mask_union(snd_mask_t *mask, const snd_mask_t *v); +unsigned int snd_mask_count(const snd_mask_t *mask); +unsigned int snd_mask_min(const snd_mask_t *mask); +unsigned int snd_mask_max(const snd_mask_t *mask); +void snd_mask_set_range(snd_mask_t *mask, unsigned int from, unsigned int to); +void snd_mask_reset_range(snd_mask_t *mask, unsigned int from, unsigned int to); +void snd_mask_leave(snd_mask_t *mask, unsigned int val); +int snd_mask_eq(const snd_mask_t *mask, const snd_mask_t *v); +int snd_mask_single(const snd_mask_t *mask); +int snd_mask_refine(snd_mask_t *mask, const snd_mask_t *v); +int snd_mask_refine_first(snd_mask_t *mask); +int snd_mask_refine_last(snd_mask_t *mask); +int snd_mask_refine_min(snd_mask_t *mask, unsigned int val); +int snd_mask_refine_max(snd_mask_t *mask, unsigned int val); +int snd_mask_refine_set(snd_mask_t *mask, unsigned int val); +int snd_mask_value(const snd_mask_t *mask); +int snd_mask_always_eq(const snd_mask_t *m1, const snd_mask_t *m2); +int snd_mask_never_eq(const snd_mask_t *m1, const snd_mask_t *m2); +#endif diff --git a/src/pcm/mask_inline.h b/src/pcm/mask_inline.h new file mode 100644 index 0000000..f656568 --- /dev/null +++ b/src/pcm/mask_inline.h @@ -0,0 +1,299 @@ +/* + * Mask inlines + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +#define MASK_INLINE static inline + +#define MASK_MAX SND_MASK_MAX +#define MASK_SIZE (MASK_MAX / 32) + +#define MASK_OFS(i) ((i) >> 5) +#define MASK_BIT(i) (1U << ((i) & 31)) + +MASK_INLINE unsigned int ld2(u_int32_t v) +{ + unsigned r = 0; + + if (v >= 0x10000) { + v >>= 16; + r += 16; + } + if (v >= 0x100) { + v >>= 8; + r += 8; + } + if (v >= 0x10) { + v >>= 4; + r += 4; + } + if (v >= 4) { + v >>= 2; + r += 2; + } + if (v >= 2) + r++; + return r; +} + +MASK_INLINE unsigned int hweight32(u_int32_t v) +{ + v = (v & 0x55555555) + ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F); + v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF); + return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF); +} + +MASK_INLINE size_t snd_mask_sizeof(void) +{ + return sizeof(snd_mask_t); +} + +MASK_INLINE void snd_mask_none(snd_mask_t *mask) +{ + memset(mask, 0, sizeof(*mask)); +} + +MASK_INLINE void snd_mask_any(snd_mask_t *mask) +{ + memset(mask, 0xff, MASK_SIZE * sizeof(u_int32_t)); +} + +MASK_INLINE int snd_mask_empty(const snd_mask_t *mask) +{ + int i; + for (i = 0; i < MASK_SIZE; i++) + if (mask->bits[i]) + return 0; + return 1; +} + +MASK_INLINE int snd_mask_full(const snd_mask_t *mask) +{ + int i; + for (i = 0; i < MASK_SIZE; i++) + if (mask->bits[i] != 0xffffffff) + return 0; + return 1; +} + +MASK_INLINE unsigned int snd_mask_count(const snd_mask_t *mask) +{ + int i, w = 0; + for (i = 0; i < MASK_SIZE; i++) + w += hweight32(mask->bits[i]); + return w; +} + +MASK_INLINE unsigned int snd_mask_min(const snd_mask_t *mask) +{ + int i; + assert(!snd_mask_empty(mask)); + for (i = 0; i < MASK_SIZE; i++) { + if (mask->bits[i]) + return ffs(mask->bits[i]) - 1 + (i << 5); + } + return 0; +} + +MASK_INLINE unsigned int snd_mask_max(const snd_mask_t *mask) +{ + int i; + assert(!snd_mask_empty(mask)); + for (i = MASK_SIZE - 1; i >= 0; i--) { + if (mask->bits[i]) + return ld2(mask->bits[i]) + (i << 5); + } + return 0; +} + +MASK_INLINE void snd_mask_set(snd_mask_t *mask, unsigned int val) +{ + assert(val <= SND_MASK_MAX); + mask->bits[MASK_OFS(val)] |= MASK_BIT(val); +} + +MASK_INLINE void snd_mask_reset(snd_mask_t *mask, unsigned int val) +{ + assert(val <= SND_MASK_MAX); + mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val); +} + +MASK_INLINE void snd_mask_set_range(snd_mask_t *mask, unsigned int from, unsigned int to) +{ + unsigned int i; + assert(to <= SND_MASK_MAX && from <= to); + for (i = from; i <= to; i++) + mask->bits[MASK_OFS(i)] |= MASK_BIT(i); +} + +MASK_INLINE void snd_mask_reset_range(snd_mask_t *mask, unsigned int from, unsigned int to) +{ + unsigned int i; + assert(to <= SND_MASK_MAX && from <= to); + for (i = from; i <= to; i++) + mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i); +} + +MASK_INLINE void snd_mask_leave(snd_mask_t *mask, unsigned int val) +{ + unsigned int v; + assert(val <= SND_MASK_MAX); + v = mask->bits[MASK_OFS(val)] & MASK_BIT(val); + snd_mask_none(mask); + mask->bits[MASK_OFS(val)] = v; +} + +MASK_INLINE void snd_mask_intersect(snd_mask_t *mask, const snd_mask_t *v) +{ + int i; + for (i = 0; i < MASK_SIZE; i++) + mask->bits[i] &= v->bits[i]; +} + +MASK_INLINE void snd_mask_union(snd_mask_t *mask, const snd_mask_t *v) +{ + int i; + for (i = 0; i < MASK_SIZE; i++) + mask->bits[i] |= v->bits[i]; +} + +MASK_INLINE int snd_mask_eq(const snd_mask_t *mask, const snd_mask_t *v) +{ + return ! memcmp(mask, v, MASK_SIZE * 4); +} + +MASK_INLINE void snd_mask_copy(snd_mask_t *mask, const snd_mask_t *v) +{ + *mask = *v; +} + +MASK_INLINE int snd_mask_test(const snd_mask_t *mask, unsigned int val) +{ + assert(val <= SND_MASK_MAX); + return mask->bits[MASK_OFS(val)] & MASK_BIT(val); +} + +MASK_INLINE int snd_mask_single(const snd_mask_t *mask) +{ + int i, c = 0; + assert(!snd_mask_empty(mask)); + for (i = 0; i < MASK_SIZE; i++) { + if (! mask->bits[i]) + continue; + if (mask->bits[i] & (mask->bits[i] - 1)) + return 0; + if (c) + return 0; + c++; + } + return 1; +} + +MASK_INLINE int snd_mask_refine(snd_mask_t *mask, const snd_mask_t *v) +{ + snd_mask_t old; + if (snd_mask_empty(mask)) + return -ENOENT; + snd_mask_copy(&old, mask); + snd_mask_intersect(mask, v); + if (snd_mask_empty(mask)) + return -EINVAL; + return !snd_mask_eq(mask, &old); +} + +MASK_INLINE int snd_mask_refine_first(snd_mask_t *mask) +{ + if (snd_mask_empty(mask)) + return -ENOENT; + if (snd_mask_single(mask)) + return 0; + snd_mask_leave(mask, snd_mask_min(mask)); + return 1; +} + +MASK_INLINE int snd_mask_refine_last(snd_mask_t *mask) +{ + if (snd_mask_empty(mask)) + return -ENOENT; + if (snd_mask_single(mask)) + return 0; + snd_mask_leave(mask, snd_mask_max(mask)); + return 1; +} + +MASK_INLINE int snd_mask_refine_min(snd_mask_t *mask, unsigned int val) +{ + if (snd_mask_empty(mask)) + return -ENOENT; + if (snd_mask_min(mask) >= val) + return 0; + snd_mask_reset_range(mask, 0, val - 1); + if (snd_mask_empty(mask)) + return -EINVAL; + return 1; +} + +MASK_INLINE int snd_mask_refine_max(snd_mask_t *mask, unsigned int val) +{ + if (snd_mask_empty(mask)) + return -ENOENT; + if (snd_mask_max(mask) <= val) + return 0; + snd_mask_reset_range(mask, val + 1, SND_MASK_MAX); + if (snd_mask_empty(mask)) + return -EINVAL; + return 1; +} + +MASK_INLINE int snd_mask_refine_set(snd_mask_t *mask, unsigned int val) +{ + int changed; + if (snd_mask_empty(mask)) + return -ENOENT; + changed = !snd_mask_single(mask); + snd_mask_leave(mask, val); + if (snd_mask_empty(mask)) + return -EINVAL; + return changed; +} + +MASK_INLINE int snd_mask_value(const snd_mask_t *mask) +{ + assert(!snd_mask_empty(mask)); + return snd_mask_min(mask); +} + +MASK_INLINE int snd_mask_always_eq(const snd_mask_t *m1, const snd_mask_t *m2) +{ + return snd_mask_single(m1) && snd_mask_single(m2) && + snd_mask_value(m1) == snd_mask_value(m2); +} + +MASK_INLINE int snd_mask_never_eq(const snd_mask_t *m1, const snd_mask_t *m2) +{ + int i; + for (i = 0; i < MASK_SIZE; i++) + if (m1->bits[i] & m2->bits[i]) + return 0; + return 1; +} diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c new file mode 100644 index 0000000..02dea0d --- /dev/null +++ b/src/pcm/pcm.c @@ -0,0 +1,7524 @@ +/** + * \file pcm/pcm.c + * \ingroup PCM + * \brief PCM Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2000-2001 + * + * PCM Interface is designed to write or read digital audio frames. A + * frame is the data unit converted into/from sound in one time unit + * (1/rate seconds), by example if you set your playback PCM rate to + * 44100 you'll hear 44100 frames per second. The size in bytes of a + * frame may be obtained from bits needed to store a sample and + * channels count. + * + * See the \ref pcm page for more details. + */ +/* + * PCM Interface - main file + * Copyright (c) 1998 by Jaroslav Kysela + * Copyright (c) 2000 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page pcm PCM (digital audio) interface + +

Although abbreviation PCM stands for Pulse Code Modulation, we are +understanding it as general digital audio processing with volume samples +generated in continuous time periods.

+ +

The analog signal is recorded via analog to digital converters (ADC). +The digital value (de-facto a volume at a specific time) obtained +from ADC can be further processed. The following picture shows a perfect +sinus waveform:

+ +
+\image html wave1.gif + +

Next image shows digitized representation:

+ +
+\image html wave2.gif + +

As you may see, the quality of digital audio signal depends on the time +(recording rate) and voltage resolution (usually in an linear integer +representation with basic unit one bit).

+ +

The stored digital signal can be converted back to voltage (analog) +representation via digital to analog converters (DAC).

+ +

One digital value is called sample. More samples are collected to frames +(frame is terminology for ALSA) depending on count of converters used at one +specific time. One frame might contain one sample (when only one converter is +used - mono) or more samples (for example: stereo has signals from two converters +recorded at same time). Digital audio stream contains collection of frames +recorded at boundaries of continuous time periods.

+ +\section pcm_general_overview General overview + +ALSA uses the ring buffer to store outgoing (playback) and incoming (capture, +record) samples. There are two pointers being maintained to allow +a precise communication between application and device pointing to current +processed sample by hardware and last processed sample by application. +The modern audio chips allow to program the transfer time periods. +It means that the stream of samples is divided to small chunks. Device +acknowledges to application when the transfer of a chunk is complete. + +\section pcm_transfer Transfer methods in UNIX environments + +In the UNIX environment, data chunk acknowledges are received via standard I/O +calls or event waiting routines (poll or select function). To accomplish +this list, the asynchronous notification of acknowledges should be listed +here. The ALSA implementation for these methods is described in +the \ref alsa_transfers section. + +\subsection pcm_transfer_io Standard I/O transfers + +The standard I/O transfers are using the read (see 'man 2 read') and write +(see 'man 2 write') C functions. There are two basic behaviours of these +functions - blocked and non-blocked (see the O_NONBLOCK flag for the +standard C open function - see 'man 2 open'). In non-blocked behaviour, +these I/O functions never stops, they return -EAGAIN error code, when no +data can be transferred (the ring buffer is full in our case). In blocked +behaviour, these I/O functions stop and wait until there is a room in the +ring buffer (playback) or until there are a new samples (capture). The ALSA +implementation can be found in the \ref alsa_pcm_rw section. + +\subsection pcm_transfer_event Event waiting routines + +The poll or select functions (see 'man 2 poll' or 'man 2 select' for further +details) allows to receive requests/events from the device while +an application is waiting on events from other sources (like keyboard, screen, +network etc.), too. \ref snd_pcm_poll_descriptors can be used to get file +descriptors to poll or select on (note that wait direction might be diferent +than expected - do not use only returned file descriptors, but handle +events member as well - see \ref snd_pcm_poll_descriptors function +description for more details and \ref snd_pcm_poll_descriptors_revents for +events demangling). The implemented transfer routines can be found in +the \ref alsa_transfers section. + +\subsection pcm_transfer_async Asynchronous notification + +ALSA driver and library knows to handle the asynchronous notifications over +the SIGIO signal. This signal allows to interrupt application and transfer +data in the signal handler. For further details see the sigaction function +('man 2 sigaction'). The section \ref pcm_async describes the ALSA API for +this extension. The implemented transfer routines can be found in the +\ref alsa_transfers section. + +\section pcm_open_behaviour Blocked and non-blocked open + +The ALSA PCM API uses a different behaviour when the device is opened +with blocked or non-blocked mode. The mode can be specified with +\a mode argument in #snd_pcm_open() function. +The blocked mode is the default (without #SND_PCM_NONBLOCK mode). +In this mode, the behaviour is that if the resources have already used +with another application, then it blocks the caller, until resources are +free. The non-blocked behaviour (with #SND_PCM_NONBLOCK) +doesn't block the caller in any way and returns -EBUSY error when the +resources are not available. Note that the mode also determines the +behaviour of standard I/O calls, returning -EAGAIN when non-blocked mode is +used and the ring buffer is full (playback) or empty (capture). +The operation mode for I/O calls can be changed later with +the #snd_pcm_nonblock() function. + +\section pcm_async Asynchronous mode + +There is also possibility to receive asynchronous notification after +specified time periods. You may see the #SND_PCM_ASYNC +mode for #snd_pcm_open() function and +#snd_async_add_pcm_handler() function for further details. + +\section pcm_handshake Handshake between application and library + +The ALSA PCM API design uses the states to determine the communication +phase between application and library. The actual state can be determined +using #snd_pcm_state() call. There are these states: + +\par SND_PCM_STATE_OPEN +The PCM device is in the open state. After the #snd_pcm_open() open call, +the device is in this state. Also, when #snd_pcm_hw_params() call fails, +then this state is entered to force application calling +#snd_pcm_hw_params() function to set right communication +parameters. + +\par SND_PCM_STATE_SETUP +The PCM device has accepted communication parameters and it is waiting +for #snd_pcm_prepare() call to prepare the hardware for +selected operation (playback or capture). + +\par SND_PCM_STATE_PREPARE +The PCM device is prepared for operation. Application can use +#snd_pcm_start() call, write or read data to start +the operation. + +\par SND_PCM_STATE_RUNNING +The PCM device has been started and is running. It processes the samples. The stream can +be stopped using the #snd_pcm_drop() or +#snd_pcm_drain() calls. + +\par SND_PCM_STATE_XRUN +The PCM device reached overrun (capture) or underrun (playback). +You can use the -EPIPE return code from I/O functions +(#snd_pcm_writei(), #snd_pcm_writen(), #snd_pcm_readi(), #snd_pcm_readn()) +to determine this state without checking +the actual state via #snd_pcm_state() call. It is recommended to use +the helper function #snd_pcm_recover() to recover from this state, but you can also use #snd_pcm_prepare(), +#snd_pcm_drop() or #snd_pcm_drain() calls. + +\par SND_PCM_STATE_DRAINING +The device is in this state when application using the capture mode +called #snd_pcm_drain() function. Until all data are +read from the internal ring buffer using I/O routines +(#snd_pcm_readi(), #snd_pcm_readn()), +then the device stays in this state. + +\par SND_PCM_STATE_PAUSED +The device is in this state when application called +the #snd_pcm_pause() function until the pause is released. +Not all hardware supports this feature. Application should check the +capability with the #snd_pcm_hw_params_can_pause(). + +\par SND_PCM_STATE_SUSPENDED +The device is in the suspend state provoked with the power management +system. The stream can be resumed using #snd_pcm_resume() +call, but not all hardware supports this feature. Application should check +the capability with the #snd_pcm_hw_params_can_resume(). +In other case, the calls #snd_pcm_prepare(), +#snd_pcm_drop(), #snd_pcm_drain() can be used +to leave this state. + +\par SND_PCM_STATE_DISCONNECTED +The device is physicaly disconnected. It does not accept any I/O calls in this state. + +\section pcm_formats PCM formats + +The full list of formats present the #snd_pcm_format_t type. +The 24-bit linear samples uses 32-bit physical space, but the sample is +stored in low three bits. Some hardware does not support processing of full +range, thus you may get the significant bits for linear samples via +#snd_pcm_hw_params_get_sbits() function. The example: ICE1712 +chips support 32-bit sample processing, but low byte is ignored (playback) +or zero (capture). The function snd_pcm_hw_params_get_sbits() +returns 24 in the case. + +\section alsa_transfers ALSA transfers + +There are two methods to transfer samples in application. The first method +is the standard read / write one. The second method, uses the direct audio +buffer to communicate with the device while ALSA library manages this space +itself. You can find examples of all communication schemes for playback +in \ref example_test_pcm "Sine-wave generator example". To complete the +list, we should note that #snd_pcm_wait() function contains +embedded poll waiting implementation. + +\subsection alsa_pcm_rw Read / Write transfer + +There are two versions of read / write routines. The first expects the +interleaved samples at input (#SND_PCM_ACCESS_RW_INTERLEAVED access method), +and the second one expects non-interleaved (samples in separated buffers - +#SND_PCM_ACCESS_RW_NONINTERLEAVED access method) at input. There are these +functions for interleaved transfers: #snd_pcm_writei() +#snd_pcm_readi(). For non-interleaved transfers, there are +these functions: #snd_pcm_writen() and #snd_pcm_readn(). + +\subsection alsa_mmap_rw Direct Read / Write transfer (via mmap'ed areas) + +Three kinds of organization of ring buffer memory areas exist in ALSA API. +Access #SND_PCM_ACCESS_MMAP_INTERLEAVED has interleaved samples. Access +#SND_PCM_ACCESS_MMAP_NONINTERLEAVED expects continous sample areas for +one channel. Access #SND_PCM_ACCESS_MMAP_COMPLEX does not fit to interleaved +and non-interleaved ring buffer organization. + +There are two functions for this kind of transfer. Application can get an +access to memory areas via #snd_pcm_mmap_begin() function. +This function returns the areas (single area is equal to a channel) +containing the direct pointers to memory and sample position description +in #snd_pcm_channel_area_t structure. After application +transfers the data in the memory areas, then it must be acknowledged +the end of transfer via #snd_pcm_mmap_commit() function +to allow the ALSA library update the pointers to ring buffer. This kind of +communication is also called "zero-copy", because the device does not require +to copy the samples from application to another place in system memory. + +If you like to use the compatibility functions in mmap mode, there are +read / write routines equaling to standard read / write transfers. Using +these functions discards the benefits of direct access to memory region. +See the #snd_pcm_mmap_readi(), +#snd_pcm_writei(), #snd_pcm_readn() +and #snd_pcm_writen() functions. + +\section pcm_errors Error codes + +\par -EPIPE + +This error means xrun (underrun for playback or overrun for capture). +The underrun can happen when an application does not feed new samples +in time to alsa-lib (due CPU usage). The overrun can happen when +an application does not take new captured samples in time from alsa-lib. + +\par -ESTRPIPE + +This error means that system has suspended drivers. The application +should wait in loop when snd_pcm_resume() != -EAGAIN and then +call snd_pcm_prepare() when snd_pcm_resume() return an error code. +If snd_pcm_resume() does not fail (a zero value is returned), driver +supports resume and the snd_pcm_prepare() call can be ommited. + +\par -EBADFD + +This error means that the device is in a bad state. It means that +the handskahe between application and alsa-lib is corrupted. + +\par -ENOTTY, -ENODEV + +This error can happen when device is physically removed (for example +some hotplug devices like USB or PCMCIA, CardBus or ExpressCard +can be removed on the fly). + +\section pcm_params Managing parameters + +The ALSA PCM device uses two groups of PCM related parameters. The hardware +parameters contains the stream description like format, rate, count of +channels, ring buffer size etc. The software parameters contains the +software (driver) related parameters. The communication behaviour can be +controlled via these parameters, like automatic start, automatic stop, +interrupting (chunk acknowledge) etc. The software parameters can be +modified at any time (when valid hardware parameters are set). It includes +the running state as well. + +\subsection pcm_hw_params Hardware related parameters + +The ALSA PCM devices use the parameter refining system for hardware +parameters - #snd_pcm_hw_params_t. It means, that +application choose the full-range of configurations at first and then +application sets single parameters until all parameters are elementary +(definite). + +\par Access modes + +ALSA knows about five access modes. The first three can be used for direct +communication. The access mode #SND_PCM_ACCESS_MMAP_INTERLEAVED +determines the direct memory area and interleaved sample organization. +Interleaved organization means, that samples from channels are mixed together. +The access mode #SND_PCM_ACCESS_MMAP_NONINTERLEAVED +determines the direct memory area and non-interleaved sample organization. +Each channel has a separate buffer in the case. The complex direct memory +organization represents the #SND_PCM_ACCESS_MMAP_COMPLEX +access mode. The sample organization does not fit the interleaved or +non-interleaved access modes in the case. The last two access modes +describes the read / write access methods. +The #SND_PCM_ACCESS_RW_INTERLEAVED access represents the read / +write interleaved access and the #SND_PCM_ACCESS_RW_NONINTERLEAVED +represents the non-interleaved access. + +\par Formats + +The full list of formats is available in #snd_pcm_format_t +enumeration. + +\subsection pcm_sw_params Software related parameters + +These parameters - #snd_pcm_sw_params_t can be modified at +any time including the running state. + +\par Minimum available count of samples + +This parameter controls the wakeup point. If the count of available samples +is equal or greater than this value, then application will be activated. + +\par Timestamp mode + +The timestamp mode specifies, if timestamps are activated. Currently, only +#SND_PCM_TSTAMP_NONE and #SND_PCM_TSTAMP_MMAP +modes are known. The mmap mode means that timestamp is taken +on every period time boundary. Corresponding position in the ring buffer +assigned to timestamp can be obtained using #snd_pcm_htimestamp() function. + +\par Transfer align + +The read / write transfers can be aligned to this sample count. The modulo +is ignored by device. Usually, this value is set to one (no align). + +\par Start threshold + +The start threshold parameter is used to determine the start point in +stream. For playback, if samples in ring buffer is equal or greater than +the start threshold parameters and the stream is not running, the stream will +be started automatically from the device. For capture, if the application wants +to read count of samples equal or greater then the stream will be started. +If you want to use explicit start (#snd_pcm_start), you can +set this value greater than ring buffer size (in samples), but use the +constant MAXINT is not a bad idea. + +\par Stop threshold + +Similarly, the stop threshold parameter is used to automatically stop +the running stream, when the available samples crosses this boundary. +It means, for playback, the empty samples in ring buffer and for capture, +the filled (used) samples in ring buffer. + +\par Silence threshold + +The silence threshold specifies count of samples filled with silence +ahead of the current application pointer for playback. It is usable +for applications when an overrun is possible (like tasks depending on +network I/O etc.). If application wants to manage the ahead samples itself, +the #snd_pcm_rewind() function allows to forget the last +samples in the stream. + +\section pcm_status Obtaining stream status + +The stream status is stored in #snd_pcm_status_t structure. +These parameters can be obtained: the current stream state - +#snd_pcm_status_get_state(), timestamp of trigger - +#snd_pcm_status_get_trigger_tstamp(), timestamp of last +pointer update #snd_pcm_status_get_tstamp(), delay in samples - +#snd_pcm_status_get_delay(), available count in samples - +#snd_pcm_status_get_avail(), maximum available samples - +#snd_pcm_status_get_avail_max(), ADC over-range count in +samples - #snd_pcm_status_get_overrange(). The last two +parameters - avail_max and overrange are reset to zero after the status +call. + +\subsection pcm_status_fast Obtaining stream state fast and update r/w pointer + +

+The function #snd_pcm_avail_update() updates the current +available count of samples for writing (playback) or filled samples for +reading (capture). This call is mandatory for updating actual r/w pointer. +Using standalone, it is a light method to obtain current stream position, +because it does not require the user <-> kernel context switch, but the value +is less accurate, because ring buffer pointers are updated in kernel drivers +only when an interrupt occurs. If you want to get accurate stream state, +use functions #snd_pcm_avail(), #snd_pcm_delay() or #snd_pcm_avail_delay(). +

+

+The function #snd_pcm_avail() reads the current hardware pointer +in the ring buffer from hardware and calls #snd_pcm_avail_update() then. +

+

+The function #snd_pcm_delay() returns the delay in samples. +For playback, it means count of samples in the ring buffer before +the next sample will be sent to DAC. For capture, it means count of samples +in the ring buffer before the next sample will be captured from ADC. It works +only when the stream is in the running or draining (playback only) state. +Note that this function does not update the current r/w pointer for applications, +so the function #snd_pcm_avail_update() must be called afterwards +before any read/write begin+commit operations. +

+

+The function #snd_pcm_avail_delay() combines #snd_pcm_avail() and +#snd_pcm_delay() and returns both values in sync. +

+ +\section pcm_action Managing the stream state + +The following functions directly and indirectly affect the stream state: + +\par snd_pcm_hw_params +The #snd_pcm_hw_params() function brings the stream state +to #SND_PCM_STATE_SETUP +if successfully finishes, otherwise the state #SND_PCM_STATE_OPEN +is entered. +When it is brought to SETUP state, this function automatically +calls #snd_pcm_prepare() function to bring to the PREPARE state +as below. + +\par snd_pcm_prepare +The #snd_pcm_prepare() function enters from #SND_PCM_STATE_SETUP +to the #SND_PCM_STATE_PREPARED after a successful finish. + +\par snd_pcm_start +The #snd_pcm_start() function enters +the #SND_PCM_STATE_RUNNING after a successful finish. + +\par snd_pcm_drop +The #snd_pcm_drop() function enters the +#SND_PCM_STATE_SETUP state. + +\par snd_pcm_drain +The #snd_pcm_drain() function enters the +#SND_PCM_STATE_DRAINING, if +the capture device has some samples in the ring buffer otherwise +#SND_PCM_STATE_SETUP state is entered. + +\par snd_pcm_pause +The #snd_pcm_pause() function enters the +#SND_PCM_STATE_PAUSED or #SND_PCM_STATE_RUNNING. + +\par snd_pcm_writei, snd_pcm_writen +The #snd_pcm_writei() and #snd_pcm_writen() +functions can conditionally start the stream - +#SND_PCM_STATE_RUNNING. They depend on the start threshold +software parameter. + +\par snd_pcm_readi, snd_pcm_readn +The #snd_pcm_readi() and #snd_pcm_readn() +functions can conditionally start the stream - +#SND_PCM_STATE_RUNNING. They depend on the start threshold +software parameter. + +\section pcm_sync Streams synchronization + +There are two functions allowing link multiple streams together. In the +case, the linking means that all operations are synchronized. Because the +drivers cannot guarantee the synchronization (sample resolution) on hardware +lacking this feature, the #snd_pcm_info_get_sync() function +returns synchronization ID - #snd_pcm_sync_id_t, which is equal +for hardware synchronized streams. When the #snd_pcm_link() +function is called, all operations managing the stream state for these two +streams are joined. The opposite function is #snd_pcm_unlink(). + +\section pcm_dev_names PCM naming conventions + +The ALSA library uses a generic string representation for names of devices. +The devices might be virtual, physical or a mix of both. The generic string +is passed to #snd_pcm_open() or #snd_pcm_open_lconf(). +It contains two parts: device name and arguments. Devices and arguments are described +in configuration files. The usual place for default definitions is at /usr/share/alsa/alsa.conf. +For detailed descriptions about integrated PCM plugins look to \ref pcm_plugins. + +\subsection pcm_dev_names_default Default device + +The default device is equal to plug plugin with hw plugin as slave. The defaults are +used: + +\code +defaults.pcm.card 0 +defaults.pcm.device 0 +defaults.pcm.subdevice -1 +\endcode + +These defaults can be freely overwritten in local configuration files. + +Example: + +\code +default +\endcode + +\subsection pcm_dev_names_hw HW device + +The hw device description uses the hw plugin. The three arguments (in order: CARD,DEV,SUBDEV) +specify card number or identifier, device number and subdevice number (-1 means any). + +Example: + +\code +hw +hw:0 +hw:0,0 +hw:supersonic,1 +hw:soundwave,1,2 +hw:DEV=1,CARD=soundwave,SUBDEV=2 +\endcode + +\subsection pcm_dev_names_plughw Plug->HW device + +The plughw device description uses the plug plugin and hw plugin as slave. The arguments +are same as for hw device. + +Example: + +\code +plughw +plughw:0 +plughw:0,0 +plughw:supersonic,1 +plughw:soundwave,1,2 +plughw:DEV=1,CARD=soundwave,SUBDEV=2 +\endcode + +\subsection pcm_dev_names_plug Plug device + +The plug device uses the plug plugin. The one SLAVE argument specifies the slave plugin. + +Example: + +\code +plug:mypcmdef +plug:hw +plug:'hw:0,0' +plug:SLAVE=hw +\endcode + +\subsection pcm_dev_names_shm Shared memory device + +The shm device uses the shm plugin. The two arguments (in order: SOCKET,PCM) specify +UNIX socket name (for example /tmp/alsa.socket) for server communication and server's PCM name. + +Example: + +\code +shm:'/tmp/alsa.sock',default +shm:SOCKET='/tmp/alsa.sock',PCM=default +\endcode + +\subsection pcm_dev_names_tee Tee device + +The tee device stores contents of a stream to given file plus transfers it to given slave plugin. +The three arguments (in order: SLAVE,FILE,FORMAT) specify slave plugin, filename and file format. + +Example: + +\code +tee:hw,'/tmp/out.raw',raw +\endcode + +\subsection pcm_dev_names_file File device + +The file device is file plugin with null plugin as slave. The arguments (in order: FILE,FORMAT) +specify filename and file format. + +Example: + +\code +file:'/tmp/out.raw',raw +\endcode + +\subsection pcm_dev_names_null Null device + +The null device is null plugin. This device has not any arguments. + + +\section pcm_examples Examples + +The full featured examples with cross-links can be found in Examples section +(see top of page): + +\anchor example_test_pcm +\par Sine-wave generator +\par +alsa-lib/test/pcm.c example shows various transfer methods for the playback direction. + +\par Minimalistic PCM playback code +\par +alsa-lib/test/pcm_min.c example shows the minimal code to produce a sound. + +\par Latency measuring tool +\par +alsa-lib/test/latency.c example shows the measuring of minimal latency between capture and +playback devices. + +*/ + +/** +\example ../../test/pcm.c +*/ +/** +\example ../../test/pcm_min.c +*/ +/** +\example ../../test/latency.c +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_local.h" + +/** + * \brief get identifier of PCM handle + * \param pcm PCM handle + * \return ascii identifier of PCM handle + * + * Returns the ASCII identifier of given PCM handle. It's the same + * identifier specified in snd_pcm_open(). + */ +const char *snd_pcm_name(snd_pcm_t *pcm) +{ + assert(pcm); + return pcm->name; +} + +/** + * \brief get type of PCM handle + * \param pcm PCM handle + * \return type of PCM handle + * + * Returns the type #snd_pcm_type_t of given PCM handle. + */ +snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm) +{ + assert(pcm); + return pcm->type; +} + +/** + * \brief get stream for a PCM handle + * \param pcm PCM handle + * \return stream of PCM handle + * + * Returns the type #snd_pcm_stream_t of given PCM handle. + */ +snd_pcm_stream_t snd_pcm_stream(snd_pcm_t *pcm) +{ + assert(pcm); + return pcm->stream; +} + +/** + * \brief close PCM handle + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified PCM handle and frees all associated + * resources. + */ +int snd_pcm_close(snd_pcm_t *pcm) +{ + int res = 0, err; + assert(pcm); + if (pcm->setup && !pcm->donot_close) { + snd_pcm_drop(pcm); + err = snd_pcm_hw_free(pcm); + if (err < 0) + res = err; + } + if (pcm->mmap_channels) + snd_pcm_munmap(pcm); + while (!list_empty(&pcm->async_handlers)) { + snd_async_handler_t *h = list_entry(pcm->async_handlers.next, snd_async_handler_t, hlist); + snd_async_del_handler(h); + } + err = pcm->ops->close(pcm->op_arg); + if (err < 0) + res = err; + err = snd_pcm_free(pcm); + if (err < 0) + res = err; + return res; +} + +/** + * \brief set nonblock mode + * \param pcm PCM handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) +{ + int err; + assert(pcm); + if ((err = pcm->ops->nonblock(pcm->op_arg, nonblock)) < 0) + return err; + if (nonblock) + pcm->mode |= SND_PCM_NONBLOCK; + else { + if (pcm->hw_flags & SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP) + return -EINVAL; + pcm->mode &= ~SND_PCM_NONBLOCK; + } + return 0; +} + +#ifndef DOC_HIDDEN +/** + * \brief set async mode + * \param pcm PCM handle + * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) + * \param pid Process ID to signal: 0 current + * \return 0 on success otherwise a negative error code + * + * A signal is raised every period. + */ +int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + assert(pcm); + if (sig == 0) + sig = SIGIO; + if (pid == 0) + pid = getpid(); + return pcm->ops->async(pcm->op_arg, sig, pid); +} +#endif + +/** + * \brief Obtain general (static) information for PCM handle + * \param pcm PCM handle + * \param info Information container + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info) +{ + assert(pcm && info); + return pcm->ops->info(pcm->op_arg, info); +} + +/** \brief Retreive current PCM hardware configuration chosen with #snd_pcm_hw_params + * \param pcm PCM handle + * \param params Configuration space definition container + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_hw_params_current(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + unsigned int frame_bits; + + assert(pcm && params); + if (!pcm->setup) + return -EBADFD; + memset(params, 0, snd_pcm_hw_params_sizeof()); + params->flags = pcm->hw_flags; + snd_mask_set(¶ms->masks[SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK], pcm->access); + snd_mask_set(¶ms->masks[SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK], pcm->format); + snd_mask_set(¶ms->masks[SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK], pcm->subformat); + frame_bits = snd_pcm_format_physical_width(pcm->format) * pcm->channels; + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL], frame_bits); + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL], pcm->channels); + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL], pcm->rate); + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL], pcm->period_time); + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL], pcm->period_size); + snd_interval_copy(¶ms->intervals[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL], &pcm->periods); + snd_interval_copy(¶ms->intervals[SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL], &pcm->buffer_time); + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL], pcm->buffer_size); + snd_interval_set_value(¶ms->intervals[SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL], (pcm->buffer_size * frame_bits) / 8); + params->info = pcm->info; + params->msbits = pcm->msbits; + params->rate_num = pcm->rate_num; + params->rate_den = pcm->rate_den; + params->fifo_size = pcm->fifo_size; + return 0; +} + +/** \brief Install one PCM hardware configuration chosen from a configuration space and #snd_pcm_prepare it + * \param pcm PCM handle + * \param params Configuration space definition container + * \return 0 on success otherwise a negative error code + * + * The configuration is chosen fixing single parameters in this order: + * first access, first format, first subformat, min channels, min rate, + * min period time, max buffer size, min tick time + * + * After this call, #snd_pcm_prepare() is called automatically and + * the stream is brought to \c #SND_PCM_STATE_PREPARED state. + * + * The hardware parameters cannot be changed when the stream is + * running (active). The software parameters can be changed + * at any time. + */ +int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int err; + assert(pcm && params); + err = _snd_pcm_hw_params(pcm, params); + if (err < 0) + return err; + err = snd_pcm_prepare(pcm); + return err; +} + +/** \brief Remove PCM hardware configuration and free associated resources + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_hw_free(snd_pcm_t *pcm) +{ + int err; + if (! pcm->setup) + return 0; + if (pcm->mmap_channels) { + err = snd_pcm_munmap(pcm); + if (err < 0) + return err; + } + // assert(snd_pcm_state(pcm) == SND_PCM_STATE_SETUP || + // snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED); + err = pcm->ops->hw_free(pcm->op_arg); + pcm->setup = 0; + if (err < 0) + return err; + return 0; +} + +/** \brief Install PCM software configuration defined by params + * \param pcm PCM handle + * \param params Configuration container + * \return 0 on success otherwise a negative error code + * + * The software parameters can be changed at any time. + * The hardware parameters cannot be changed when the stream is + * running (active). + */ +int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) +{ + int err; + /* the hw_params must be set at first!!! */ + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (! params->avail_min) { + SNDMSG("params->avail_min is 0"); + return -EINVAL; + } +#if 0 + /* disable the check below - it looks too restrictive + * (start_threshold is basically independent from avail_min) + */ + if (params->start_threshold <= pcm->buffer_size && + params->start_threshold > (pcm->buffer_size / params->avail_min) * params->avail_min) { + SNDMSG("params->avail_min problem for start_threshold"); + return -EINVAL; + } +#endif + err = pcm->ops->sw_params(pcm->op_arg, params); + if (err < 0) + return err; + pcm->tstamp_mode = params->tstamp_mode; + pcm->period_step = params->period_step; + pcm->avail_min = params->avail_min; + pcm->period_event = params->period_event; + pcm->start_threshold = params->start_threshold; + pcm->stop_threshold = params->stop_threshold; + pcm->silence_threshold = params->silence_threshold; + pcm->silence_size = params->silence_size; + pcm->boundary = params->boundary; + return 0; +} + +/** + * \brief Obtain status (runtime) information for PCM handle + * \param pcm PCM handle + * \param status Status container + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status) +{ + assert(pcm && status); + return pcm->fast_ops->status(pcm->fast_op_arg, status); +} + +/** + * \brief Return PCM state + * \param pcm PCM handle + * \return PCM state #snd_pcm_state_t of given PCM handle + * + * This is a faster way to obtain only the PCM state without calling + * \link ::snd_pcm_status() \endlink. + */ +snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm) +{ + assert(pcm); + return pcm->fast_ops->state(pcm->fast_op_arg); +} + +/** + * \brief (DEPRECATED) Synchronize stream position with hardware + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * Note this function does not update the actual r/w pointer + * for applications. The function #snd_pcm_avail_update() + * have to be called before any mmap begin+commit operation. + */ +int snd_pcm_hwsync(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->hwsync(pcm->fast_op_arg); +} +#ifndef DOC_HIDDEN +link_warning(snd_pcm_hwsync, "Warning: snd_pcm_hwsync() is deprecated, consider to use snd_pcm_avail()"); +#endif + +/** + * \brief Obtain delay for a running PCM handle + * \param pcm PCM handle + * \param delayp Returned delay in frames + * \return 0 on success otherwise a negative error code + * + * For playback the delay is defined as the time that a frame that is written + * to the PCM stream shortly after this call will take to be actually + * audible. It is as such the overall latency from the write call to the final + * DAC. + * + * For capture the delay is defined as the time that a frame that was + * digitized by the audio device takes until it can be read from the PCM + * stream shortly after this call returns. It is as such the overall latency + * from the initial ADC to the read call. + * + * Please note that hence in case of a playback underrun this value will not + * necessarily got down to 0. + * + * If the application is interested in the fill level of the playback buffer + * of the device, it should use #snd_pcm_avail*() functions. The + * value returned by that call is not directly related to the delay, since the + * latter might include some additional, fixed latencies the former does not. + * + * Note this function does not update the actual r/w pointer + * for applications. The function #snd_pcm_avail_update() + * have to be called before any begin+commit operation. + */ +int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->delay(pcm->fast_op_arg, delayp); +} + +/** + * \brief Resume from suspend, no samples are lost + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * \retval -EAGAIN resume can't be proceed immediately (audio hardware is probably still suspended) + * \retval -ENOSYS hardware doesn't support this feature + * + * This function can be used when the stream is in the suspend state + * to do the fine resume from this state. Not all hardware supports + * this feature, when an -ENOSYS error is returned, use the \link ::snd_pcm_prepare() \endlink + * function to recovery. + */ +int snd_pcm_resume(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->resume(pcm->fast_op_arg); +} + +/** + * \brief Obtain last position update hi-res timestamp + * \param pcm PCM handle + * \param avail Number of available frames when timestamp was grabbed + * \param tstamp Hi-res timestamp + * \return 0 on success otherwise a negative error code + * + * Note this function does not update the actual r/w pointer + * for applications. + */ +int snd_pcm_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, snd_htimestamp_t *tstamp) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->htimestamp(pcm->fast_op_arg, avail, tstamp); +} + +/** + * \brief Prepare PCM for use + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_prepare(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->prepare(pcm->fast_op_arg); +} + +/** + * \brief Reset PCM position + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * Reduce PCM delay to 0. + */ +int snd_pcm_reset(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->reset(pcm->fast_op_arg); +} + +/** + * \brief Start a PCM + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_start(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->start(pcm->fast_op_arg); +} + +/** + * \brief Stop a PCM dropping pending frames + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * This function stops the PCM immediately. + * The pending samples on the buffer are ignored. + * + * For processing all pending samples, use \link ::snd_pcm_drain() \endlink + * instead. + */ +int snd_pcm_drop(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->drop(pcm->fast_op_arg); +} + +/** + * \brief Stop a PCM preserving pending frames + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * \retval -ESTRPIPE a suspend event occurred + * + * For playback wait for all pending frames to be played and then stop + * the PCM. + * For capture stop PCM permitting to retrieve residual frames. + * + * For stopping the PCM stream immediately, use \link ::snd_pcm_drop() \endlink + * instead. + */ +int snd_pcm_drain(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->drain(pcm->fast_op_arg); +} + +/** + * \brief Pause/resume PCM + * \param pcm PCM handle + * \param enable 0 = resume, 1 = pause + * \return 0 on success otherwise a negative error code + * + * Note that this function works only on the hardware which supports + * pause feature. You can check it via \link ::snd_pcm_hw_params_can_pause() \endlink + * function. + */ +int snd_pcm_pause(snd_pcm_t *pcm, int enable) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->pause(pcm->fast_op_arg, enable); +} + +/** + * \brief Get safe count of frames which can be rewinded + * \param pcm PCM handle + * \return a positive number of frames or negative error code + * + * Note: The snd_pcm_rewind() can accept bigger value than returned + * by this function. But it is not guaranteed that output stream + * will be consistent with bigger value. + */ +snd_pcm_sframes_t snd_pcm_rewindable(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->rewindable(pcm->fast_op_arg); +} + +/** + * \brief Move application frame position backward + * \param pcm PCM handle + * \param frames wanted displacement in frames + * \return a positive number for actual displacement otherwise a + * negative error code + */ +snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (frames == 0) + return 0; + return pcm->fast_ops->rewind(pcm->fast_op_arg, frames); +} + +/** + * \brief Get safe count of frames which can be forwarded + * \param pcm PCM handle + * \return a positive number of frames or negative error code + * + * Note: The snd_pcm_forward() can accept bigger value than returned + * by this function. But it is not guaranteed that output stream + * will be consistent with bigger value. + */ +snd_pcm_sframes_t snd_pcm_forwardable(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return pcm->fast_ops->forwardable(pcm->fast_op_arg); +} + +/** + * \brief Move application frame position forward + * \param pcm PCM handle + * \param frames wanted skip in frames + * \return a positive number for actual skip otherwise a negative error code + * \retval 0 means no action + */ +#ifndef DOXYGEN +snd_pcm_sframes_t INTERNAL(snd_pcm_forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +#else +snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +#endif +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (frames == 0) + return 0; + return pcm->fast_ops->forward(pcm->fast_op_arg, frames); +} +use_default_symbol_version(__snd_pcm_forward, snd_pcm_forward, ALSA_0.9.0rc8); + +/** + * \brief Write interleaved frames to a PCM + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected and it is running, then routine waits until + * all requested frames are played or put to the playback ring buffer. + * The returned number of frames can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + assert(pcm); + assert(size == 0 || buffer); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED) { + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } + return _snd_pcm_writei(pcm, buffer, size); +} + +/** + * \brief Write non interleaved frames to a PCM + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected and it is running, then routine waits until + * all requested frames are played or put to the playback ring buffer. + * The returned number of frames can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + assert(pcm); + assert(size == 0 || bufs); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } + return _snd_pcm_writen(pcm, bufs, size); +} + +/** + * \brief Read interleaved frames from a PCM + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be read + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected and it is running, then routine waits until + * all requested frames are filled. The returned number of frames can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + assert(pcm); + assert(size == 0 || buffer); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED) { + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } + return _snd_pcm_readi(pcm, buffer, size); +} + +/** + * \brief Read non interleaved frames to a PCM + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be read + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected and it is running, then routine waits until + * all requested frames are filled. The returned number of frames can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + assert(pcm); + assert(size == 0 || bufs); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { + SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access)); + return -EINVAL; + } + return _snd_pcm_readn(pcm, bufs, size); +} + +/** + * \brief Link two PCMs + * \param pcm1 first PCM handle + * \param pcm2 first PCM handle + * \return 0 on success otherwise a negative error code + * + * The two PCMs will start/stop/prepare in sync. + */ +int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + assert(pcm1); + assert(pcm2); + if (pcm1->fast_ops->link) + return pcm1->fast_ops->link(pcm1, pcm2); + return -ENOSYS; +} + +/** + * \brief Remove a PCM from a linked group + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_unlink(snd_pcm_t *pcm) +{ + assert(pcm); + if (pcm->fast_ops->unlink) + return pcm->fast_ops->unlink(pcm); + return -ENOSYS; +} + +/** + * \brief get count of poll descriptors for PCM handle + * \param pcm PCM handle + * \return count of poll descriptors + */ +int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm) +{ + assert(pcm); + if (pcm->fast_ops->poll_descriptors_count) + return pcm->fast_ops->poll_descriptors_count(pcm->fast_op_arg); + return pcm->poll_fd_count; +} + + +/** + * \brief get poll descriptors + * \param pcm PCM handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + * + * This function fills the given poll descriptor structs for the specified + * PCM handle. The poll desctiptor array should have the size returned by + * \link ::snd_pcm_poll_descriptors_count() \endlink function. + * + * The result is intended for direct use with the poll() syscall. + * + * For reading the returned events of poll descriptor after poll() system + * call, use \link ::snd_pcm_poll_descriptors_revents() \endlink function. + * The field values in pollfd structs may be bogus regarding the stream + * direction from the application perspective (POLLIN might not imply read + * direction and POLLOUT might not imply write), but + * the \link ::snd_pcm_poll_descriptors_revents() \endlink function + * does the right "demangling". + * + * You can use output from this function as arguments for the select() + * syscall, too. Do not forget to translate POLLIN and POLLOUT events to + * corresponding FD_SET arrays and demangle events using + * \link ::snd_pcm_poll_descriptors_revents() \endlink . + */ +int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + assert(pcm && pfds); + if (pcm->fast_ops->poll_descriptors) + return pcm->fast_ops->poll_descriptors(pcm->fast_op_arg, pfds, space); + if (pcm->poll_fd < 0) { + SNDMSG("poll_fd < 0"); + return -EIO; + } + if (space >= 1 && pfds) { + pfds->fd = pcm->poll_fd; + pfds->events = pcm->poll_events | POLLERR | POLLNVAL; + } else { + return 0; + } + return 1; +} + +/** + * \brief get returned events from poll descriptors + * \param pcm PCM handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents pointer to the returned (single) event + * \return zero if success, otherwise a negative error code + * + * This function does "demangling" of the revents mask returned from + * the poll() syscall to correct semantics (POLLIN = read, POLLOUT = write). + * + * Note: The null event also exists. Even if poll() or select() + * syscall returned that some events are waiting, this function might + * return empty set of events. In this case, application should + * do next event waiting using poll() or select(). + * + * Note: Even if multiple poll descriptors are used (i.e. pfds > 1), + * this function returns only a single event. + */ +int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(pcm && pfds && revents); + if (pcm->fast_ops->poll_revents) + return pcm->fast_ops->poll_revents(pcm->fast_op_arg, pfds, nfds, revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +#ifndef DOC_HIDDEN +#define PCMTYPE(v) [SND_PCM_TYPE_##v] = #v +#define STATE(v) [SND_PCM_STATE_##v] = #v +#define STREAM(v) [SND_PCM_STREAM_##v] = #v +#define READY(v) [SND_PCM_READY_##v] = #v +#define XRUN(v) [SND_PCM_XRUN_##v] = #v +#define SILENCE(v) [SND_PCM_SILENCE_##v] = #v +#define TSTAMP(v) [SND_PCM_TSTAMP_##v] = #v +#define ACCESS(v) [SND_PCM_ACCESS_##v] = #v +#define START(v) [SND_PCM_START_##v] = #v +#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v +#define SW_PARAM(v) [SND_PCM_SW_PARAM_##v] = #v +#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v +#define SUBFORMAT(v) [SND_PCM_SUBFORMAT_##v] = #v + +#define FORMATD(v, d) [SND_PCM_FORMAT_##v] = d +#define SUBFORMATD(v, d) [SND_PCM_SUBFORMAT_##v] = d + + +static const char *const snd_pcm_stream_names[] = { + STREAM(PLAYBACK), + STREAM(CAPTURE), +}; + +static const char *const snd_pcm_state_names[] = { + STATE(OPEN), + STATE(SETUP), + STATE(PREPARED), + STATE(RUNNING), + STATE(XRUN), + STATE(DRAINING), + STATE(PAUSED), + STATE(SUSPENDED), + STATE(DISCONNECTED), +}; + +static const char *const snd_pcm_access_names[] = { + ACCESS(MMAP_INTERLEAVED), + ACCESS(MMAP_NONINTERLEAVED), + ACCESS(MMAP_COMPLEX), + ACCESS(RW_INTERLEAVED), + ACCESS(RW_NONINTERLEAVED), +}; + +static const char *const snd_pcm_format_names[] = { + FORMAT(S8), + FORMAT(U8), + FORMAT(S16_LE), + FORMAT(S16_BE), + FORMAT(U16_LE), + FORMAT(U16_BE), + FORMAT(S24_LE), + FORMAT(S24_BE), + FORMAT(U24_LE), + FORMAT(U24_BE), + FORMAT(S32_LE), + FORMAT(S32_BE), + FORMAT(U32_LE), + FORMAT(U32_BE), + FORMAT(FLOAT_LE), + FORMAT(FLOAT_BE), + FORMAT(FLOAT64_LE), + FORMAT(FLOAT64_BE), + FORMAT(IEC958_SUBFRAME_LE), + FORMAT(IEC958_SUBFRAME_BE), + FORMAT(MU_LAW), + FORMAT(A_LAW), + FORMAT(IMA_ADPCM), + FORMAT(MPEG), + FORMAT(GSM), + FORMAT(SPECIAL), + FORMAT(S24_3LE), + FORMAT(S24_3BE), + FORMAT(U24_3LE), + FORMAT(U24_3BE), + FORMAT(S20_3LE), + FORMAT(S20_3BE), + FORMAT(U20_3LE), + FORMAT(U20_3BE), + FORMAT(S18_3LE), + FORMAT(S18_3BE), + FORMAT(U18_3LE), + FORMAT(U18_3BE), +}; + +static const char *const snd_pcm_format_aliases[SND_PCM_FORMAT_LAST+1] = { + FORMAT(S16), + FORMAT(U16), + FORMAT(S24), + FORMAT(U24), + FORMAT(S32), + FORMAT(U32), + FORMAT(FLOAT), + FORMAT(FLOAT64), + FORMAT(IEC958_SUBFRAME), +}; + +static const char *const snd_pcm_format_descriptions[] = { + FORMATD(S8, "Signed 8 bit"), + FORMATD(U8, "Unsigned 8 bit"), + FORMATD(S16_LE, "Signed 16 bit Little Endian"), + FORMATD(S16_BE, "Signed 16 bit Big Endian"), + FORMATD(U16_LE, "Unsigned 16 bit Little Endian"), + FORMATD(U16_BE, "Unsigned 16 bit Big Endian"), + FORMATD(S24_LE, "Signed 24 bit Little Endian"), + FORMATD(S24_BE, "Signed 24 bit Big Endian"), + FORMATD(U24_LE, "Unsigned 24 bit Little Endian"), + FORMATD(U24_BE, "Unsigned 24 bit Big Endian"), + FORMATD(S32_LE, "Signed 32 bit Little Endian"), + FORMATD(S32_BE, "Signed 32 bit Big Endian"), + FORMATD(U32_LE, "Unsigned 32 bit Little Endian"), + FORMATD(U32_BE, "Unsigned 32 bit Big Endian"), + FORMATD(FLOAT_LE, "Float 32 bit Little Endian"), + FORMATD(FLOAT_BE, "Float 32 bit Big Endian"), + FORMATD(FLOAT64_LE, "Float 64 bit Little Endian"), + FORMATD(FLOAT64_BE, "Float 64 bit Big Endian"), + FORMATD(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"), + FORMATD(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"), + FORMATD(MU_LAW, "Mu-Law"), + FORMATD(A_LAW, "A-Law"), + FORMATD(IMA_ADPCM, "Ima-ADPCM"), + FORMATD(MPEG, "MPEG"), + FORMATD(GSM, "GSM"), + FORMATD(SPECIAL, "Special"), + FORMATD(S24_3LE, "Signed 24 bit Little Endian in 3bytes"), + FORMATD(S24_3BE, "Signed 24 bit Big Endian in 3bytes"), + FORMATD(U24_3LE, "Unsigned 24 bit Little Endian in 3bytes"), + FORMATD(U24_3BE, "Unsigned 24 bit Big Endian in 3bytes"), + FORMATD(S20_3LE, "Signed 20 bit Little Endian in 3bytes"), + FORMATD(S20_3BE, "Signed 20 bit Big Endian in 3bytes"), + FORMATD(U20_3LE, "Unsigned 20 bit Little Endian in 3bytes"), + FORMATD(U20_3BE, "Unsigned 20 bit Big Endian in 3bytes"), + FORMATD(S18_3LE, "Signed 18 bit Little Endian in 3bytes"), + FORMATD(S18_3BE, "Signed 18 bit Big Endian in 3bytes"), + FORMATD(U18_3LE, "Unsigned 18 bit Little Endian in 3bytes"), + FORMATD(U18_3BE, "Unsigned 18 bit Big Endian in 3bytes"), +}; + +static const char *const snd_pcm_type_names[] = { + PCMTYPE(HW), + PCMTYPE(HOOKS), + PCMTYPE(MULTI), + PCMTYPE(FILE), + PCMTYPE(NULL), + PCMTYPE(SHM), + PCMTYPE(INET), + PCMTYPE(COPY), + PCMTYPE(LINEAR), + PCMTYPE(ALAW), + PCMTYPE(MULAW), + PCMTYPE(ADPCM), + PCMTYPE(RATE), + PCMTYPE(ROUTE), + PCMTYPE(PLUG), + PCMTYPE(SHARE), + PCMTYPE(METER), + PCMTYPE(MIX), + PCMTYPE(DROUTE), + PCMTYPE(LBSERVER), + PCMTYPE(LINEAR_FLOAT), + PCMTYPE(LADSPA), + PCMTYPE(DMIX), + PCMTYPE(JACK), + PCMTYPE(DSNOOP), + PCMTYPE(IEC958), + PCMTYPE(SOFTVOL), + PCMTYPE(IOPLUG), + PCMTYPE(EXTPLUG), + PCMTYPE(MMAP_EMUL), +}; + +static const char *const snd_pcm_subformat_names[] = { + SUBFORMAT(STD), +}; + +static const char *const snd_pcm_subformat_descriptions[] = { + SUBFORMATD(STD, "Standard"), +}; + +static const char *const snd_pcm_start_mode_names[] = { + START(EXPLICIT), + START(DATA), +}; + +static const char *const snd_pcm_xrun_mode_names[] = { + XRUN(NONE), + XRUN(STOP), +}; + +static const char *const snd_pcm_tstamp_mode_names[] = { + TSTAMP(NONE), + TSTAMP(ENABLE), +}; +#endif + +/** + * \brief get name of PCM stream type + * \param stream PCM stream type + * \return ascii name of PCM stream type + */ +const char *snd_pcm_stream_name(snd_pcm_stream_t stream) +{ + if (stream > SND_PCM_STREAM_LAST) + return NULL; + return snd_pcm_stream_names[stream]; +} + +/** + * \brief get name of PCM access type + * \param acc PCM access type + * \return ascii name of PCM access type + */ +const char *snd_pcm_access_name(snd_pcm_access_t acc) +{ + if (acc > SND_PCM_ACCESS_LAST) + return NULL; + return snd_pcm_access_names[acc]; +} + +/** + * \brief get name of PCM sample format + * \param format PCM sample format + * \return ascii name of PCM sample format + */ +const char *snd_pcm_format_name(snd_pcm_format_t format) +{ + if (format > SND_PCM_FORMAT_LAST) + return NULL; + return snd_pcm_format_names[format]; +} + +/** + * \brief get description of PCM sample format + * \param format PCM sample format + * \return ascii description of PCM sample format + */ +const char *snd_pcm_format_description(snd_pcm_format_t format) +{ + if (format > SND_PCM_FORMAT_LAST) + return NULL; + return snd_pcm_format_descriptions[format]; +} + +/** + * \brief get PCM sample format from name + * \param name PCM sample format name (case insensitive) + * \return PCM sample format + */ +snd_pcm_format_t snd_pcm_format_value(const char* name) +{ + snd_pcm_format_t format; + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (snd_pcm_format_names[format] && + strcasecmp(name, snd_pcm_format_names[format]) == 0) { + return format; + } + if (snd_pcm_format_aliases[format] && + strcasecmp(name, snd_pcm_format_aliases[format]) == 0) { + return format; + } + } + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (snd_pcm_format_descriptions[format] && + strcasecmp(name, snd_pcm_format_descriptions[format]) == 0) { + return format; + } + } + return SND_PCM_FORMAT_UNKNOWN; +} + +/** + * \brief get name of PCM sample subformat + * \param subformat PCM sample subformat + * \return ascii name of PCM sample subformat + */ +const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat) +{ + if (subformat > SND_PCM_SUBFORMAT_LAST) + return NULL; + return snd_pcm_subformat_names[subformat]; +} + +/** + * \brief get description of PCM sample subformat + * \param subformat PCM sample subformat + * \return ascii description of PCM sample subformat + */ +const char *snd_pcm_subformat_description(snd_pcm_subformat_t subformat) +{ + if (subformat > SND_PCM_SUBFORMAT_LAST) + return NULL; + return snd_pcm_subformat_descriptions[subformat]; +} + +/** + * \brief (DEPRECATED) get name of PCM start mode setting + * \param mode PCM start mode + * \return ascii name of PCM start mode setting + */ +const char *snd_pcm_start_mode_name(snd_pcm_start_t mode) +{ + if (mode > SND_PCM_START_LAST) + return NULL; + return snd_pcm_start_mode_names[mode]; +} + +#ifndef DOC_HIDDEN +link_warning(snd_pcm_start_mode_name, "Warning: start_mode is deprecated, consider to use start_threshold"); +#endif + +/** + * \brief (DEPRECATED) get name of PCM xrun mode setting + * \param mode PCM xrun mode + * \return ascii name of PCM xrun mode setting + */ +const char *snd_pcm_xrun_mode_name(snd_pcm_xrun_t mode) +{ + if (mode > SND_PCM_XRUN_LAST) + return NULL; + return snd_pcm_xrun_mode_names[mode]; +} + +#ifndef DOC_HIDDEN +link_warning(snd_pcm_xrun_mode_name, "Warning: xrun_mode is deprecated, consider to use stop_threshold"); +#endif + +/** + * \brief get name of PCM tstamp mode setting + * \param mode PCM tstamp mode + * \return ascii name of PCM tstamp mode setting + */ +const char *snd_pcm_tstamp_mode_name(snd_pcm_tstamp_t mode) +{ + if (mode > SND_PCM_TSTAMP_LAST) + return NULL; + return snd_pcm_tstamp_mode_names[mode]; +} + +/** + * \brief get name of PCM state + * \param state PCM state + * \return ascii name of PCM state + */ +const char *snd_pcm_state_name(snd_pcm_state_t state) +{ + if (state > SND_PCM_STATE_LAST) + return NULL; + return snd_pcm_state_names[state]; +} + +/** + * \brief get name of PCM type + * \param type PCM type + * \return ascii name of PCM type + */ +#ifndef DOXYGEN +const char *INTERNAL(snd_pcm_type_name)(snd_pcm_type_t type) +#else +const char *snd_pcm_type_name(snd_pcm_type_t type) +#endif +{ + if (type > SND_PCM_TYPE_LAST) + return NULL; + return snd_pcm_type_names[type]; +} +use_default_symbol_version(__snd_pcm_type_name, snd_pcm_type_name, ALSA_0.9.0); + +/** + * \brief Dump current hardware setup for PCM + * \param pcm PCM handle + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, snd_output_t *out) +{ + assert(pcm); + assert(out); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_output_printf(out, " stream : %s\n", snd_pcm_stream_name(pcm->stream)); + snd_output_printf(out, " access : %s\n", snd_pcm_access_name(pcm->access)); + snd_output_printf(out, " format : %s\n", snd_pcm_format_name(pcm->format)); + snd_output_printf(out, " subformat : %s\n", snd_pcm_subformat_name(pcm->subformat)); + snd_output_printf(out, " channels : %u\n", pcm->channels); + snd_output_printf(out, " rate : %u\n", pcm->rate); + snd_output_printf(out, " exact rate : %g (%u/%u)\n", + (pcm->rate_den ? ((double) pcm->rate_num / pcm->rate_den) : 0.0), + pcm->rate_num, pcm->rate_den); + snd_output_printf(out, " msbits : %u\n", pcm->msbits); + snd_output_printf(out, " buffer_size : %lu\n", pcm->buffer_size); + snd_output_printf(out, " period_size : %lu\n", pcm->period_size); + snd_output_printf(out, " period_time : %u\n", pcm->period_time); + return 0; +} + +/** + * \brief Dump current software setup for PCM + * \param pcm PCM handle + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out) +{ + assert(pcm); + assert(out); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_output_printf(out, " tstamp_mode : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode)); + snd_output_printf(out, " period_step : %d\n", pcm->period_step); + snd_output_printf(out, " avail_min : %ld\n", pcm->avail_min); + snd_output_printf(out, " period_event : %i\n", pcm->period_event); + snd_output_printf(out, " start_threshold : %ld\n", pcm->start_threshold); + snd_output_printf(out, " stop_threshold : %ld\n", pcm->stop_threshold); + snd_output_printf(out, " silence_threshold: %ld\n", pcm->silence_threshold); + snd_output_printf(out, " silence_size : %ld\n", pcm->silence_size); + snd_output_printf(out, " boundary : %ld\n", pcm->boundary); + return 0; +} + +/** + * \brief Dump current setup (hardware and software) for PCM + * \param pcm PCM handle + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_dump_setup(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_dump_hw_setup(pcm, out); + snd_pcm_dump_sw_setup(pcm, out); + return 0; +} + +/** + * \brief Dump status + * \param status Status container + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out) +{ + assert(status); + snd_output_printf(out, " state : %s\n", snd_pcm_state_name((snd_pcm_state_t) status->state)); + snd_output_printf(out, " trigger_time: %ld.%06ld\n", + status->trigger_tstamp.tv_sec, status->trigger_tstamp.tv_nsec); + snd_output_printf(out, " tstamp : %ld.%06ld\n", + status->tstamp.tv_sec, status->tstamp.tv_nsec); + snd_output_printf(out, " delay : %ld\n", (long)status->delay); + snd_output_printf(out, " avail : %ld\n", (long)status->avail); + snd_output_printf(out, " avail_max : %ld\n", (long)status->avail_max); + return 0; +} + +/** + * \brief Dump PCM info + * \param pcm PCM handle + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + assert(pcm); + assert(out); + pcm->ops->dump(pcm->op_arg, out); + return 0; +} + +/** + * \brief Convert bytes in frames for a PCM + * \param pcm PCM handle + * \param bytes quantity in bytes + * \return quantity expressed in frames + */ +snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return bytes * 8 / pcm->frame_bits; +} + +/** + * \brief Convert frames in bytes for a PCM + * \param pcm PCM handle + * \param frames quantity in frames + * \return quantity expressed in bytes + */ +ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return frames * pcm->frame_bits / 8; +} + +/** + * \brief Convert bytes in samples for a PCM + * \param pcm PCM handle + * \param bytes quantity in bytes + * \return quantity expressed in samples + */ +long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return bytes * 8 / pcm->sample_bits; +} + +/** + * \brief Convert samples in bytes for a PCM + * \param pcm PCM handle + * \param samples quantity in samples + * \return quantity expressed in bytes + */ +ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + return samples * pcm->sample_bits / 8; +} + +/** + * \brief Add an async handler for a PCM + * \param handler Returned handler handle + * \param pcm PCM handle + * \param callback Callback function + * \param private_data Callback private data + * \return 0 otherwise a negative error code on failure + * + * The asynchronous callback is called when period boundary elapses. + */ +int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm, + snd_async_callback_t callback, void *private_data) +{ + int err; + int was_empty; + snd_async_handler_t *h; + err = snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm), + callback, private_data); + if (err < 0) + return err; + h->type = SND_ASYNC_HANDLER_PCM; + h->u.pcm = pcm; + was_empty = list_empty(&pcm->async_handlers); + list_add_tail(&h->hlist, &pcm->async_handlers); + if (was_empty) { + err = snd_pcm_async(pcm, snd_async_handler_get_signo(h), getpid()); + if (err < 0) { + snd_async_del_handler(h); + return err; + } + } + *handler = h; + return 0; +} + +/** + * \brief Return PCM handle related to an async handler + * \param handler Async handler handle + * \return PCM handle + */ +snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler) +{ + if (handler->type != SND_ASYNC_HANDLER_PCM) { + SNDMSG("invalid handler type %d", handler->type); + return NULL; + } + return handler->u.pcm; +} + +static const char *const build_in_pcms[] = { + "adpcm", "alaw", "copy", "dmix", "file", "hooks", "hw", "ladspa", "lfloat", + "linear", "meter", "mulaw", "multi", "null", "empty", "plug", "rate", "route", "share", + "shm", "dsnoop", "dshare", "asym", "iec958", "softvol", "mmap_emul", + NULL +}; + +static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name, + snd_config_t *pcm_root, snd_config_t *pcm_conf, + snd_pcm_stream_t stream, int mode) +{ + const char *str; + char *buf = NULL, *buf1 = NULL; + int err; + snd_config_t *conf, *type_conf = NULL, *tmp; + snd_config_iterator_t i, next; + const char *id; + const char *lib = NULL, *open_name = NULL; + int (*open_func)(snd_pcm_t **, const char *, + snd_config_t *, snd_config_t *, + snd_pcm_stream_t, int) = NULL; +#ifndef PIC + extern void *snd_pcm_open_symbols(void); +#endif + if (snd_config_get_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) { + char *val; + id = NULL; + snd_config_get_id(pcm_conf, &id); + val = NULL; + snd_config_get_ascii(pcm_conf, &val); + SNDERR("Invalid type for PCM %s%sdefinition (id: %s, value: %s)", name ? name : "", name ? " " : "", id, val); + free(val); + return -EINVAL; + } + err = snd_config_search(pcm_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(pcm_root, "pcm_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for PCM type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + buf = malloc(strlen(str) + 32); + if (buf == NULL) { + err = -ENOMEM; + goto _err; + } + open_name = buf; + sprintf(buf, "_snd_pcm_%s_open", str); + } + if (!lib) { + const char *const *build_in = build_in_pcms; + while (*build_in) { + if (!strcmp(*build_in, str)) + break; + build_in++; + } + if (*build_in == NULL) { + buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32); + if (buf1 == NULL) { + err = -ENOMEM; + goto _err; + } + lib = buf1; + sprintf(buf1, "%s/libasound_module_pcm_%s.so", ALSA_PLUGIN_DIR, str); + } + } +#ifndef PIC + snd_pcm_open_symbols(); /* this call is for static linking only */ +#endif + open_func = snd_dlobj_cache_get(lib, open_name, + SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION), 1); + if (open_func) { + err = open_func(pcmp, name, pcm_root, pcm_conf, stream, mode); + if (err >= 0) { + (*pcmp)->open_func = open_func; + err = 0; + } else { + snd_dlobj_cache_put(open_func); + } + } else { + err = -ENXIO; + } + if (err >= 0) { + err = snd_config_search(pcm_root, "defaults.pcm.compat", &tmp); + if (err >= 0) { + long i; + if (snd_config_get_integer(tmp, &i) >= 0) { + if (i > 0) + (*pcmp)->compat = 1; + } + } else { + char *str = getenv("LIBASOUND_COMPAT"); + if (str && *str) + (*pcmp)->compat = 1; + } + err = snd_config_search(pcm_root, "defaults.pcm.minperiodtime", &tmp); + if (err >= 0) + snd_config_get_integer(tmp, &(*pcmp)->minperiodtime); + err = 0; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + free(buf); + free(buf1); + return err; +} + +static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, + const char *name, snd_pcm_stream_t stream, + int mode, int hop) +{ + int err; + snd_config_t *pcm_conf; + const char *str; + + err = snd_config_search_definition(root, "pcm", name, &pcm_conf); + if (err < 0) { + SNDERR("Unknown PCM %s", name); + return err; + } + if (snd_config_get_string(pcm_conf, &str) >= 0) + err = snd_pcm_open_noupdate(pcmp, root, str, stream, mode, + hop + 1); + else { + snd_config_set_hop(pcm_conf, hop); + err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode); + } + snd_config_delete(pcm_conf); + return err; +} + +/** + * \brief Opens a PCM + * \param pcmp Returned PCM handle + * \param name ASCII identifier of the PCM handle + * \param stream Wanted stream + * \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_stream_t stream, int mode) +{ + int err; + assert(pcmp && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0); +} + +/** + * \brief Opens a PCM using local configuration + * \param pcmp Returned PCM handle + * \param name ASCII identifier of the PCM handle + * \param stream Wanted stream + * \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC) + * \param lconf Local configuration + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_open_lconf(snd_pcm_t **pcmp, const char *name, + snd_pcm_stream_t stream, int mode, + snd_config_t *lconf) +{ + assert(pcmp && name && lconf); + return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode, 0); +} + +#ifndef DOC_HIDDEN +int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm; + pcm = calloc(1, sizeof(*pcm)); + if (!pcm) + return -ENOMEM; + pcm->type = type; + if (name) + pcm->name = strdup(name); + pcm->stream = stream; + pcm->mode = mode; + pcm->poll_fd_count = 1; + pcm->poll_fd = -1; + pcm->op_arg = pcm; + pcm->fast_op_arg = pcm; + INIT_LIST_HEAD(&pcm->async_handlers); + *pcmp = pcm; + return 0; +} + +int snd_pcm_free(snd_pcm_t *pcm) +{ + assert(pcm); + free(pcm->name); + free(pcm->hw.link_dst); + free(pcm->appl.link_dst); + snd_dlobj_cache_put(pcm->open_func); + free(pcm); + return 0; +} + +int snd_pcm_open_named_slave(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, + snd_config_t *conf, snd_pcm_stream_t stream, + int mode, snd_config_t *parent_conf) +{ + const char *str; + int hop; + + if ((hop = snd_config_check_hop(parent_conf)) < 0) + return hop; + if (snd_config_get_string(conf, &str) >= 0) + return snd_pcm_open_noupdate(pcmp, root, str, stream, mode, + hop + 1); + return snd_pcm_open_conf(pcmp, name, root, conf, stream, mode); +} +#endif + +/** + * \brief Wait for a PCM to become ready + * \param pcm PCM handle + * \param timeout maximum time in milliseconds to wait, + * a negative value means infinity + * \return a positive value on success otherwise a negative error code + * (-EPIPE for the xrun and -ESTRPIPE for the suspended status, + * others for general errors) + * \retval 0 timeout occurred + * \retval 1 PCM stream is ready for I/O + */ +int snd_pcm_wait(snd_pcm_t *pcm, int timeout) +{ + if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min) { + /* check more precisely */ + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return 1; + } + } + return snd_pcm_wait_nocheck(pcm, timeout); +} + +#ifndef DOC_HIDDEN +/* + * like snd_pcm_wait() but doesn't check mmap_avail before calling poll() + * + * used in drain code in some plugins + */ +int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout) +{ + struct pollfd *pfd; + unsigned short revents = 0; + int npfds, err, err_poll; + + npfds = snd_pcm_poll_descriptors_count(pcm); + if (npfds <= 0 || npfds >= 16) { + SNDERR("Invalid poll_fds %d\n", npfds); + return -EIO; + } + pfd = alloca(sizeof(*pfd) * npfds); + err = snd_pcm_poll_descriptors(pcm, pfd, npfds); + if (err < 0) + return err; + if (err != npfds) { + SNDMSG("invalid poll descriptors %d\n", err); + return -EIO; + } + do { + err_poll = poll(pfd, npfds, timeout); + if (err_poll < 0) { + if (errno == EINTR) + continue; + return -errno; + } + if (! err_poll) + break; + err = snd_pcm_poll_descriptors_revents(pcm, pfd, npfds, &revents); + if (err < 0) + return err; + if (revents & (POLLERR | POLLNVAL)) { + /* check more precisely */ + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EIO; + } + } + } while (!(revents & (POLLIN | POLLOUT))); +#if 0 /* very useful code to test poll related problems */ + { + snd_pcm_sframes_t avail_update; + snd_pcm_hwsync(pcm); + avail_update = snd_pcm_avail_update(pcm); + if (avail_update < (snd_pcm_sframes_t)pcm->avail_min) { + printf("*** snd_pcm_wait() FATAL ERROR!!!\n"); + printf("avail_min = %li, avail_update = %li\n", pcm->avail_min, avail_update); + } + } +#endif + return err_poll > 0 ? 1 : 0; +} +#endif + +/** + * \brief Return number of frames ready to be read (capture) / written (playback) + * \param pcm PCM handle + * \return a positive number of frames ready otherwise a negative + * error code + * + * On capture does all the actions needed to transport to application + * level all the ready frames across underlying layers. + * + * The position is not synced with hardware (driver) position in the sound + * ring buffer in this function. This function is a light version of + * #snd_pcm_avail() . + * + * Using this function is ideal after poll() or select() when audio + * file descriptor made the event and when application expects just period + * timing. + * + * Also this function might be called after #snd_pcm_delay() or + * #snd_pcm_hwsync() functions to move private ring buffer pointers + * in alsa-lib (the internal plugin chain). + */ +snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm) +{ + return pcm->fast_ops->avail_update(pcm->fast_op_arg); +} + +/** + * \brief Return number of frames ready to be read (capture) / written (playback) + * \param pcm PCM handle + * \return a positive number of frames ready otherwise a negative + * error code + * + * On capture does all the actions needed to transport to application + * level all the ready frames across underlying layers. + * + * The position is synced with hardware (driver) position in the sound + * ring buffer in this functions. + */ +snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = pcm->fast_ops->hwsync(pcm->fast_op_arg); + if (err < 0) + return err; + return pcm->fast_ops->avail_update(pcm->fast_op_arg); +} + +/** + * \brief Combine snd_pcm_avail and snd_pcm_delay functions + * \param pcm PCM handle + * \param availp Number of available frames in the ring buffer + * \param delayp Total I/O latency in frames + * \return zero on success otherwise a negative error code + * + * The avail and delay values retuned are in sync. + */ +int snd_pcm_avail_delay(snd_pcm_t *pcm, + snd_pcm_sframes_t *availp, + snd_pcm_sframes_t *delayp) +{ + snd_pcm_sframes_t sf; + int err; + + assert(pcm && availp && delayp); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = pcm->fast_ops->hwsync(pcm->fast_op_arg); + if (err < 0) + return err; + sf = pcm->fast_ops->avail_update(pcm->fast_op_arg); + if (sf < 0) + return (int)sf; + err = pcm->fast_ops->delay(pcm->fast_op_arg, delayp); + if (err < 0) + return err; + *availp = sf; + return 0; +} + +/** + * \brief Silence an area + * \param dst_area area specification + * \param dst_offset offset in frames inside area + * \param samples samples to silence + * \param format PCM sample format + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset, + unsigned int samples, snd_pcm_format_t format) +{ + /* FIXME: sub byte resolution and odd dst_offset */ + char *dst; + unsigned int dst_step; + int width; + u_int64_t silence; + if (!dst_area->addr) + return 0; + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + width = snd_pcm_format_physical_width(format); + silence = snd_pcm_format_silence_64(format); + if (dst_area->step == (unsigned int) width) { + unsigned int dwords = samples * width / 64; + u_int64_t *dstp = (u_int64_t *)dst; + samples -= dwords * 64 / width; + while (dwords-- > 0) + *dstp++ = silence; + if (samples == 0) + return 0; + } + dst_step = dst_area->step / 8; + switch (width) { + case 4: { + u_int8_t s0 = silence & 0xf0; + u_int8_t s1 = silence & 0x0f; + int dstbit = dst_area->first % 8; + int dstbit_step = dst_area->step % 8; + while (samples-- > 0) { + if (dstbit) { + *dst &= 0xf0; + *dst |= s1; + } else { + *dst &= 0x0f; + *dst |= s0; + } + dst += dst_step; + dstbit += dstbit_step; + if (dstbit == 8) { + dst++; + dstbit = 0; + } + } + break; + } + case 8: { + u_int8_t sil = silence; + while (samples-- > 0) { + *dst = sil; + dst += dst_step; + } + break; + } + case 16: { + u_int16_t sil = silence; + while (samples-- > 0) { + *(u_int16_t*)dst = sil; + dst += dst_step; + } + break; + } + case 24: +#ifdef SNDRV_LITTLE_ENDIAN + *(dst + 0) = silence >> 0; + *(dst + 1) = silence >> 8; + *(dst + 2) = silence >> 16; +#else + *(dst + 2) = silence >> 0; + *(dst + 1) = silence >> 8; + *(dst + 0) = silence >> 16; +#endif + break; + case 32: { + u_int32_t sil = silence; + while (samples-- > 0) { + *(u_int32_t*)dst = sil; + dst += dst_step; + } + break; + } + case 64: { + while (samples-- > 0) { + *(u_int64_t*)dst = silence; + dst += dst_step; + } + break; + } + default: + SNDMSG("invalid format width %d", width); + return -EINVAL; + } + return 0; +} + +/** + * \brief Silence one or more areas + * \param dst_areas areas specification (one for each channel) + * \param dst_offset offset in frames inside area + * \param channels channels count + * \param frames frames to silence + * \param format PCM sample format + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format) +{ + int width = snd_pcm_format_physical_width(format); + while (channels > 0) { + void *addr = dst_areas->addr; + unsigned int step = dst_areas->step; + const snd_pcm_channel_area_t *begin = dst_areas; + int channels1 = channels; + unsigned int chns = 0; + int err; + while (1) { + channels1--; + chns++; + dst_areas++; + if (channels1 == 0 || + dst_areas->addr != addr || + dst_areas->step != step || + dst_areas->first != dst_areas[-1].first + width) + break; + } + if (chns > 1 && chns * width == step) { + /* Collapse the areas */ + snd_pcm_channel_area_t d; + d.addr = begin->addr; + d.first = begin->first; + d.step = width; + err = snd_pcm_area_silence(&d, dst_offset * chns, frames * chns, format); + channels -= chns; + } else { + err = snd_pcm_area_silence(begin, dst_offset, frames, format); + dst_areas = begin + 1; + channels--; + } + if (err < 0) + return err; + } + return 0; +} + + +/** + * \brief Copy an area + * \param dst_area destination area specification + * \param dst_offset offset in frames inside destination area + * \param src_area source area specification + * \param src_offset offset in frames inside source area + * \param samples samples to copy + * \param format PCM sample format + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_area, snd_pcm_uframes_t src_offset, + unsigned int samples, snd_pcm_format_t format) +{ + /* FIXME: sub byte resolution and odd dst_offset */ + const char *src; + char *dst; + int width; + int src_step, dst_step; + if (dst_area == src_area && dst_offset == src_offset) + return 0; + if (!src_area->addr) + return snd_pcm_area_silence(dst_area, dst_offset, samples, format); + src = snd_pcm_channel_area_addr(src_area, src_offset); + if (!dst_area->addr) + return 0; + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + width = snd_pcm_format_physical_width(format); + if (src_area->step == (unsigned int) width && + dst_area->step == (unsigned int) width) { + size_t bytes = samples * width / 8; + samples -= bytes * 8 / width; + memcpy(dst, src, bytes); + if (samples == 0) + return 0; + } + src_step = src_area->step / 8; + dst_step = dst_area->step / 8; + switch (width) { + case 4: { + int srcbit = src_area->first % 8; + int srcbit_step = src_area->step % 8; + int dstbit = dst_area->first % 8; + int dstbit_step = dst_area->step % 8; + while (samples-- > 0) { + unsigned char srcval; + if (srcbit) + srcval = *src & 0x0f; + else + srcval = *src & 0xf0; + if (dstbit) + *dst &= 0xf0; + else + *dst &= 0x0f; + *dst |= srcval; + src += src_step; + srcbit += srcbit_step; + if (srcbit == 8) { + src++; + srcbit = 0; + } + dst += dst_step; + dstbit += dstbit_step; + if (dstbit == 8) { + dst++; + dstbit = 0; + } + } + break; + } + case 8: { + while (samples-- > 0) { + *dst = *src; + src += src_step; + dst += dst_step; + } + break; + } + case 16: { + while (samples-- > 0) { + *(u_int16_t*)dst = *(const u_int16_t*)src; + src += src_step; + dst += dst_step; + } + break; + } + case 24: + while (samples-- > 0) { + *(dst + 0) = *(src + 0); + *(dst + 1) = *(src + 1); + *(dst + 2) = *(src + 2); + src += src_step; + dst += dst_step; + } + break; + case 32: { + while (samples-- > 0) { + *(u_int32_t*)dst = *(const u_int32_t*)src; + src += src_step; + dst += dst_step; + } + break; + } + case 64: { + while (samples-- > 0) { + *(u_int64_t*)dst = *(const u_int64_t*)src; + src += src_step; + dst += dst_step; + } + break; + } + default: + SNDMSG("invalid format width %d", width); + return -EINVAL; + } + return 0; +} + +/** + * \brief Copy one or more areas + * \param dst_areas destination areas specification (one for each channel) + * \param dst_offset offset in frames inside destination area + * \param src_areas source areas specification (one for each channel) + * \param src_offset offset in frames inside source area + * \param channels channels count + * \param frames frames to copy + * \param format PCM sample format + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format) +{ + int width = snd_pcm_format_physical_width(format); + assert(dst_areas); + assert(src_areas); + if (! channels) { + SNDMSG("invalid channels %d", channels); + return -EINVAL; + } + if (! frames) { + SNDMSG("invalid frames %ld", frames); + return -EINVAL; + } + while (channels > 0) { + unsigned int step = src_areas->step; + void *src_addr = src_areas->addr; + const snd_pcm_channel_area_t *src_start = src_areas; + void *dst_addr = dst_areas->addr; + const snd_pcm_channel_area_t *dst_start = dst_areas; + int channels1 = channels; + unsigned int chns = 0; + while (dst_areas->step == step) { + channels1--; + chns++; + src_areas++; + dst_areas++; + if (channels1 == 0 || + src_areas->step != step || + src_areas->addr != src_addr || + dst_areas->addr != dst_addr || + src_areas->first != src_areas[-1].first + width || + dst_areas->first != dst_areas[-1].first + width) + break; + } + if (chns > 1 && chns * width == step) { + /* Collapse the areas */ + snd_pcm_channel_area_t s, d; + s.addr = src_start->addr; + s.first = src_start->first; + s.step = width; + d.addr = dst_start->addr; + d.first = dst_start->first; + d.step = width; + snd_pcm_area_copy(&d, dst_offset * chns, + &s, src_offset * chns, + frames * chns, format); + channels -= chns; + } else { + snd_pcm_area_copy(dst_start, dst_offset, + src_start, src_offset, + frames, format); + src_areas = src_start + 1; + dst_areas = dst_start + 1; + channels--; + } + } + return 0; +} + +static void dump_one_param(snd_pcm_hw_params_t *params, unsigned int k, snd_output_t *out) +{ + snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(k)); + snd_pcm_hw_param_dump(params, k, out); + snd_output_putc(out, '\n'); +} + +/** + * \brief Dump a PCM hardware configuration space + * \param params Configuration space + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params, snd_output_t *out) +{ + unsigned int k; + for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) + dump_one_param(params, k, out); + for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) + dump_one_param(params, k, out); + return 0; +} + +/** + * \brief Check, if hardware supports sample-resolution mmap for given configuration + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't support sample-resolution mmap + * \retval 1 Hardware supports sample-resolution mmap + * + * The return value is always one when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_can_mmap_sample_resolution(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_MMAP_VALID); +} + +/** + * \brief Check, if hardware does double buffering for start/stop for given configuration + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't do double buffering for start/stop + * \retval 1 Hardware does double buffering for start/stop + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_is_double(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_DOUBLE); +} + +/** + * \brief Check, if hardware does double buffering for data transfers for given configuration + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't do double buffering for data transfers + * \retval 1 Hardware does double buffering for data transfers + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_is_batch(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_BATCH); +} + +/** + * \brief Check, if hardware does block transfers for samples for given configuration + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't block transfers + * \retval 1 Hardware does block transfers + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_is_block_transfer(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_BLOCK_TRANSFER); +} + +/** + * \brief Check, if timestamps are monotonic for given configuration + * \param params Configuration space + * \return Boolean value + * \retval 0 Device doesn't do monotomic timestamps + * \retval 1 Device does monotonic timestamps + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_is_monotonic(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SND_PCM_INFO_MONOTONIC); +} + +/** + * \brief Check, if hardware supports overrange detection + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't support overrange detection + * \retval 1 Hardware supports overrange detection + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_can_overrange(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_OVERRANGE); +} + +/** + * \brief Check, if hardware supports pause + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't support pause + * \retval 1 Hardware supports pause + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_PAUSE); +} + +/** + * \brief Check, if hardware supports resume + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't support resume + * \retval 1 Hardware supports resume + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_can_resume(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_RESUME); +} + +/** + * \brief Check, if hardware does half-duplex only + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't do half-duplex + * \retval 1 Hardware does half-duplex + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_HALF_DUPLEX); +} + +/** + * \brief Check, if hardware does joint-duplex (playback and capture are somewhat correlated) + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't do joint-duplex + * \retval 1 Hardware does joint-duplex + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_JOINT_DUPLEX); +} + +/** + * \brief Check, if hardware supports synchronized start with sample resolution + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware doesn't support synchronized start + * \retval 1 Hardware supports synchronized start + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_SYNC_START); +} + +/** + * \brief Check if hardware can disable period wakeups + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware cannot disable period wakeups + * \retval 1 Hardware can disable period wakeups + */ +int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP); +} + +/** + * \brief Get rate exact info from a configuration space + * \param params Configuration space + * \param rate_num Pointer to returned rate numerator + * \param rate_den Pointer to returned rate denominator + * \return 0 otherwise a negative error code if the info is not available + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params, + unsigned int *rate_num, unsigned int *rate_den) +{ + assert(params); + if (CHECK_SANITY(params->rate_den == 0)) { + SNDMSG("invalid rate_den value"); + return -EINVAL; + } + *rate_num = params->rate_num; + *rate_den = params->rate_den; + return 0; +} + +/** + * \brief Get sample resolution info from a configuration space + * \param params Configuration space + * \return signification bits in sample otherwise a negative error code if the info is not available + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_get_sbits(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->msbits == 0)) { + SNDMSG("invalid msbits value"); + return -EINVAL; + } + return params->msbits; +} + +/** + * \brief Get hard are FIFO size info from a configuration space + * \param params Configuration space + * \return FIFO size in frames otherwise a negative error code if the info is not available + * + * It is not allowed to call this function when given configuration is not exactly one. + * Usually, #snd_pcm_hw_params() function chooses one configuration + * from the configuration space. + */ +int snd_pcm_hw_params_get_fifo_size(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return -EINVAL; + } + return params->fifo_size; +} + +/** + * \brief Fill params with a full configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + */ +int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + _snd_pcm_hw_params_any(params); + return snd_pcm_hw_refine(pcm, params); +} + +/** + * \brief get size of #snd_pcm_access_mask_t + * \return size in bytes + */ +size_t snd_pcm_access_mask_sizeof() +{ + return sizeof(snd_pcm_access_mask_t); +} + +/** + * \brief allocate an empty #snd_pcm_access_mask_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_access_mask_malloc(snd_pcm_access_mask_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_access_mask_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_access_mask_t + * \param obj pointer to object to free + */ +void snd_pcm_access_mask_free(snd_pcm_access_mask_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_access_mask_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_access_mask_copy(snd_pcm_access_mask_t *dst, const snd_pcm_access_mask_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief reset all bits in a #snd_pcm_access_mask_t + * \param mask pointer to mask + */ +void snd_pcm_access_mask_none(snd_pcm_access_mask_t *mask) +{ + snd_mask_none((snd_mask_t *) mask); +} + +/** + * \brief set all bits in a #snd_pcm_access_mask_t + * \param mask pointer to mask + */ +void snd_pcm_access_mask_any(snd_pcm_access_mask_t *mask) +{ + snd_mask_any((snd_mask_t *) mask); +} + +/** + * \brief test the presence of an access type in a #snd_pcm_access_mask_t + * \param mask pointer to mask + * \param val access type + */ +int snd_pcm_access_mask_test(const snd_pcm_access_mask_t *mask, snd_pcm_access_t val) +{ + return snd_mask_test((const snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief test, if given a #snd_pcm_access_mask_t is empty + * \param mask pointer to mask + * \retval 0 not empty + * \retval 1 empty + */ +int snd_pcm_access_mask_empty(const snd_pcm_access_mask_t *mask) +{ + return snd_mask_empty((const snd_mask_t *) mask); +} + +/** + * \brief make an access type present in a #snd_pcm_access_mask_t + * \param mask pointer to mask + * \param val access type + */ +void snd_pcm_access_mask_set(snd_pcm_access_mask_t *mask, snd_pcm_access_t val) +{ + snd_mask_set((snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief make an access type missing from a #snd_pcm_access_mask_t + * \param mask pointer to mask + * \param val access type + */ +void snd_pcm_access_mask_reset(snd_pcm_access_mask_t *mask, snd_pcm_access_t val) +{ + snd_mask_reset((snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief get size of #snd_pcm_format_mask_t + * \return size in bytes + */ +size_t snd_pcm_format_mask_sizeof() +{ + return sizeof(snd_pcm_format_mask_t); +} + +/** + * \brief allocate an empty #snd_pcm_format_mask_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_format_mask_malloc(snd_pcm_format_mask_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_format_mask_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_format_mask_t + * \param obj pointer to object to free + */ +void snd_pcm_format_mask_free(snd_pcm_format_mask_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_format_mask_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_format_mask_copy(snd_pcm_format_mask_t *dst, const snd_pcm_format_mask_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief reset all bits in a #snd_pcm_format_mask_t + * \param mask pointer to mask + */ +void snd_pcm_format_mask_none(snd_pcm_format_mask_t *mask) +{ + snd_mask_none((snd_mask_t *) mask); +} + +/** + * \brief set all bits in a #snd_pcm_format_mask_t + * \param mask pointer to mask + */ +void snd_pcm_format_mask_any(snd_pcm_format_mask_t *mask) +{ + snd_mask_any((snd_mask_t *) mask); +} + +/** + * \brief test the presence of a format in a #snd_pcm_format_mask_t + * \param mask pointer to mask + * \param val format + */ +int snd_pcm_format_mask_test(const snd_pcm_format_mask_t *mask, snd_pcm_format_t val) +{ + return snd_mask_test((const snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief test, if given a #snd_pcm_format_mask_t is empty + * \param mask pointer to mask + * \retval 0 not empty + * \retval 1 empty + */ +int snd_pcm_format_mask_empty(const snd_pcm_format_mask_t *mask) +{ + return snd_mask_empty((const snd_mask_t *) mask); +} + +/** + * \brief make a format present in a #snd_pcm_format_mask_t + * \param mask pointer to mask + * \param val format + */ +void snd_pcm_format_mask_set(snd_pcm_format_mask_t *mask, snd_pcm_format_t val) +{ + snd_mask_set((snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief make a format missing from a #snd_pcm_format_mask_t + * \param mask pointer to mask + * \param val format + */ +void snd_pcm_format_mask_reset(snd_pcm_format_mask_t *mask, snd_pcm_format_t val) +{ + snd_mask_reset((snd_mask_t *) mask, (unsigned long) val); +} + + +/** + * \brief get size of #snd_pcm_subformat_mask_t + * \return size in bytes + */ +size_t snd_pcm_subformat_mask_sizeof() +{ + return sizeof(snd_pcm_subformat_mask_t); +} + +/** + * \brief allocate an empty #snd_pcm_subformat_mask_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_subformat_mask_malloc(snd_pcm_subformat_mask_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_subformat_mask_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_subformat_mask_t + * \param obj pointer to object to free + */ +void snd_pcm_subformat_mask_free(snd_pcm_subformat_mask_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_subformat_mask_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_subformat_mask_copy(snd_pcm_subformat_mask_t *dst, const snd_pcm_subformat_mask_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief reset all bits in a #snd_pcm_subformat_mask_t + * \param mask pointer to mask + */ +void snd_pcm_subformat_mask_none(snd_pcm_subformat_mask_t *mask) +{ + snd_mask_none((snd_mask_t *) mask); +} + +/** + * \brief set all bits in a #snd_pcm_subformat_mask_t + * \param mask pointer to mask + */ +void snd_pcm_subformat_mask_any(snd_pcm_subformat_mask_t *mask) +{ + snd_mask_any((snd_mask_t *) mask); +} + +/** + * \brief test the presence of a subformat in a #snd_pcm_subformat_mask_t + * \param mask pointer to mask + * \param val subformat + */ +int snd_pcm_subformat_mask_test(const snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val) +{ + return snd_mask_test((const snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief test, if given a #snd_pcm_subformat_mask_t is empty + * \param mask pointer to mask + * \retval 0 not empty + * \retval 1 empty + */ +int snd_pcm_subformat_mask_empty(const snd_pcm_subformat_mask_t *mask) +{ + return snd_mask_empty((const snd_mask_t *) mask); +} + +/** + * \brief make a subformat present in a #snd_pcm_subformat_mask_t + * \param mask pointer to mask + * \param val subformat + */ +void snd_pcm_subformat_mask_set(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val) +{ + snd_mask_set((snd_mask_t *) mask, (unsigned long) val); +} + +/** + * \brief make a subformat missing from a #snd_pcm_subformat_mask_t + * \param mask pointer to mask + * \param val subformat + */ +void snd_pcm_subformat_mask_reset(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val) +{ + snd_mask_reset((snd_mask_t *) mask, (unsigned long) val); +} + + +/** + * \brief get size of #snd_pcm_hw_params_t + * \return size in bytes + */ +size_t snd_pcm_hw_params_sizeof() +{ + return sizeof(snd_pcm_hw_params_t); +} + +/** + * \brief allocate an invalid #snd_pcm_hw_params_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_hw_params_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_hw_params_t + * \param obj pointer to object to free + */ +void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_hw_params_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Extract access type from a configuration space + * \param params Configuration space + * \param access Returned value + * \return access type otherwise a negative error code if not exactly one is present + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_access)(const snd_pcm_hw_params_t *params, snd_pcm_access_t *access) +#else +int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params, snd_pcm_access_t *access) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_ACCESS, &_val, NULL); + if (err >= 0) + *access = _val; + return err; +} + +/** + * \brief Verify if an access type is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param access access type + * \return 0 if available a negative error code otherwise + */ +int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_ACCESS, access, 0); +} + +/** + * \brief Restrict a configuration space to contain only one access type + * \param pcm PCM handle + * \param params Configuration space + * \param access access type + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_ACCESS, access, 0); +} + +/** + * \brief Restrict a configuration space to contain only its first access type + * \param pcm PCM handle + * \param params Configuration space + * \param access Returned first access type + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_access_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *access) +#else +int snd_pcm_hw_params_set_access_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *access) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, access, NULL); +} + +/** + * \brief Restrict a configuration space to contain only its last access type + * \param pcm PCM handle + * \param params Configuration space + * \param access Returned last access type + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_access_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *access) +#else +int snd_pcm_hw_params_set_access_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *access) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_ACCESS, access, NULL); +} + +/** + * \brief Restrict a configuration space to contain only a set of access types + * \param pcm PCM handle + * \param params Configuration space + * \param mask Access mask + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask) +{ + return snd_pcm_hw_param_set_mask(pcm, params, SND_TRY, SND_PCM_HW_PARAM_ACCESS, (snd_mask_t *) mask); +} + +/** + * \brief Get access mask from a configuration space + * \param params Configuration space + * \param mask Returned Access mask + */ +int snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask) +{ + if (params == NULL || mask == NULL) + return -EINVAL; + snd_pcm_access_mask_copy(mask, snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS)); + return 0; +} + + +/** + * \brief Extract format from a configuration space + * \param params Configuration space + * \param format returned format + * \return format otherwise a negative error code if not exactly one is present + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_format)(const snd_pcm_hw_params_t *params, snd_pcm_format_t *format) +#else +int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params, snd_pcm_format_t *format) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_FORMAT, (unsigned int *)format, NULL); +} + +/** + * \brief Verify if a format is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param format format + * \return 0 if available a negative error code otherwise + */ +int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t format) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_FORMAT, format, 0); +} + +/** + * \brief Restrict a configuration space to contain only one format + * \param pcm PCM handle + * \param params Configuration space + * \param format format + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t format) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_FORMAT, format, 0); +} + +/** + * \brief Restrict a configuration space to contain only its first format + * \param pcm PCM handle + * \param params Configuration space + * \param format Returned first format + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_format_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format) +#else +int snd_pcm_hw_params_set_format_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, (unsigned int *)format, NULL); +} + +/** + * \brief Restrict a configuration space to contain only its last format + * \param pcm PCM handle + * \param params Configuration space + * \param format Returned last format + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_format_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format) +#else +int snd_pcm_hw_params_set_format_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_FORMAT, (unsigned int *)format, NULL); +} + +/** + * \brief Restrict a configuration space to contain only a set of formats + * \param pcm PCM handle + * \param params Configuration space + * \param mask Format mask + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask) +{ + return snd_pcm_hw_param_set_mask(pcm, params, SND_TRY, SND_PCM_HW_PARAM_FORMAT, (snd_mask_t *) mask); +} + +/** + * \brief Get format mask from a configuration space + * \param params Configuration space + * \param mask Returned Format mask + */ +void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask) +{ + snd_pcm_format_mask_copy(mask, snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_FORMAT)); +} + + +/** + * \brief Extract subformat from a configuration space + * \param params Configuration space + * \param subformat Returned subformat value + * \return subformat otherwise a negative error code if not exactly one is present + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_subformat)(const snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat) +#else +int snd_pcm_hw_params_get_subformat(const snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_SUBFORMAT, subformat, NULL); +} + +/** + * \brief Verify if a subformat is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param subformat subformat value + * \return 0 if available a negative error code otherwise + */ +int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_SUBFORMAT, subformat, 0); +} + +/** + * \brief Restrict a configuration space to contain only one subformat + * \param pcm PCM handle + * \param params Configuration space + * \param subformat subformat value + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_SUBFORMAT, subformat, 0); +} + +/** + * \brief Restrict a configuration space to contain only its first subformat + * \param pcm PCM handle + * \param params Configuration space + * \param subformat Returned subformat + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_subformat_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat) +#else +int snd_pcm_hw_params_set_subformat_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, subformat, NULL); +} + +/** + * \brief Restrict a configuration space to contain only its last subformat + * \param pcm PCM handle + * \param params Configuration space + * \param subformat Returned subformat + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_subformat_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat) +#else +int snd_pcm_hw_params_set_subformat_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, subformat, NULL); +} + +/** + * \brief Restrict a configuration space to contain only a set of subformats + * \param pcm PCM handle + * \param params Configuration space + * \param mask Subformat mask + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask) +{ + return snd_pcm_hw_param_set_mask(pcm, params, SND_TRY, SND_PCM_HW_PARAM_SUBFORMAT, (snd_mask_t *) mask); +} + +/** + * \brief Get subformat mask from a configuration space + * \param params Configuration space + * \param mask Returned Subformat mask + */ +void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask) +{ + snd_pcm_subformat_mask_copy(mask, snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_SUBFORMAT)); +} + + +/** + * \brief Extract channels from a configuration space + * \param params Configuration space + * \param val Returned channels count + * \return 0 otherwise a negative error code if not exactly one is present + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_channels)(const snd_pcm_hw_params_t *params, unsigned int *val) +#else +int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params, unsigned int *val) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Extract minimum channels count from a configuration space + * \param params Configuration space + * \param val minimum channels count + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_channels_min)(const snd_pcm_hw_params_t *params, unsigned int *val) +#else +int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params, unsigned int *val) +#endif +{ + return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Extract maximum channels count from a configuration space + * \param params Configuration space + * \param val maximum channels count + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_channels_max)(const snd_pcm_hw_params_t *params, unsigned int *val) +#else +int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params, unsigned int *val) +#endif +{ + return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Verify if a channels count is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val channels count + * \return 0 if available a negative error code otherwise + */ +int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_CHANNELS, val, 0); +} + +/** + * \brief Restrict a configuration space to contain only one channels count + * \param pcm PCM handle + * \param params Configuration space + * \param val channels count + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, 0); +} + +/** + * \brief Restrict a configuration space with a minimum channels count + * \param pcm PCM handle + * \param params Configuration space + * \param val minimum channels count (on return filled with actual minimum) + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +{ + return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Restrict a configuration space with a maximum channels count + * \param pcm PCM handle + * \param params Configuration space + * \param val maximum channels count (on return filled with actual maximum) + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +{ + return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Restrict a configuration space to have channels counts in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min minimum channels count (on return filled with actual minimum) + * \param max maximum channels count (on return filled with actual maximum) + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max) +{ + return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, min, NULL, max, NULL); +} + +/** + * \brief Restrict a configuration space to have channels count nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val target channels count, returned chosen channels count + * \return 0 otherwise a negative error code if configuration space is empty + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_channels_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +#else +int snd_pcm_hw_params_set_channels_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +#endif +{ + return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Restrict a configuration space to contain only its minimum channels count + * \param pcm PCM handle + * \param params Configuration space + * \param val minimum channels count + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_channels_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +#else +int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + +/** + * \brief Restrict a configuration space to contain only its maximum channels count + * \param pcm PCM handle + * \param params Configuration space + * \param val maximum channels count + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_channels_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +#else +int snd_pcm_hw_params_set_channels_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_CHANNELS, val, NULL); +} + + +/** + * \brief Extract rate from a configuration space + * \param params Configuration space + * \param val Returned approximate rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_rate)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Extract minimum rate from a configuration space + * \param params Configuration space + * \param val Returned approximate minimum rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_rate_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Extract maximum rate from a configuration space + * \param params Configuration space + * \param val Returned approximate maximum rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_rate_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Verify if a rate is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate rate + * \param dir Sub unit direction + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only one rate + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space with a minimum rate + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum rate (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space with a maximum rate + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum rate (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space to have rates in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum rate (on return filled with actual minimum) + * \param mindir Sub unit direction for minimum (on return filled with actual direction) + * \param max approximate maximum rate (on return filled with actual maximum) + * \param maxdir Sub unit direction for maximum (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact min/max is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir) +{ + return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, min, mindir, max, maxdir); +} + +/** + * \brief Restrict a configuration space to have rate nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target rate / returned approximate set rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_rate_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its minimum rate + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned minimum approximate rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_rate_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_rate_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its maximum rate + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned maximum approximate rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_rate_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_rate_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_RATE, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only real hardware rates + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disable, 1 = enable (default) rate resampling + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_set_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val) +{ + assert(pcm && params); + if (!val) + params->flags |= SND_PCM_HW_PARAMS_NORESAMPLE; + else + params->flags &= ~SND_PCM_HW_PARAMS_NORESAMPLE; + return snd_pcm_hw_refine(pcm, params); +} + +/** + * \brief Extract resample state from a configuration space + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disable, 1 = enable rate resampling + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_get_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +{ + assert(pcm && params && val); + *val = params->flags & SND_PCM_HW_PARAMS_NORESAMPLE ? 0 : 1; + return 0; +} + +/** + * \brief Restrict a configuration space to allow the buffer accessible from outside + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disable, 1 = enable (default) exporting buffer + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_set_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val) +{ + assert(pcm && params); + if (val) + params->flags |= SND_PCM_HW_PARAMS_EXPORT_BUFFER; + else + params->flags &= ~SND_PCM_HW_PARAMS_EXPORT_BUFFER; + return snd_pcm_hw_refine(pcm, params); +} + +/** + * \brief Extract buffer accessibility from a configuration space + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disable, 1 = enable exporting buffer + * \return 0 otherwise a negative error code + */ +int snd_pcm_hw_params_get_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +{ + assert(pcm && params && val); + *val = params->flags & SND_PCM_HW_PARAMS_EXPORT_BUFFER ? 1 : 0; + return 0; +} + +/** + * \brief Restrict a configuration space to settings without period wakeups + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disable, 1 = enable (default) period wakeup + * \return Zero on success, otherwise a negative error code. + * + * This function must be called only on devices where non-blocking mode is + * enabled. + * + * To check whether the hardware does support disabling period wakeups, call + * #snd_pcm_hw_params_can_disable_period_wakeup(). If the hardware does not + * support this mode, standard period wakeups will be generated. + * + * Even with disabled period wakeups, the period size/time/count parameters + * are valid; it is suggested to use #snd_pcm_hw_params_set_period_size_last(). + * + * When period wakeups are disabled, the application must not use any functions + * that could block on this device. The use of poll should be limited to error + * cases. The application needs to use an external event or a timer to + * check the state of the ring buffer and refill it apropriately. + */ +int snd_pcm_hw_params_set_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val) +{ + assert(pcm && params); + + if (!val) { + if (!(pcm->mode & SND_PCM_NONBLOCK)) + return -EINVAL; + params->flags |= SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; + } else + params->flags &= ~SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; + + return snd_pcm_hw_refine(pcm, params); +} + +/** + * \brief Extract period wakeup flag from a configuration space + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disabled, 1 = enabled period wakeups + * \return Zero on success, otherwise a negative error code. + */ +int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) +{ + assert(pcm && params && val); + *val = params->flags & SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP ? 0 : 1; + return 0; +} + +/** + * \brief Extract period time from a configuration space + * \param params Configuration space + * \param val Returned approximate period duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_period_time)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Extract minimum period time from a configuration space + * \param params Configuration space + * \param val approximate minimum period duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_period_time_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Extract maximum period time from a configuration space + * \param params Configuration space + * \param val approximate maximum period duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_period_time_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_period_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Verify if a period time is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate period duration in us + * \param dir Sub unit direction + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only one period time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate period duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + + +/** + * \brief Restrict a configuration space with a minimum period time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum period duration in us (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space with a maximum period time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum period duration in us (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to have period times in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum period duration in us (on return filled with actual minimum) + * \param mindir Sub unit direction for minimum (on return filled with actual direction) + * \param max approximate maximum period duration in us (on return filled with actual maximum) + * \param maxdir Sub unit direction for maximum (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact min/max is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir) +{ + return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, min, mindir, max, maxdir); +} + +/** + * \brief Restrict a configuration space to have period time nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target period duration in us / returned chosen approximate target period duration + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_period_time_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its minimum period time + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate period duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_period_time_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_period_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its maximum period time + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned maximum approximate period time + * \param dir Sub unit direction + * \return approximate period duration in us + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_period_time_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_period_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir); +} + + +/** + * \brief Extract period size from a configuration space + * \param params Configuration space + * \param val Returned approximate period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_period_size)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#else +int snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Extract minimum period size from a configuration space + * \param params Configuration space + * \param val approximate minimum period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_period_size_min)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#else +int snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#endif +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Extract maximum period size from a configuration space + * \param params Configuration space + * \param val approximate minimum period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_period_size_max)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#else +int snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#endif +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Verify if a period size is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate period size in frames + * \param dir Sub unit direction + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_PERIOD_SIZE, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only one period size + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, val, dir); +} + +/** + * \brief Restrict a configuration space with a minimum period size + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum period size in frames (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space with a maximum period size + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum period size in frames (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to have period sizes in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum period size in frames (on return filled with actual minimum) + * \param mindir Sub unit direction for minimum (on return filled with actual direction) + * \param max approximate maximum period size in frames (on return filled with actual maximum) + * \param maxdir Sub unit direction for maximum (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact min/max is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir) +{ + unsigned int _min = *min; + unsigned int _max = *max; + int err = snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, &_min, mindir, &_max, maxdir); + *min = _min; + *max = _max; + return err; +} + +/** + * \brief Restrict a configuration space to have period size nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target period size in frames / returned chosen approximate target period size + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_period_size_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#else +int snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#endif +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to contain only its minimum period size + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned maximum approximate period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_period_size_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#else +int snd_pcm_hw_params_set_period_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to contain only its maximum period size + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned maximum approximate period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_period_size_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#else +int snd_pcm_hw_params_set_period_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to contain only integer period sizes + * \param pcm PCM handle + * \param params Configuration space + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_param_set_integer(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE); +} + + +/** + * \brief Extract periods from a configuration space + * \param params Configuration space + * \param val approximate periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_periods)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Extract minimum periods count from a configuration space + * \param params Configuration space + * \param val approximate minimum periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_periods_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_periods_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Extract maximum periods count from a configuration space + * \param params Configuration space + * \param val approximate maximum periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_periods_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_periods_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Verify if a periods count is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate periods per buffer + * \param dir Sub unit direction + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only one periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space with a minimum periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum periods per buffer (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space with a maximum periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum periods per buffer (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space to have periods counts in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum periods per buffer (on return filled with actual minimum) + * \param mindir Sub unit direction for minimum (on return filled with actual direction) + * \param max approximate maximum periods per buffer (on return filled with actual maximum) + * \param maxdir Sub unit direction for maximum (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact min/max is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir) +{ + return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, min, mindir, max, maxdir); +} + +/** + * \brief Restrict a configuration space to have periods count nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target periods per buffer / returned chosen approximate target periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_periods_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its minimum periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate minimum periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_periods_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_periods_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its maximum periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate maximum periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_periods_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_periods_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_PERIODS, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only integer periods counts + * \param pcm PCM handle + * \param params Configuration space + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_param_set_integer(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS); +} + + +/** + * \brief Extract buffer time from a configuration space + * \param params Configuration space + * \param val Returned buffer time in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_buffer_time)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Extract minimum buffer time from a configuration space + * \param params Configuration space + * \param val approximate minimum buffer duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_buffer_time_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_buffer_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Extract maximum buffer time from a configuration space + * \param params Configuration space + * \param val approximate maximum buffer duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_buffer_time_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_get_buffer_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Verify if a buffer time is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate buffer duration in us + * \param dir Sub unit direction + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only one buffer time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate buffer duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space with a minimum buffer time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum buffer duration in us (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space with a maximum buffer time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum buffer duration in us (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to have buffer times in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum buffer duration in us (on return filled with actual minimum) + * \param mindir Sub unit direction for minimum (on return filled with actual direction) + * \param max approximate maximum buffer duration in us (on return filled with actual maximum) + * \param maxdir Sub unit direction for maximum (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact min/max is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir) +{ + return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, min, mindir, max, maxdir); +} + +/** + * \brief Restrict a configuration space to have buffer time nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target buffer duration in us / returned chosen approximate target buffer duration + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its minimum buffer time + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate minimum buffer duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_buffer_time_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_buffer_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + +/** + * \brief Restrict a configuration space to contain only its maximum buffered time + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate maximum buffer duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_buffer_time_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#else +int snd_pcm_hw_params_set_buffer_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir); +} + + +/** + * \brief Extract buffer size from a configuration space + * \param params Configuration space + * \param val Returned buffer size in frames + * \return 0 otherwise a negative error code if not exactly one is present + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_buffer_size)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Extract minimum buffer size from a configuration space + * \param params Configuration space + * \param val Returned approximate minimum buffer size in frames + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_buffer_size_min)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Extract maximum buffer size from a configuration space + * \param params Configuration space + * \param val Returned approximate maximum buffer size in frames + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_buffer_size_max)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Verify if a buffer size is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val buffer size in frames + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_BUFFER_SIZE, val, 0); +} + +/** + * \brief Restrict a configuration space to contain only one buffer size + * \param pcm PCM handle + * \param params Configuration space + * \param val buffer size in frames + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val) +{ + return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, val, 0); +} + +/** + * \brief Restrict a configuration space with a minimum buffer size + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum buffer size in frames (on return filled with actual minimum) + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space with a maximum buffer size + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum buffer size in frames (on return filled with actual maximum) + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to have buffer sizes in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum buffer size in frames (on return filled with actual minimum) + * \param max approximate maximum buffer size in frames (on return filled with actual maximum) + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max) +{ + unsigned int _min = *min; + unsigned int _max = *max; + int err = snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, &_min, NULL, &_max, NULL); + *min = _min; + *max = _max; + return err; +} + +/** + * \brief Restrict a configuration space to have buffer size nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target buffer size in frames / returned chosen approximate target buffer size in frames + * \return 0 otherwise a negative error code if configuration space is empty + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_buffer_size_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + unsigned int _val = *val; + int err = snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to contain only its minimum buffer size + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned minimum buffer size in frames + * \return buffer size in frames + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_buffer_size_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_hw_params_set_buffer_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + +/** + * \brief Restrict a configuration space to contain only its maximum buffer size + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned maximum buffer size in frames + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_buffer_size_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_hw_params_set_buffer_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + unsigned int _val; + int err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL); + if (err >= 0) + *val = _val; + return err; +} + + +/** + * \brief (DEPRECATED) Extract tick time from a configuration space + * \param params Configuration space + * \param val Returned approximate tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_tick_time)(const snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val, int *dir ATTRIBUTE_UNUSED) +#else +int snd_pcm_hw_params_get_tick_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + *val = 0; + return 0; +} + +/** + * \brief (DEPRECATED) Extract minimum tick time from a configuration space + * \param params Configuration space + * \param val Returned approximate minimum tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_tick_time_min)(const snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val, int *dir ATTRIBUTE_UNUSED) +#else +int snd_pcm_hw_params_get_tick_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + *val = 0; + return 0; +} + +/** + * \brief (DEPRECATED) Extract maximum tick time from a configuration space + * \param params Configuration space + * \param val Returned approximate maximum tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_get_tick_time_max)(const snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val, int *dir ATTRIBUTE_UNUSED) +#else +int snd_pcm_hw_params_get_tick_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + *val = 0; + return 0; +} + +/** + * \brief (DEPRECATED) Verify if a tick time is available inside a configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate tick duration in us + * \param dir Sub unit direction + * \return 0 if available a negative error code otherwise + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_test_tick_time(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int val, int dir ATTRIBUTE_UNUSED) +{ + return val ? -EINVAL : 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space to contain only one tick time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_tick_time(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int val ATTRIBUTE_UNUSED, int dir ATTRIBUTE_UNUSED) +{ + return 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space with a minimum tick time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate minimum tick duration in us (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_tick_time_min(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val ATTRIBUTE_UNUSED, int *dir ATTRIBUTE_UNUSED) +{ + return 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space with a maximum tick time + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum tick duration in us (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_tick_time_max(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val ATTRIBUTE_UNUSED, int *dir ATTRIBUTE_UNUSED) +{ + return 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space to have tick times in a given range + * \param pcm PCM handle + * \param params Configuration space + * \param min approximate minimum tick duration in us (on return filled with actual minimum) + * \param mindir Sub unit direction for minimum (on return filled with actual direction) + * \param max approximate maximum tick duration in us (on return filled with actual maximum) + * \param maxdir Sub unit direction for maximum (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact min/max is <,=,> val following dir (-1,0,1) + */ +int snd_pcm_hw_params_set_tick_time_minmax(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *min ATTRIBUTE_UNUSED, int *mindir ATTRIBUTE_UNUSED, unsigned int *max ATTRIBUTE_UNUSED, int *maxdir ATTRIBUTE_UNUSED) +{ + return 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space to have tick time nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target tick duration in us / returned chosen approximate target tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_tick_time_near)(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val ATTRIBUTE_UNUSED, int *dir ATTRIBUTE_UNUSED) +#else +int snd_pcm_hw_params_set_tick_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space to contain only its minimum tick time + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate minimum tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_tick_time_first)(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val ATTRIBUTE_UNUSED, int *dir ATTRIBUTE_UNUSED) +#else +int snd_pcm_hw_params_set_tick_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return 0; +} + +/** + * \brief (DEPRECATED) Restrict a configuration space to contain only its maximum tick time + * \param pcm PCM handle + * \param params Configuration space + * \param val Returned approximate maximum tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_hw_params_set_tick_time_last)(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val ATTRIBUTE_UNUSED, int *dir ATTRIBUTE_UNUSED) +#else +int snd_pcm_hw_params_set_tick_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +#endif +{ + return 0; +} + +/** + * \brief Get the minimum transfer align value in samples + * \param params Configuration space + * \param val Returned minimum align value + * \return 0 otherwise a negative error code if not exactly one is present + */ +int snd_pcm_hw_params_get_min_align(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +{ + unsigned int format, channels, fb, min_align; + int err; + + err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_FORMAT, &format, NULL); + if (err < 0) + return err; + err = snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_CHANNELS, &channels, NULL); + if (err < 0) + return err; + // compute frame bits + fb = snd_pcm_format_physical_width((snd_pcm_format_t)format) * channels; + min_align = 1; + while (fb % 8) { + fb *= 2; + min_align *= 2; + } + if (val) + *val = min_align; + return 0; +} + +/** + * \brief Return current software configuration for a PCM + * \param pcm PCM handle + * \param params Software configuration container + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) +{ + assert(pcm && params); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + params->tstamp_mode = pcm->tstamp_mode; + params->period_step = pcm->period_step; + params->sleep_min = 0; + params->avail_min = pcm->avail_min; + params->period_event = pcm->period_event; + params->xfer_align = 1; + params->start_threshold = pcm->start_threshold; + params->stop_threshold = pcm->stop_threshold; + params->silence_threshold = pcm->silence_threshold; + params->silence_size = pcm->silence_size; + params->boundary = pcm->boundary; + return 0; +} + +/** + * \brief Dump a software configuration + * \param params Software configuration container + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_sw_params_dump(snd_pcm_sw_params_t *params, snd_output_t *out) +{ + snd_output_printf(out, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(params->tstamp_mode)); + snd_output_printf(out, "period_step: %u\n", params->period_step); + snd_output_printf(out, "avail_min: %lu\n", params->avail_min); + snd_output_printf(out, "start_threshold: %ld\n", params->start_threshold); + snd_output_printf(out, "stop_threshold: %ld\n", params->stop_threshold); + snd_output_printf(out, "silence_threshold: %lu\n", params->silence_threshold); + snd_output_printf(out, "silence_size: %lu\n", params->silence_size); + snd_output_printf(out, "boundary: %lu\n", params->boundary); + return 0; +} + +/** + * \brief get size of #snd_pcm_sw_params_t + * \return size in bytes + */ +size_t snd_pcm_sw_params_sizeof() +{ + return sizeof(snd_pcm_sw_params_t); +} + +/** + * \brief allocate an invalid #snd_pcm_sw_params_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_sw_params_malloc(snd_pcm_sw_params_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_sw_params_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_sw_params_t + * \param obj pointer to object to free + */ +void snd_pcm_sw_params_free(snd_pcm_sw_params_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_sw_params_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get boundary for ring pointers from a software configuration container + * \param params Software configuration container + * \param val Returned boundary in frames + * \return 0 otherwise a negative error code + */ +int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +{ + assert(params); + *val = params->boundary; + return 0; +} + +/** + * \brief (DEPRECATED) Set start mode inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Start mode + * \return 0 otherwise a negative error code + */ +int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_start_t val) +{ + assert(pcm && params); + switch (val) { + case SND_PCM_START_DATA: + params->start_threshold = 1; + break; + case SND_PCM_START_EXPLICIT: + params->start_threshold = pcm->boundary; + break; + default: + SNDMSG("invalid start mode value %d\n", val); + return -EINVAL; + } + return 0; +} + +#ifndef DOC_HIDDEN +link_warning(snd_pcm_sw_params_set_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold"); +#endif + +/** + * \brief (DEPRECATED) Get start mode from a software configuration container + * \param params Software configuration container + * \return start mode + */ +snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *params) +{ + assert(params); + /* FIXME: Ugly */ + return params->start_threshold > 1024 * 1024 ? SND_PCM_START_EXPLICIT : SND_PCM_START_DATA; +} + +#ifndef DOC_HIDDEN +link_warning(snd_pcm_sw_params_get_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold"); +#endif + +/** + * \brief (DEPRECATED) Set xrun mode inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Xrun mode + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val) +#else +int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val) +#endif +{ + assert(pcm && params); + switch (val) { + case SND_PCM_XRUN_STOP: + params->stop_threshold = pcm->buffer_size; + break; + case SND_PCM_XRUN_NONE: + params->stop_threshold = pcm->boundary; + break; + default: + SNDMSG("invalid xrun mode value %d\n", val); + return -EINVAL; + } + return 0; +} + +#ifndef DOC_HIDDEN +link_warning(snd_pcm_sw_params_set_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold"); +#endif + +/** + * \brief (DEPRECATED) Get xrun mode from a software configuration container + * \param params Software configuration container + * \return xrun mode + */ +snd_pcm_xrun_t snd_pcm_sw_params_get_xrun_mode(const snd_pcm_sw_params_t *params) +{ + assert(params); + /* FIXME: Ugly */ + return params->stop_threshold > 1024 * 1024 ? SND_PCM_XRUN_NONE : SND_PCM_XRUN_STOP; +} + +#ifndef DOC_HIDDEN +link_warning(snd_pcm_sw_params_get_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold"); +#endif + +/** + * \brief Set timestamp mode inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Timestamp mode + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val) +#else +int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val) +#endif +{ + assert(pcm && params); + if (CHECK_SANITY(val > SND_PCM_TSTAMP_LAST)) { + SNDMSG("invalid tstamp_mode value %d", val); + return -EINVAL; + } + params->tstamp_mode = val; + return 0; +} + +/** + * \brief Get timestamp mode from a software configuration container + * \param params Software configuration container + * \param val Returned timestamp + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_tstamp_mode)(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val) +#else +int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val) +#endif +{ + assert(params && val); + *val = params->tstamp_mode; + return 0; +} + +/** + * \brief (DEPRECATED) Set minimum number of ticks to sleep inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Minimum ticks to sleep or 0 to disable the use of tick timer + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED, unsigned int val ATTRIBUTE_UNUSED) +#else +int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, unsigned int val) +#endif +{ + return 0; +} + +/** + * \brief (DEPRECATED) Get minimum numbers of ticks to sleep from a software configuration container + * \param params Software configuration container + * \param val returned minimum number of ticks to sleep or 0 if tick timer is disabled + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_sleep_min)(const snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED, unsigned int *val) +#else +int snd_pcm_sw_params_get_sleep_min(const snd_pcm_sw_params_t *params, unsigned int *val) +#endif +{ + *val = 0; + return 0; +} + +/** + * \brief Set avail min inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Minimum avail frames to consider PCM ready + * \return 0 otherwise a negative error code + * + * Note: This is similar to setting an OSS wakeup point. The valid + * values for 'val' are determined by the specific hardware. Most PC + * sound cards can only accept power of 2 frame counts (i.e. 512, + * 1024, 2048). You cannot use this as a high resolution timer - it + * is limited to how often the sound card hardware raises an + * interrupt. + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#else +int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#endif +{ + assert(pcm && params); + /* Fix avail_min if it's below period size. The period_size + * defines the minimal wake-up timing accuracy, so it doesn't + * make sense to set below that. + */ + if (val < pcm->period_size) + val = pcm->period_size; + params->avail_min = val; + return 0; +} + +/** + * \brief Get avail min from a software configuration container + * \param params Software configuration container + * \param val returned minimum available frames to consider PCM ready + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_avail_min)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + assert(params && val); + *val = params->avail_min; + return 0; +} + +/** + * \brief Set period event inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val 0 = disable period event, 1 = enable period event + * \return 0 otherwise a negative error code + * + * An poll (select) wakeup event is raised if enabled. + */ +int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val) +{ + assert(pcm && params); + params->period_event = val; + return 0; +} + +/** + * \brief Get period event from a software configuration container + * \param params Software configuration container + * \param val returned period event state + * \return 0 otherwise a negative error code + */ +int snd_pcm_sw_params_get_period_event(const snd_pcm_sw_params_t *params, int *val) +{ + assert(params && val); + *val = params->period_event; + return 0; +} + +/** + * \brief (DEPRECATED) Set xfer align inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Chunk size (frames are attempted to be transferred in chunks) + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED, snd_pcm_uframes_t val ATTRIBUTE_UNUSED) +#else +int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#endif +{ + return 0; +} + +/** + * \brief (DEPRECATED) Get xfer align from a software configuration container + * \param params Software configuration container + * \param val returned chunk size (frames are attempted to be transferred in chunks) + * \return 0 otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_xfer_align)(const snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED, snd_pcm_uframes_t *val) +#else +int snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + *val = 1; + return 0; +} + +/** + * \brief Set start threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Start threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically started when playback frames available to PCM + * are >= threshold or when requested capture frames are >= threshold + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#else +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#endif +{ + assert(pcm && params); + params->start_threshold = val; + return 0; +} + +/** + * \brief Get start threshold from a software configuration container + * \param params Software configuration container + * \param val Returned start threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically started when playback frames available to PCM + * are >= threshold or when requested capture frames are >= threshold + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_start_threshold)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + assert(params); + *val = params->start_threshold; + return 0; +} + + +/** + * \brief Set stop threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Stop threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available + * frames is >= threshold. If the stop threshold is equal to boundary (also + * software parameter - sw_param) then automatic stop will be disabled + * (thus device will do the endless loop in the ring buffer). + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#else +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#endif +{ + assert(pcm && params); + params->stop_threshold = val; + return 0; +} + +/** + * \brief Get stop threshold from a software configuration container + * \param params Software configuration container + * \param val Returned stop threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available + * frames is >= threshold. If the stop threshold is equal to boundary (also + * software parameter - sw_param) then automatic stop will be disabled + * (thus device will do the endless loop in the ring buffer). + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_stop_threshold)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + assert(params); + *val = params->stop_threshold; + return 0; +} + + +/** + * \brief Set silence threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Silence threshold in frames + * \return 0 otherwise a negative error code + * + * A portion of playback buffer is overwritten with silence (see + * #snd_pcm_sw_params_set_silence_size) when playback underrun is nearer + * than silence threshold. + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#else +int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#endif +{ + assert(pcm && params); + if (CHECK_SANITY(val >= pcm->buffer_size)) { + SNDMSG("invalid silent_threshold value %ld (buffer_size = %ld)", + val, pcm->buffer_size); + return -EINVAL; + } + params->silence_threshold = val; + return 0; +} + +/** + * \brief Get silence threshold from a software configuration container + * \param params Software configuration container + * \param val Returned silence threshold in frames + * \return 0 otherwise a negative error value + * + * A portion of playback buffer is overwritten with silence (see + * #snd_pcm_sw_params_set_silence_size) when playback underrun is nearer + * than silence threshold. + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_silence_threshold)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + assert(params && val); + *val = params->silence_threshold; + return 0; +} + + +/** + * \brief Set silence size inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Silence size in frames (0 for disabled) + * \return 0 otherwise a negative error code + * + * A portion of playback buffer is overwritten with silence when playback + * underrun is nearer than silence threshold (see + * #snd_pcm_sw_params_set_silence_threshold) + * + * The special case is when silence size value is equal or greater than + * boundary. The unused portion of the ring buffer (initial written samples + * are untouched) is filled with silence at start. Later, only just processed + * sample area is filled with silence. Note: silence_threshold must be set to zero. + */ +#ifndef DOXYGEN +int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#else +int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) +#endif +{ + assert(pcm && params); + if (CHECK_SANITY(val < pcm->boundary && val > pcm->buffer_size)) { + SNDMSG("invalid silence_size %ld (boundary %ld, buffer_size %ld)", + val, pcm->boundary, pcm->buffer_size); + return -EINVAL; + } + params->silence_size = val; + return 0; +} + +/** + * \brief Get silence size from a software configuration container + * \param params Software configuration container + * \param val Returned silence size in frames (0 for disabled) + * \return 0 otherwise a negative error code + * + * A portion of playback buffer is overwritten with silence when playback + * underrun is nearer than silence threshold (see + * #snd_pcm_sw_params_set_silence_threshold) + */ +#ifndef DOXYGEN +int INTERNAL(snd_pcm_sw_params_get_silence_size)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#else +int snd_pcm_sw_params_get_silence_size(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) +#endif +{ + assert(params); + *val = params->silence_size; + return 0; +} + + +/** + * \brief get size of #snd_pcm_status_t + * \return size in bytes + */ +size_t snd_pcm_status_sizeof() +{ + return sizeof(snd_pcm_status_t); +} + +/** + * \brief allocate an invalid #snd_pcm_status_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_status_malloc(snd_pcm_status_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_status_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_status_t + * \param obj pointer to object to free + */ +void snd_pcm_status_free(snd_pcm_status_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_status_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_status_copy(snd_pcm_status_t *dst, const snd_pcm_status_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get state from a PCM status container (see #snd_pcm_state) + * \param obj #snd_pcm_status_t pointer + * \return PCM state + */ +snd_pcm_state_t snd_pcm_status_get_state(const snd_pcm_status_t *obj) +{ + assert(obj); + return obj->state; +} + +/** + * \brief Get trigger timestamp from a PCM status container + * \param obj #snd_pcm_status_t pointer + * \param ptr Pointer to returned timestamp + * + * Trigger means a PCM state transition (from stopped to running or + * versa vice). It applies also to pause and suspend. In other words, + * timestamp contains time when stream started or when it was stopped. + */ +void snd_pcm_status_get_trigger_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr) +{ + assert(obj && ptr); + ptr->tv_sec = obj->trigger_tstamp.tv_sec; + ptr->tv_usec = obj->trigger_tstamp.tv_nsec / 1000L; +} + +/** + * \brief Get trigger hi-res timestamp from a PCM status container + * \param obj #snd_pcm_status_t pointer + * \param ptr Pointer to returned timestamp + * + * Trigger means a PCM state transition (from stopped to running or + * versa vice). It applies also to pause and suspend. In other words, + * timestamp contains time when stream started or when it was stopped. + */ +#ifndef DOXYGEN +void INTERNAL(snd_pcm_status_get_trigger_htstamp)(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr) +#else +void snd_pcm_status_get_trigger_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr) +#endif +{ + assert(obj && ptr); + *ptr = obj->trigger_tstamp; +} +use_default_symbol_version(__snd_pcm_status_get_trigger_htstamp, snd_pcm_status_get_trigger_htstamp, ALSA_0.9.0rc8); + +/** + * \brief Get "now" timestamp from a PCM status container + * \param obj #snd_pcm_status_t pointer + * \param ptr Pointer to returned timestamp + */ +void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr) +{ + assert(obj && ptr); + ptr->tv_sec = obj->tstamp.tv_sec; + ptr->tv_usec = obj->tstamp.tv_nsec / 1000L; +} + +/** + * \brief Get "now" hi-res timestamp from a PCM status container + * \param obj pointer to #snd_pcm_status_t + * \param ptr Pointer to returned timestamp + */ +#ifndef DOXYGEN +void INTERNAL(snd_pcm_status_get_htstamp)(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr) +#else +void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr) +#endif +{ + assert(obj && ptr); + *ptr = obj->tstamp; +} +use_default_symbol_version(__snd_pcm_status_get_htstamp, snd_pcm_status_get_htstamp, ALSA_0.9.0rc8); + +/** + * \brief Get delay from a PCM status container (see #snd_pcm_delay) + * \return Delay in frames + * + * Delay is distance between current application frame position and + * sound frame position. + * It's positive and less than buffer size in normal situation, + * negative on playback underrun and greater than buffer size on + * capture overrun. + */ +snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj) +{ + assert(obj); + return obj->delay; +} + +/** + * \brief Get number of frames available from a PCM status container (see #snd_pcm_avail_update) + * \return Number of frames ready to be read/written + */ +snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj) +{ + assert(obj); + return obj->avail; +} + +/** + * \brief Get maximum number of frames available from a PCM status container after last #snd_pcm_status call + * \return Maximum number of frames ready to be read/written + */ +snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj) +{ + assert(obj); + return obj->avail_max; +} + +/** + * \brief Get count of ADC overrange detections since last call + * \return Count of ADC overrange detections + */ +snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj) +{ + assert(obj); + return obj->overrange; +} + +/** + * \brief get size of #snd_pcm_info_t + * \return size in bytes + */ +size_t snd_pcm_info_sizeof() +{ + return sizeof(snd_pcm_info_t); +} + +/** + * \brief allocate an invalid #snd_pcm_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_info_malloc(snd_pcm_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_info_t + * \param obj pointer to object to free + */ +void snd_pcm_info_free(snd_pcm_info_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_pcm_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_pcm_info_copy(snd_pcm_info_t *dst, const snd_pcm_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief Get device from a PCM info container + * \param obj PCM info container + * \return device number + */ +unsigned int snd_pcm_info_get_device(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->device; +} + +/** + * \brief Get subdevice from a PCM info container + * \param obj PCM info container + * \return subdevice number + */ +unsigned int snd_pcm_info_get_subdevice(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->subdevice; +} + +/** + * \brief Get stream (direction) from a PCM info container + * \param obj PCM info container + * \return stream + */ +snd_pcm_stream_t snd_pcm_info_get_stream(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->stream; +} + +/** + * \brief Get card from a PCM info container + * \param obj PCM info container + * \return card number otherwise a negative error code if not associable to a card + */ +int snd_pcm_info_get_card(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->card; +} + +/** + * \brief Get id from a PCM info container + * \param obj PCM info container + * \return short id of PCM + */ +const char *snd_pcm_info_get_id(const snd_pcm_info_t *obj) +{ + assert(obj); + return (const char *)obj->id; +} + +/** + * \brief Get name from a PCM info container + * \param obj PCM info container + * \return name of PCM + */ +const char *snd_pcm_info_get_name(const snd_pcm_info_t *obj) +{ + assert(obj); + return (const char *)obj->name; +} + +/** + * \brief Get subdevice name from a PCM info container + * \param obj PCM info container + * \return name of used PCM subdevice + */ +const char *snd_pcm_info_get_subdevice_name(const snd_pcm_info_t *obj) +{ + assert(obj); + return (const char *)obj->subname; +} + +/** + * \brief Get class from a PCM info container + * \param obj PCM info container + * \return class of PCM + */ +snd_pcm_class_t snd_pcm_info_get_class(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->dev_class; +} + +/** + * \brief Get subclass from a PCM info container + * \param obj PCM info container + * \return subclass of PCM + */ +snd_pcm_subclass_t snd_pcm_info_get_subclass(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->dev_subclass; +} + +/** + * \brief Get subdevices count from a PCM info container + * \param obj PCM info container + * \return subdevices total count of PCM + */ +unsigned int snd_pcm_info_get_subdevices_count(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->subdevices_count; +} + +/** + * \brief Get available subdevices count from a PCM info container + * \param obj PCM info container + * \return available subdevices count of PCM + */ +unsigned int snd_pcm_info_get_subdevices_avail(const snd_pcm_info_t *obj) +{ + assert(obj); + return obj->subdevices_avail; +} + +/** + * \brief Get hardware synchronization ID from a PCM info container + * \param obj PCM info container + * \return hardware synchronization ID + */ +snd_pcm_sync_id_t snd_pcm_info_get_sync(const snd_pcm_info_t *obj) +{ + snd_pcm_sync_id_t res; + assert(obj); + memcpy(&res, &obj->sync, sizeof(res)); + return res; +} + +/** + * \brief Set wanted device inside a PCM info container (see #snd_ctl_pcm_info) + * \param obj PCM info container + * \param val Device number + */ +void snd_pcm_info_set_device(snd_pcm_info_t *obj, unsigned int val) +{ + assert(obj); + obj->device = val; +} + +/** + * \brief Set wanted subdevice inside a PCM info container (see #snd_ctl_pcm_info) + * \param obj PCM info container + * \param val Subdevice number + */ +void snd_pcm_info_set_subdevice(snd_pcm_info_t *obj, unsigned int val) +{ + assert(obj); + obj->subdevice = val; +} + +/** + * \brief Set wanted stream inside a PCM info container (see #snd_ctl_pcm_info) + * \param obj PCM info container + * \param val Stream + */ +void snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val) +{ + assert(obj); + obj->stream = val; +} + +/** + * \brief Application request to access a portion of direct (mmap) area + * \param pcm PCM handle + * \param areas Returned mmap channel areas + * \param offset Returned mmap area offset in area steps (== frames) + * \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit) + * \return 0 on success otherwise a negative error code + * + * It is necessary to call the snd_pcm_avail_update() function directly before + * this call. Otherwise, this function can return a wrong count of available frames. + * + * The function should be called before a sample-direct area can be accessed. + * The resulting size parameter is always less or equal to the input count of frames + * and can be zero, if no frames can be processed (the ring buffer is full). + * + * See the snd_pcm_mmap_commit() function to finish the frame processing in + * the direct areas. + */ +int snd_pcm_mmap_begin(snd_pcm_t *pcm, + const snd_pcm_channel_area_t **areas, + snd_pcm_uframes_t *offset, + snd_pcm_uframes_t *frames) +{ + snd_pcm_uframes_t cont; + snd_pcm_uframes_t f; + snd_pcm_uframes_t avail; + const snd_pcm_channel_area_t *xareas; + assert(pcm && areas && offset && frames); + xareas = snd_pcm_mmap_areas(pcm); + if (xareas == NULL) + return -EBADFD; + *areas = xareas; + *offset = *pcm->appl.ptr % pcm->buffer_size; + avail = snd_pcm_mmap_avail(pcm); + if (avail > pcm->buffer_size) + avail = pcm->buffer_size; + cont = pcm->buffer_size - *offset; + f = *frames; + if (f > avail) + f = avail; + if (f > cont) + f = cont; + *frames = f; + return 0; +} + +/** + * \brief Application has completed the access to area requested with #snd_pcm_mmap_begin + * \param pcm PCM handle + * \param offset area offset in area steps (== frames) + * \param frames area portion size in frames + * \return count of transferred frames otherwise a negative error code + * + * You should pass this function the offset value that + * snd_pcm_mmap_begin() returned. The frames parameter should hold the + * number of frames you have written or read to/from the audio + * buffer. The frames parameter must never exceed the contiguous frames + * count that snd_pcm_mmap_begin() returned. Each call to snd_pcm_mmap_begin() + * must be followed by a call to snd_pcm_mmap_commit(). + * + * Example: +\code + double phase = 0; + const snd_pcm_area_t *areas; + snd_pcm_sframes_t avail, size, commitres; + snd_pcm_uframes_t offset, frames; + int err; + + avail = snd_pcm_avail_update(pcm); + if (avail < 0) + error(avail); + // at this point, we can transfer at least 'avail' frames + + // we want to process frames in chunks (period_size) + if (avail < period_size) + goto _skip; + size = period_size; + // it is possible that contiguous areas are smaller, thus we use a loop + while (size > 0) { + frames = size; + + err = snd_pcm_mmap_begin(pcm_handle, &areas, &offset, &frames); + if (err < 0) + error(err); + // this function fills the areas from offset with count of frames + generate_sine(areas, offset, frames, &phase); + commitres = snd_pcm_mmap_commit(pcm_handle, offset, frames); + if (commitres < 0 || commitres != frames) + error(commitres >= 0 ? -EPIPE : commitres); + + size -= frames; + } + _skip: +\endcode + * + * Look to the \ref example_test_pcm "Sine-wave generator" example + * for more details about the generate_sine function. + */ +snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t frames) +{ + assert(pcm); + if (CHECK_SANITY(offset != *pcm->appl.ptr % pcm->buffer_size)) { + SNDMSG("commit offset (%ld) doesn't match with appl_ptr (%ld) %% buf_size (%ld)", + offset, *pcm->appl.ptr, pcm->buffer_size); + return -EPIPE; + } + if (CHECK_SANITY(frames > snd_pcm_mmap_avail(pcm))) { + SNDMSG("commit frames (%ld) overflow (avail = %ld)", frames, + snd_pcm_mmap_avail(pcm)); + return -EPIPE; + } + return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames); +} + +#ifndef DOC_HIDDEN + +int _snd_pcm_poll_descriptor(snd_pcm_t *pcm) +{ + assert(pcm); + return pcm->poll_fd; +} + +void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, + void *buf) +{ + unsigned int channel; + unsigned int channels = pcm->channels; + for (channel = 0; channel < channels; ++channel, ++areas) { + areas->addr = buf; + areas->first = channel * pcm->sample_bits; + areas->step = pcm->frame_bits; + } +} + +void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, + void **bufs) +{ + unsigned int channel; + unsigned int channels = pcm->channels; + for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) { + areas->addr = *bufs; + areas->first = 0; + areas->step = pcm->sample_bits; + } +} + +snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size, + snd_pcm_xfer_areas_func_t func) +{ + snd_pcm_uframes_t xfer = 0; + snd_pcm_sframes_t err = 0; + snd_pcm_state_t state; + + if (size == 0) + return 0; + + while (size > 0) { + snd_pcm_uframes_t frames; + snd_pcm_sframes_t avail; + _again: + state = snd_pcm_state(pcm); + switch (state) { + case SND_PCM_STATE_PREPARED: + err = snd_pcm_start(pcm); + if (err < 0) + goto _end; + break; + case SND_PCM_STATE_RUNNING: + err = snd_pcm_hwsync(pcm); + if (err < 0) + goto _end; + break; + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PAUSED: + break; + case SND_PCM_STATE_XRUN: + err = -EPIPE; + goto _end; + case SND_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end; + case SND_PCM_STATE_DISCONNECTED: + err = -ENODEV; + goto _end; + default: + err = -EBADFD; + goto _end; + } + avail = snd_pcm_avail_update(pcm); + if (avail < 0) { + err = avail; + goto _end; + } + if (avail == 0) { + if (state == SND_PCM_STATE_DRAINING) + goto _end; + if (pcm->mode & SND_PCM_NONBLOCK) { + err = -EAGAIN; + goto _end; + } + + err = snd_pcm_wait(pcm, -1); + if (err < 0) + break; + goto _again; + + } + frames = size; + if (frames > (snd_pcm_uframes_t) avail) + frames = avail; + if (! frames) + break; + err = func(pcm, areas, offset, frames); + if (err < 0) + break; + frames = err; + offset += frames; + size -= frames; + xfer += frames; + } + _end: + return xfer > 0 ? (snd_pcm_sframes_t) xfer : snd_pcm_check_error(pcm, err); +} + +snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size, + snd_pcm_xfer_areas_func_t func) +{ + snd_pcm_uframes_t xfer = 0; + snd_pcm_sframes_t err = 0; + snd_pcm_state_t state; + + if (size == 0) + return 0; + + while (size > 0) { + snd_pcm_uframes_t frames; + snd_pcm_sframes_t avail; + _again: + state = snd_pcm_state(pcm); + switch (state) { + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_PAUSED: + break; + case SND_PCM_STATE_RUNNING: + err = snd_pcm_hwsync(pcm); + if (err < 0) + goto _end; + break; + case SND_PCM_STATE_XRUN: + err = -EPIPE; + goto _end; + case SND_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end; + case SND_PCM_STATE_DISCONNECTED: + err = -ENODEV; + goto _end; + default: + err = -EBADFD; + goto _end; + } + avail = snd_pcm_avail_update(pcm); + if (avail < 0) { + err = avail; + goto _end; + } + if ((state == SND_PCM_STATE_RUNNING && + (snd_pcm_uframes_t)avail < pcm->avail_min && + size > (snd_pcm_uframes_t)avail)) { + if (pcm->mode & SND_PCM_NONBLOCK) { + err = -EAGAIN; + goto _end; + } + + err = snd_pcm_wait(pcm, -1); + if (err < 0) + break; + goto _again; + } + frames = size; + if (frames > (snd_pcm_uframes_t) avail) + frames = avail; + if (! frames) + break; + err = func(pcm, areas, offset, frames); + if (err < 0) + break; + frames = err; + if (state == SND_PCM_STATE_PREPARED) { + snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail; + hw_avail += frames; + /* some plugins might automatically start the stream */ + state = snd_pcm_state(pcm); + if (state == SND_PCM_STATE_PREPARED && + hw_avail >= (snd_pcm_sframes_t) pcm->start_threshold) { + err = snd_pcm_start(pcm); + if (err < 0) + goto _end; + } + } + offset += frames; + size -= frames; + xfer += frames; + } + _end: + return xfer > 0 ? (snd_pcm_sframes_t) xfer : snd_pcm_check_error(pcm, err); +} + +snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm) +{ + return *pcm->hw.ptr; +} + +snd_pcm_uframes_t _snd_pcm_boundary(snd_pcm_t *pcm) +{ + return pcm->boundary; +} + +#ifndef DOC_HIDDEN +link_warning(_snd_pcm_mmap_hw_ptr, "Warning: _snd_pcm_mmap_hw_ptr() is deprecated, consider to not use this function"); +link_warning(_snd_pcm_boundary, "Warning: _snd_pcm_boundary() is deprecated, consider to use snd_pcm_sw_params_current()"); +#endif + +static const char *const names[SND_PCM_HW_PARAM_LAST_INTERVAL + 1] = { + [SND_PCM_HW_PARAM_FORMAT] = "format", + [SND_PCM_HW_PARAM_CHANNELS] = "channels", + [SND_PCM_HW_PARAM_RATE] = "rate", + [SND_PCM_HW_PARAM_PERIOD_TIME] = "period_time", + [SND_PCM_HW_PARAM_PERIOD_SIZE] = "period_size", + [SND_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time", + [SND_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size", + [SND_PCM_HW_PARAM_PERIODS] = "periods" +}; + +int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf, + snd_config_t **_pcm_conf, unsigned int count, ...) +{ + snd_config_iterator_t i, next; + const char *str; + struct { + unsigned int index; + int flags; + void *ptr; + int present; + } fields[count]; + unsigned int k; + snd_config_t *pcm_conf = NULL; + int err; + int to_free = 0; + va_list args; + assert(root); + assert(conf); + assert(_pcm_conf); + if (snd_config_get_string(conf, &str) >= 0) { + err = snd_config_search_definition(root, "pcm_slave", str, &conf); + if (err < 0) { + SNDERR("Invalid slave definition"); + return -EINVAL; + } + to_free = 1; + } + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid slave definition"); + err = -EINVAL; + goto _err; + } + va_start(args, count); + for (k = 0; k < count; ++k) { + fields[k].index = va_arg(args, int); + fields[k].flags = va_arg(args, int); + fields[k].ptr = va_arg(args, void *); + fields[k].present = 0; + } + va_end(args); + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "pcm") == 0) { + if (pcm_conf != NULL) + snd_config_delete(pcm_conf); + if ((err = snd_config_copy(&pcm_conf, n)) < 0) + goto _err; + continue; + } + for (k = 0; k < count; ++k) { + unsigned int idx = fields[k].index; + long v; + assert(idx < SND_PCM_HW_PARAM_LAST_INTERVAL); + assert(names[idx]); + if (strcmp(id, names[idx]) != 0) + continue; + switch (idx) { + case SND_PCM_HW_PARAM_FORMAT: + { + snd_pcm_format_t f; + err = snd_config_get_string(n, &str); + if (err < 0) { + _invalid: + SNDERR("invalid type for %s", id); + goto _err; + } + if ((fields[k].flags & SCONF_UNCHANGED) && + strcasecmp(str, "unchanged") == 0) { + *(snd_pcm_format_t*)fields[k].ptr = (snd_pcm_format_t) -2; + break; + } + f = snd_pcm_format_value(str); + if (f == SND_PCM_FORMAT_UNKNOWN) { + SNDERR("unknown format %s", str); + err = -EINVAL; + goto _err; + } + *(snd_pcm_format_t*)fields[k].ptr = f; + break; + } + default: + if ((fields[k].flags & SCONF_UNCHANGED)) { + err = snd_config_get_string(n, &str); + if (err >= 0 && + strcasecmp(str, "unchanged") == 0) { + *(int*)fields[k].ptr = -2; + break; + } + } + err = snd_config_get_integer(n, &v); + if (err < 0) + goto _invalid; + *(int*)fields[k].ptr = v; + break; + } + fields[k].present = 1; + break; + } + if (k < count) + continue; + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + if (!pcm_conf) { + SNDERR("missing field pcm"); + err = -EINVAL; + goto _err; + } + for (k = 0; k < count; ++k) { + if ((fields[k].flags & SCONF_MANDATORY) && !fields[k].present) { + SNDERR("missing field %s", names[fields[k].index]); + err = -EINVAL; + goto _err; + } + } + *_pcm_conf = pcm_conf; + pcm_conf = NULL; + err = 0; + _err: + if (pcm_conf) + snd_config_delete(pcm_conf); + if (to_free) + snd_config_delete(conf); + return err; +} + + +int snd_pcm_conf_generic_id(const char *id) +{ + static const char ids[3][8] = { "comment", "type", "hint" }; + unsigned int k; + for (k = 0; k < sizeof(ids) / sizeof(ids[0]); ++k) { + if (strcmp(id, ids[k]) == 0) + return 1; + } + return 0; +} + +static void snd_pcm_set_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *rbptr, + volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset) +{ + rbptr->master = NULL; /* I'm master */ + rbptr->ptr = hw_ptr; + rbptr->fd = fd; + rbptr->offset = offset; + if (rbptr->changed) + rbptr->changed(pcm, NULL); +} + +void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset) +{ + assert(pcm); + assert(hw_ptr); + snd_pcm_set_ptr(pcm, &pcm->hw, hw_ptr, fd, offset); +} + +void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr, int fd, off_t offset) +{ + assert(pcm); + assert(appl_ptr); + snd_pcm_set_ptr(pcm, &pcm->appl, appl_ptr, fd, offset); +} + +static void snd_pcm_link_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr, + snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr) +{ + snd_pcm_t **a; + int idx; + + a = slave_rbptr->link_dst; + for (idx = 0; idx < slave_rbptr->link_dst_count; idx++) + if (a[idx] == NULL) { + a[idx] = pcm; + goto __found_free_place; + } + a = realloc(a, sizeof(snd_pcm_t *) * (slave_rbptr->link_dst_count + 1)); + if (a == NULL) { + pcm_rbptr->ptr = NULL; + pcm_rbptr->fd = -1; + pcm_rbptr->offset = 0UL; + return; + } + a[slave_rbptr->link_dst_count++] = pcm; + __found_free_place: + pcm_rbptr->master = slave_rbptr->master ? slave_rbptr->master : slave; + pcm_rbptr->ptr = slave_rbptr->ptr; + pcm_rbptr->fd = slave_rbptr->fd; + pcm_rbptr->offset = slave_rbptr->offset; + slave_rbptr->link_dst = a; + if (pcm_rbptr->changed) + pcm_rbptr->changed(pcm, slave); +} + +static void snd_pcm_unlink_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr, + snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr) +{ + snd_pcm_t **a; + int idx; + + a = slave_rbptr->link_dst; + for (idx = 0; idx < slave_rbptr->link_dst_count; idx++) { + if (a[idx] == pcm) { + a[idx] = NULL; + goto __found; + } + } + /* assert(0); */ + return; + + __found: + pcm_rbptr->master = NULL; + pcm_rbptr->ptr = NULL; + pcm_rbptr->fd = -1; + pcm_rbptr->offset = 0UL; + if (pcm_rbptr->changed) + pcm_rbptr->changed(pcm, slave); +} + +void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave) +{ + assert(pcm); + assert(slave); + snd_pcm_link_ptr(pcm, &pcm->hw, slave, &slave->hw); +} + +void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave) +{ + assert(pcm); + assert(slave); + snd_pcm_link_ptr(pcm, &pcm->appl, slave, &slave->appl); +} + +void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave) +{ + assert(pcm); + assert(slave); + snd_pcm_unlink_ptr(pcm, &pcm->hw, slave, &slave->hw); +} + +void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave) +{ + assert(pcm); + assert(slave); + snd_pcm_unlink_ptr(pcm, &pcm->appl, slave, &slave->appl); +} + +#endif /* DOC_HIDDEN */ + +/* + * + */ + +#ifndef DOC_HIDDEN + +#ifdef USE_VERSIONED_SYMBOLS + +#define OBSOLETE1(name, what, new) \ + default_symbol_version(__##name, name, new); \ + symbol_version(__old_##name, name, what); + +#else + +#define OBSOLETE1(name, what, new) \ + use_default_symbol_version(__##name, name, new); + +#endif /* USE_VERSIONED_SYMBOLS */ + +#define __P_OLD_GET(pfx, name, val_type, ret_type) \ +ret_type pfx##name(const snd_pcm_hw_params_t *params) \ +{ \ + val_type val; \ + if (INTERNAL(name)(params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __P_OLD_GET1(pfx, name, val_type, ret_type) \ +ret_type pfx##name(const snd_pcm_hw_params_t *params, int *dir) \ +{ \ + val_type val; \ + if (INTERNAL(name)(params, &val, dir) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_GET(name, val_type, ret_type) __P_OLD_GET(__old_, name, val_type, ret_type) +#define __OLD_GET1(name, val_type, ret_type) __P_OLD_GET1(__old_, name, val_type, ret_type) + +__OLD_GET(snd_pcm_hw_params_get_access, snd_pcm_access_t, int); +__OLD_GET(snd_pcm_hw_params_get_format, snd_pcm_format_t, int); +__OLD_GET(snd_pcm_hw_params_get_subformat, snd_pcm_subformat_t, int); +__OLD_GET(snd_pcm_hw_params_get_channels, unsigned int, int); +__OLD_GET1(snd_pcm_hw_params_get_rate, unsigned int, int); +__OLD_GET1(snd_pcm_hw_params_get_period_time, unsigned int, int); +__OLD_GET1(snd_pcm_hw_params_get_period_size, snd_pcm_uframes_t, snd_pcm_sframes_t); +__OLD_GET1(snd_pcm_hw_params_get_periods, unsigned int, int); +__OLD_GET1(snd_pcm_hw_params_get_buffer_time, unsigned int, int); +__OLD_GET(snd_pcm_hw_params_get_buffer_size, snd_pcm_uframes_t, snd_pcm_sframes_t); +__OLD_GET1(snd_pcm_hw_params_get_tick_time, unsigned int, int); + +__OLD_GET(snd_pcm_hw_params_get_channels_min, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_rate_min, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_period_time_min, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_period_size_min, snd_pcm_uframes_t, snd_pcm_uframes_t); +__OLD_GET1(snd_pcm_hw_params_get_periods_min, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_buffer_time_min, unsigned int, unsigned int); +__OLD_GET(snd_pcm_hw_params_get_buffer_size_min, snd_pcm_uframes_t, snd_pcm_uframes_t); +__OLD_GET1(snd_pcm_hw_params_get_tick_time_min, unsigned int, unsigned int); + +__OLD_GET(snd_pcm_hw_params_get_channels_max, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_rate_max, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_period_time_max, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_period_size_max, snd_pcm_uframes_t, snd_pcm_uframes_t); +__OLD_GET1(snd_pcm_hw_params_get_periods_max, unsigned int, unsigned int); +__OLD_GET1(snd_pcm_hw_params_get_buffer_time_max, unsigned int, unsigned int); +__OLD_GET(snd_pcm_hw_params_get_buffer_size_max, snd_pcm_uframes_t, snd_pcm_uframes_t); +__OLD_GET1(snd_pcm_hw_params_get_tick_time_max, unsigned int, unsigned int); + +#define __P_OLD_NEAR(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val) \ +{ \ + if (INTERNAL(name)(pcm, params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __P_OLD_NEAR1(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val, int *dir) \ +{ \ + if (INTERNAL(name)(pcm, params, &val, dir) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_NEAR(name, ret_type) __P_OLD_NEAR(__old_, name, ret_type) +#define __OLD_NEAR1(name, ret_type) __P_OLD_NEAR1(__old_, name, ret_type) + +__OLD_NEAR(snd_pcm_hw_params_set_channels_near, unsigned int); +__OLD_NEAR1(snd_pcm_hw_params_set_rate_near, unsigned int); +__OLD_NEAR1(snd_pcm_hw_params_set_period_time_near, unsigned int); +__OLD_NEAR1(snd_pcm_hw_params_set_period_size_near, snd_pcm_uframes_t); +__OLD_NEAR1(snd_pcm_hw_params_set_periods_near, unsigned int); +__OLD_NEAR1(snd_pcm_hw_params_set_buffer_time_near, unsigned int); +__OLD_NEAR(snd_pcm_hw_params_set_buffer_size_near, snd_pcm_uframes_t); +__OLD_NEAR1(snd_pcm_hw_params_set_tick_time_near, unsigned int); + +#define __P_OLD_SET_FL(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) \ +{ \ + ret_type val; \ + if (INTERNAL(name)(pcm, params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __P_OLD_SET_FL1(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir) \ +{ \ + ret_type val; \ + if (INTERNAL(name)(pcm, params, &val, dir) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_SET_FL(name, ret_type) __P_OLD_SET_FL(__old_, name, ret_type) +#define __OLD_SET_FL1(name, ret_type) __P_OLD_SET_FL1(__old_, name, ret_type) + +__OLD_SET_FL(snd_pcm_hw_params_set_access_first, snd_pcm_access_t); +__OLD_SET_FL(snd_pcm_hw_params_set_format_first, snd_pcm_format_t); +__OLD_SET_FL(snd_pcm_hw_params_set_subformat_first, snd_pcm_subformat_t); +__OLD_SET_FL(snd_pcm_hw_params_set_channels_first, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_rate_first, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_period_time_first, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_period_size_first, snd_pcm_uframes_t); +__OLD_SET_FL1(snd_pcm_hw_params_set_periods_first, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_buffer_time_first, unsigned int); +__OLD_SET_FL(snd_pcm_hw_params_set_buffer_size_first, snd_pcm_uframes_t); +__OLD_SET_FL1(snd_pcm_hw_params_set_tick_time_first, unsigned int); + +__OLD_SET_FL(snd_pcm_hw_params_set_access_last, snd_pcm_access_t); +__OLD_SET_FL(snd_pcm_hw_params_set_format_last, snd_pcm_format_t); +__OLD_SET_FL(snd_pcm_hw_params_set_subformat_last, snd_pcm_subformat_t); +__OLD_SET_FL(snd_pcm_hw_params_set_channels_last, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_rate_last, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_period_time_last, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_period_size_last, snd_pcm_uframes_t); +__OLD_SET_FL1(snd_pcm_hw_params_set_periods_last, unsigned int); +__OLD_SET_FL1(snd_pcm_hw_params_set_buffer_time_last, unsigned int); +__OLD_SET_FL(snd_pcm_hw_params_set_buffer_size_last, snd_pcm_uframes_t); +__OLD_SET_FL1(snd_pcm_hw_params_set_tick_time_last, unsigned int); + +#define __P_OLD_GET_SW(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_sw_params_t *params) \ +{ \ + ret_type val; \ + if (INTERNAL(name)(params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_GET_SW(name, ret_type) __P_OLD_GET_SW(__old_, name, ret_type) + +__OLD_GET_SW(snd_pcm_sw_params_get_tstamp_mode, snd_pcm_tstamp_t); +__OLD_GET_SW(snd_pcm_sw_params_get_sleep_min, unsigned int); +__OLD_GET_SW(snd_pcm_sw_params_get_avail_min, snd_pcm_uframes_t); +__OLD_GET_SW(snd_pcm_sw_params_get_xfer_align, snd_pcm_uframes_t); +__OLD_GET_SW(snd_pcm_sw_params_get_start_threshold, snd_pcm_uframes_t); +__OLD_GET_SW(snd_pcm_sw_params_get_stop_threshold, snd_pcm_uframes_t); +__OLD_GET_SW(snd_pcm_sw_params_get_silence_threshold, snd_pcm_uframes_t); +__OLD_GET_SW(snd_pcm_sw_params_get_silence_size, snd_pcm_uframes_t); + +OBSOLETE1(snd_pcm_hw_params_get_access, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_access_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_access_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_format, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_format_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_format_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_subformat, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_subformat_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_subformat_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_channels, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_channels_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_channels_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_channels_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_channels_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_channels_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_rate, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_rate_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_rate_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_rate_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_rate_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_rate_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_period_time, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_period_time_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_period_time_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_period_time_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_period_time_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_period_time_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_period_size, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_period_size_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_period_size_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_period_size_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_period_size_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_period_size_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_periods, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_periods_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_periods_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_periods_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_periods_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_periods_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_buffer_time, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_buffer_time_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_buffer_time_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_buffer_time_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_buffer_time_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_buffer_time_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_buffer_size, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_buffer_size_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_buffer_size_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_buffer_size_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_buffer_size_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_buffer_size_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_hw_params_get_tick_time, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_tick_time_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_get_tick_time_max, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_tick_time_near, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_tick_time_first, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_hw_params_set_tick_time_last, ALSA_0.9, ALSA_0.9.0rc4); + +OBSOLETE1(snd_pcm_sw_params_get_tstamp_mode, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_sleep_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_avail_min, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_xfer_align, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_start_threshold, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_stop_threshold, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_silence_threshold, ALSA_0.9, ALSA_0.9.0rc4); +OBSOLETE1(snd_pcm_sw_params_get_silence_size, ALSA_0.9, ALSA_0.9.0rc4); + +#endif /* DOC_HIDDEN */ + +/* + * basic helpers + */ + + +/** + * \brief Recover the stream state from an error or suspend + * \param pcm PCM handle + * \param err error number + * \param silent do not print error reason + * \return 0 when error code was handled successfuly, otherwise a negative error code + * + * This a high-level helper function building on other functions. + * + * This functions handles -EINTR (interrupted system call), + * -EPIPE (overrun or underrun) and -ESTRPIPE (stream is suspended) + * error codes trying to prepare given stream for next I/O. + * + * Note that this function returs the original error code when it is not + * handled inside this function (for example -EAGAIN is returned back). + */ +int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent) +{ + if (err > 0) + err = -err; + if (err == -EINTR) /* nothing to do, continue */ + return 0; + if (err == -EPIPE) { + const char *s; + if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK) + s = "underrun"; + else + s = "overrun"; + if (!silent) + SNDERR("%s occurred", s); + err = snd_pcm_prepare(pcm); + if (err < 0) { + SNDERR("cannot recovery from %s, prepare failed: %s", s, snd_strerror(err)); + return err; + } + return 0; + } + if (err == -ESTRPIPE) { + while ((err = snd_pcm_resume(pcm)) == -EAGAIN) + /* wait until suspend flag is released */ + poll(NULL, 0, 1000); + if (err < 0) { + err = snd_pcm_prepare(pcm); + if (err < 0) { + SNDERR("cannot recovery from suspend, prepare failed: %s", snd_strerror(err)); + return err; + } + } + return 0; + } + return err; +} + +/** + * \brief Set the hardware and software parameters in a simple way + * \param pcm PCM handle + * \param format required PCM format + * \param access required PCM access + * \param channels required PCM channels + * \param rate required sample rate in Hz + * \param soft_resample 0 = disallow alsa-lib resample stream, 1 = allow resampling + * \param latency required overall latency in us + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_set_params(snd_pcm_t *pcm, + snd_pcm_format_t format, + snd_pcm_access_t access, + unsigned int channels, + unsigned int rate, + int soft_resample, + unsigned int latency) +{ + snd_pcm_hw_params_t *params; + snd_pcm_sw_params_t *swparams; + const char *s = snd_pcm_stream_name(snd_pcm_stream(pcm)); + snd_pcm_uframes_t buffer_size, period_size; + unsigned int rrate, period_time; + int err; + + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_sw_params_alloca(&swparams); + + assert(pcm); + /* choose all parameters */ + err = snd_pcm_hw_params_any(pcm, params); + if (err < 0) { + SNDERR("Broken configuration for %s: no configurations available", s); + return err; + } + /* set software resampling */ + err = snd_pcm_hw_params_set_rate_resample(pcm, params, soft_resample); + if (err < 0) { + SNDERR("Resampling setup failed for %s: %s", s, snd_strerror(err)); + return err; + } + /* set the selected read/write format */ + err = snd_pcm_hw_params_set_access(pcm, params, access); + if (err < 0) { + SNDERR("Access type not available for %s: %s", s, snd_strerror(err)); + return err; + } + /* set the sample format */ + err = snd_pcm_hw_params_set_format(pcm, params, format); + if (err < 0) { + SNDERR("Sample format not available for %s: %s", s, snd_strerror(err)); + return err; + } + /* set the count of channels */ + err = snd_pcm_hw_params_set_channels(pcm, params, channels); + if (err < 0) { + SNDERR("Channels count (%i) not available for %s: %s", channels, s, snd_strerror(err)); + return err; + } + /* set the stream rate */ + rrate = rate; + err = INTERNAL(snd_pcm_hw_params_set_rate_near)(pcm, params, &rrate, 0); + if (err < 0) { + SNDERR("Rate %iHz not available for playback: %s", rate, snd_strerror(err)); + return err; + } + if (rrate != rate) { + SNDERR("Rate doesn't match (requested %iHz, get %iHz)", rate, err); + return -EINVAL; + } + /* set the buffer time */ + err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, params, &latency, NULL); + if (err < 0) { + /* error path -> set period size as first */ + /* set the period time */ + period_time = latency / 4; + err = INTERNAL(snd_pcm_hw_params_set_period_time_near)(pcm, params, &period_time, NULL); + if (err < 0) { + SNDERR("Unable to set period time %i for %s: %s", period_time, s, snd_strerror(err)); + return err; + } + err = INTERNAL(snd_pcm_hw_params_get_period_size)(params, &period_size, NULL); + if (err < 0) { + SNDERR("Unable to get period size for %s: %s", s, snd_strerror(err)); + return err; + } + buffer_size = period_size * 4; + err = INTERNAL(snd_pcm_hw_params_set_buffer_size_near)(pcm, params, &buffer_size); + if (err < 0) { + SNDERR("Unable to set buffer size %lu %s: %s", buffer_size, s, snd_strerror(err)); + return err; + } + err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &buffer_size); + if (err < 0) { + SNDERR("Unable to get buffer size for %s: %s", s, snd_strerror(err)); + return err; + } + } else { + /* standard configuration buffer_time -> periods */ + err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &buffer_size); + if (err < 0) { + SNDERR("Unable to get buffer size for %s: %s", s, snd_strerror(err)); + return err; + } + err = INTERNAL(snd_pcm_hw_params_get_buffer_time)(params, &latency, NULL); + if (err < 0) { + SNDERR("Unable to get buffer time (latency) for %s: %s", s, snd_strerror(err)); + return err; + } + /* set the period time */ + period_time = latency / 4; + err = INTERNAL(snd_pcm_hw_params_set_period_time_near)(pcm, params, &period_time, NULL); + if (err < 0) { + SNDERR("Unable to set period time %i for %s: %s", period_time, s, snd_strerror(err)); + return err; + } + err = INTERNAL(snd_pcm_hw_params_get_period_size)(params, &period_size, NULL); + if (err < 0) { + SNDERR("Unable to get period size for %s: %s", s, snd_strerror(err)); + return err; + } + } + /* write the parameters to device */ + err = snd_pcm_hw_params(pcm, params); + if (err < 0) { + SNDERR("Unable to set hw params for %s: %s", s, snd_strerror(err)); + return err; + } + + /* get the current swparams */ + err = snd_pcm_sw_params_current(pcm, swparams); + if (err < 0) { + SNDERR("Unable to determine current swparams for %s: %s", s, snd_strerror(err)); + return err; + } + /* start the transfer when the buffer is almost full: */ + /* (buffer_size / avail_min) * avail_min */ + err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (buffer_size / period_size) * period_size); + if (err < 0) { + SNDERR("Unable to set start threshold mode for %s: %s", s, snd_strerror(err)); + return err; + } + /* allow the transfer when at least period_size samples can be processed */ + err = snd_pcm_sw_params_set_avail_min(pcm, swparams, period_size); + if (err < 0) { + SNDERR("Unable to set avail min for %s: %s", s, snd_strerror(err)); + return err; + } + /* write the parameters to the playback device */ + err = snd_pcm_sw_params(pcm, swparams); + if (err < 0) { + SNDERR("Unable to set sw params for %s: %s", s, snd_strerror(err)); + return err; + } + return 0; +} + +/** + * \brief Get the transfer size parameters in a simple way + * \param pcm PCM handle + * \param buffer_size PCM ring buffer size in frames + * \param period_size PCM period size in frames + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_get_params(snd_pcm_t *pcm, + snd_pcm_uframes_t *buffer_size, + snd_pcm_uframes_t *period_size) +{ + snd_pcm_hw_params_t *hw; + int err; + + assert(pcm); + snd_pcm_hw_params_alloca(&hw); + err = snd_pcm_hw_params_current(pcm, hw); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(hw, buffer_size); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_period_size)(hw, period_size, NULL); + if (err < 0) + return err; + return 0; +} diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c new file mode 100644 index 0000000..b68007f --- /dev/null +++ b/src/pcm/pcm_adpcm.c @@ -0,0 +1,679 @@ +/** + * \file pcm/pcm_adpcm.c + * \ingroup PCM_Plugins + * \brief PCM Ima-ADPCM Conversion Plugin Interface + * \author Abramo Bagnara + * \author Uros Bizjak + * \author Jaroslav Kysela + * \date 2000-2001 + */ +/* + * PCM - Ima-ADPCM conversion + * Copyright (c) 2000 by Abramo Bagnara + * Copyright (c) 1999 by Uros Bizjak + * Jaroslav Kysela + * + * Based on Version 1.2, 18-Dec-92 implementation of Intel/DVI ADPCM code + * by Jack Jansen, CWI, Amsterdam , Copyright 1992 + * by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* +These routines convert 16 bit linear PCM samples to 4 bit ADPCM code +and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which +is being recommended by the IMA Digital Audio Technical Working Group. + +The algorithm for this coder was taken from: +Proposal for Standardized Audio Interstreamge Formats, +IMA compatibility project proceedings, Vol 2, Issue 2, May 1992. + +- No, this is *not* a G.721 coder/decoder. The algorithm used by G.721 + is very complicated, requiring oodles of floating-point ops per + sample (resulting in very poor performance). I have not done any + tests myself but various people have assured my that 721 quality is + actually lower than DVI quality. + +- No, it probably isn't a RIFF ADPCM decoder either. Trying to decode + RIFF ADPCM with these routines seems to result in something + recognizable but very distorted. + +- No, it is not a CDROM-XA coder either, as far as I know. I haven't + come across a good description of XA yet. + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_adpcm = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef void (*adpcm_f)(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getputidx, + snd_pcm_adpcm_state_t *states); + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + unsigned int getput_idx; + adpcm_f func; + snd_pcm_format_t sformat; + snd_pcm_adpcm_state_t *states; +} snd_pcm_adpcm_t; + +#endif + +/* First table lookup for Ima-ADPCM quantizer */ +static const char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; + +/* Second table lookup for Ima-ADPCM quantizer */ +static const short StepSize[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +static char adpcm_encoder(int sl, snd_pcm_adpcm_state_t * state) +{ + short diff; /* Difference between sl and predicted sample */ + short pred_diff; /* Predicted difference to next sample */ + + unsigned char sign; /* sign of diff */ + short step; /* holds previous StepSize value */ + unsigned char adjust_idx; /* Index to IndexAdjust lookup table */ + + int i; + + /* Compute difference to previous predicted value */ + diff = sl - state->pred_val; + sign = (diff < 0) ? 0x8 : 0x0; + if (sign) { + diff = -diff; + } + + /* + * This code *approximately* computes: + * adjust_idx = diff * 4 / step; + * pred_diff = (adjust_idx + 0.5) * step / 4; + * + * But in shift step bits are dropped. The net result of this is + * that even if you have fast mul/div hardware you cannot put it to + * good use since the fix-up would be too expensive. + */ + + step = StepSize[state->step_idx]; + + /* Divide and clamp */ + pred_diff = step >> 3; + for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) { + if (diff >= step) { + adjust_idx |= i; + diff -= step; + pred_diff += step; + } + } + + /* Update and clamp previous predicted value */ + state->pred_val += sign ? -pred_diff : pred_diff; + + if (state->pred_val > 32767) { + state->pred_val = 32767; + } else if (state->pred_val < -32768) { + state->pred_val = -32768; + } + + /* Update and clamp StepSize lookup table index */ + state->step_idx += IndexAdjust[adjust_idx]; + + if (state->step_idx < 0) { + state->step_idx = 0; + } else if (state->step_idx > 88) { + state->step_idx = 88; + } + return (sign | adjust_idx); +} + + +static int adpcm_decoder(unsigned char code, snd_pcm_adpcm_state_t * state) +{ + short pred_diff; /* Predicted difference to next sample */ + short step; /* holds previous StepSize value */ + char sign; + + int i; + + /* Separate sign and magnitude */ + sign = code & 0x8; + code &= 0x7; + + /* + * Computes pred_diff = (code + 0.5) * step / 4, + * but see comment in adpcm_coder. + */ + + step = StepSize[state->step_idx]; + + /* Compute difference and new predicted value */ + pred_diff = step >> 3; + for (i = 0x4; i; i >>= 1, step >>= 1) { + if (code & i) { + pred_diff += step; + } + } + state->pred_val += (sign) ? -pred_diff : pred_diff; + + /* Clamp output value */ + if (state->pred_val > 32767) { + state->pred_val = 32767; + } else if (state->pred_val < -32768) { + state->pred_val = -32768; + } + + /* Find new StepSize index value */ + state->step_idx += IndexAdjust[code]; + + if (state->step_idx < 0) { + state->step_idx = 0; + } else if (state->step_idx > 88) { + state->step_idx = 88; + } + return (state->pred_val); +} + +#ifndef DOC_HIDDEN + +void snd_pcm_adpcm_decode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int putidx, + snd_pcm_adpcm_state_t *states) +{ +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS + void *put = put16_labels[putidx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel, ++states) { + const char *src; + int srcbit; + char *dst; + int src_step, srcbit_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + srcbit = src_area->first + src_area->step * src_offset; + src = (const char *) src_area->addr + srcbit / 8; + srcbit %= 8; + src_step = src_area->step / 8; + srcbit_step = src_area->step % 8; + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + int16_t sample; + unsigned char v; + if (srcbit) + v = *src & 0x0f; + else + v = (*src >> 4) & 0x0f; + sample = adpcm_decoder(v, states); + goto *put; +#define PUT16_END after +#include "plugin_ops.h" +#undef PUT16_END + after: + src += src_step; + srcbit += srcbit_step; + if (srcbit == 8) { + src++; + srcbit = 0; + } + dst += dst_step; + } + } +} + +void snd_pcm_adpcm_encode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getidx, + snd_pcm_adpcm_state_t *states) +{ +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS + void *get = get16_labels[getidx]; + unsigned int channel; + int16_t sample = 0; + for (channel = 0; channel < channels; ++channel, ++states) { + const char *src; + char *dst; + int dstbit; + int src_step, dst_step, dstbit_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + src_step = snd_pcm_channel_area_step(src_area); + dstbit = dst_area->first + dst_area->step * dst_offset; + dst = (char *) dst_area->addr + dstbit / 8; + dstbit %= 8; + dst_step = dst_area->step / 8; + dstbit_step = dst_area->step % 8; + frames1 = frames; + while (frames1-- > 0) { + int v; + goto *get; +#define GET16_END after +#include "plugin_ops.h" +#undef GET16_END + after: + v = adpcm_encoder(sample, states); + if (dstbit) + *dst = (*dst & 0xf0) | v; + else + *dst = (*dst & 0x0f) | (v << 4); + src += src_step; + dst += dst_step; + dstbit += dstbit_step; + if (dstbit == 8) { + dst++; + dstbit = 0; + } + } + } +} + +#endif + +static int snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { + snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + } else { + err = _snd_pcm_hw_params_set_format(params, + SND_PCM_FORMAT_IMA_ADPCM); + } + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, + SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, adpcm->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + return 0; +} + +static int snd_pcm_adpcm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_adpcm_hw_refine_cprepare, + snd_pcm_adpcm_hw_refine_cchange, + snd_pcm_adpcm_hw_refine_sprepare, + snd_pcm_adpcm_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + snd_pcm_format_t format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_adpcm_hw_refine_cchange, + snd_pcm_adpcm_hw_refine_sprepare, + snd_pcm_adpcm_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); + if (err < 0) + return err; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { + adpcm->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16); + adpcm->func = snd_pcm_adpcm_encode; + } else { + adpcm->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, adpcm->sformat); + adpcm->func = snd_pcm_adpcm_decode; + } + } else { + if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) { + adpcm->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format); + adpcm->func = snd_pcm_adpcm_decode; + } else { + adpcm->getput_idx = snd_pcm_linear_get_index(adpcm->sformat, SND_PCM_FORMAT_S16); + adpcm->func = snd_pcm_adpcm_encode; + } + } + assert(!adpcm->states); + adpcm->states = malloc(adpcm->plug.gen.slave->channels * sizeof(*adpcm->states)); + if (adpcm->states == NULL) + return -ENOMEM; + return 0; +} + +static int snd_pcm_adpcm_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + free(adpcm->states); + adpcm->states = NULL; + return snd_pcm_hw_free(adpcm->plug.gen.slave); +} + +static int snd_pcm_adpcm_init(snd_pcm_t *pcm) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + unsigned int k; + for (k = 0; k < pcm->channels; ++k) { + adpcm->states[k].pred_val = 0; + adpcm->states[k].step_idx = 0; + } + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_adpcm_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + adpcm->func(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, + adpcm->getput_idx, adpcm->states); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_adpcm_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + adpcm->func(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, + adpcm->getput_idx, adpcm->states); + *slave_sizep = size; + return size; +} + +static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_adpcm_t *adpcm = pcm->private_data; + snd_output_printf(out, "Ima-ADPCM conversion PCM (%s)\n", + snd_pcm_format_name(adpcm->sformat)); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(adpcm->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_adpcm_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_adpcm_hw_refine, + .hw_params = snd_pcm_adpcm_hw_params, + .hw_free = snd_pcm_adpcm_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_adpcm_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new Ima-ADPCM conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_adpcm_t *adpcm; + int err; + assert(pcmp && slave); + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_IMA_ADPCM) + return -EINVAL; + adpcm = calloc(1, sizeof(snd_pcm_adpcm_t)); + if (!adpcm) { + return -ENOMEM; + } + adpcm->sformat = sformat; + snd_pcm_plugin_init(&adpcm->plug); + adpcm->plug.read = snd_pcm_adpcm_read_areas; + adpcm->plug.write = snd_pcm_adpcm_write_areas; + adpcm->plug.init = snd_pcm_adpcm_init; + adpcm->plug.gen.slave = slave; + adpcm->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_ADPCM, name, slave->stream, slave->mode); + if (err < 0) { + free(adpcm); + return err; + } + pcm->ops = &snd_pcm_adpcm_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = adpcm; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_adpcm Plugin: Ima-ADPCM + +This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples +from master Ima-ADPCM conversion PCM to given slave PCM. The channel count, +format and rate must match for both of them. + +\code +pcm.name { + type adpcm # Ima-ADPCM conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + format STR # Slave format + } +} +\endcode + +\subsection pcm_plugins_adpcm_funcref Function reference + +
    +
  • snd_pcm_adpcm_open() +
  • _snd_pcm_adpcm_open() +
+ +*/ + +/** + * \brief Creates a new Ima-ADPCM conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); + if (err < 0) + return err; + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_IMA_ADPCM) { + snd_config_delete(sconf); + SNDERR("invalid slave format"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_adpcm_open(pcmp, name, sformat, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_adpcm_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c new file mode 100644 index 0000000..09ad481 --- /dev/null +++ b/src/pcm/pcm_alaw.c @@ -0,0 +1,553 @@ +/** + * \file pcm/pcm_alaw.c + * \ingroup PCM_Plugins + * \brief PCM A-Law Conversion Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - A-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_alaw = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef void (*alaw_f)(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getputidx); + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + unsigned int getput_idx; + alaw_f func; + snd_pcm_format_t sformat; +} snd_pcm_alaw_t; + +#endif + +static inline int val_seg(int val) +{ + int r = 1; + val >>= 8; + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static unsigned char s16_to_alaw(int pcm_val) +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; + } else { + mask = 0x55; + pcm_val = -pcm_val; + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + } + + if (pcm_val < 256) + aval = pcm_val >> 4; + else { + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + } + return aval ^ mask; +} + +/* + * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM + * + */ +static int alaw_to_s16(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + t = a_val & 0x7f; + if (t < 16) + t = (t << 4) + 8; + else { + seg = (t >> 4) & 0x07; + t = ((t & 0x0f) << 4) + 0x108; + t <<= seg -1; + } + return ((a_val & 0x80) ? t : -t); +} + +#ifndef DOC_HIDDEN + +void snd_pcm_alaw_decode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int putidx) +{ +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS + void *put = put16_labels[putidx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { + const unsigned char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + int16_t sample = alaw_to_s16(*src); + goto *put; +#define PUT16_END after +#include "plugin_ops.h" +#undef PUT16_END + after: + src += src_step; + dst += dst_step; + } + } +} + +void snd_pcm_alaw_encode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getidx) +{ +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS + void *get = get16_labels[getidx]; + unsigned int channel; + int16_t sample = 0; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + goto *get; +#define GET16_END after +#include "plugin_ops.h" +#undef GET16_END + after: + *dst = s16_to_alaw(sample); + src += src_step; + dst += dst_step; + } + } +} + +#endif /* DOC_HIDDEN */ + +static int snd_pcm_alaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_alaw_t *alaw = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { + snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + } else { + err = _snd_pcm_hw_params_set_format(params, + SND_PCM_FORMAT_A_LAW); + } + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_alaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_alaw_t *alaw = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, alaw->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + return 0; +} + +static int snd_pcm_alaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_alaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_alaw_hw_refine_cprepare, + snd_pcm_alaw_hw_refine_cchange, + snd_pcm_alaw_hw_refine_sprepare, + snd_pcm_alaw_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_alaw_t *alaw = pcm->private_data; + snd_pcm_format_t format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_alaw_hw_refine_cchange, + snd_pcm_alaw_hw_refine_sprepare, + snd_pcm_alaw_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); + if (err < 0) + return err; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { + alaw->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16); + alaw->func = snd_pcm_alaw_encode; + } else { + alaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, alaw->sformat); + alaw->func = snd_pcm_alaw_decode; + } + } else { + if (alaw->sformat == SND_PCM_FORMAT_A_LAW) { + alaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format); + alaw->func = snd_pcm_alaw_decode; + } else { + alaw->getput_idx = snd_pcm_linear_get_index(alaw->sformat, SND_PCM_FORMAT_S16); + alaw->func = snd_pcm_alaw_encode; + } + } + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_alaw_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_alaw_t *alaw = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + alaw->func(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, + alaw->getput_idx); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_alaw_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_alaw_t *alaw = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + alaw->func(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, + alaw->getput_idx); + *slave_sizep = size; + return size; +} + +static void snd_pcm_alaw_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_alaw_t *alaw = pcm->private_data; + snd_output_printf(out, "A-Law conversion PCM (%s)\n", + snd_pcm_format_name(alaw->sformat)); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(alaw->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_alaw_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_alaw_hw_refine, + .hw_params = snd_pcm_alaw_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_alaw_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new A-Law conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_alaw_t *alaw; + int err; + assert(pcmp && slave); + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_A_LAW) + return -EINVAL; + alaw = calloc(1, sizeof(snd_pcm_alaw_t)); + if (!alaw) { + return -ENOMEM; + } + snd_pcm_plugin_init(&alaw->plug); + alaw->sformat = sformat; + alaw->plug.read = snd_pcm_alaw_read_areas; + alaw->plug.write = snd_pcm_alaw_write_areas; + alaw->plug.undo_read = snd_pcm_plugin_undo_read_generic; + alaw->plug.undo_write = snd_pcm_plugin_undo_write_generic; + alaw->plug.gen.slave = slave; + alaw->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_ALAW, name, slave->stream, slave->mode); + if (err < 0) { + free(alaw); + return err; + } + pcm->ops = &snd_pcm_alaw_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = alaw; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_alaw Plugin: A-Law + +This plugin converts A-Law samples to linear or linear to A-Law samples +from master A-Law conversion PCM to given slave PCM. The channel count, +format and rate must match for both of them. + +\code +pcm.name { + type alaw # A-Law conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + format STR # Slave format + } +} +\endcode + +\subsection pcm_plugins_alaw_funcref Function reference + +
    +
  • snd_pcm_alaw_open() +
  • _snd_pcm_alaw_open() +
+ +*/ + +/** + * \brief Creates a new A-Law conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); + if (err < 0) + return err; + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_A_LAW) { + snd_config_delete(sconf); + SNDERR("invalid slave format"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_alaw_open(pcmp, name, sformat, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_alaw_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_asym.c b/src/pcm/pcm_asym.c new file mode 100644 index 0000000..9c32b1b --- /dev/null +++ b/src/pcm/pcm_asym.c @@ -0,0 +1,119 @@ +/** + * \file pcm/pcm_asym.c + * \ingroup PCM_Plugins + * \brief PCM Asymmetrical Plugin Interface + * \author Takashi Iwai + * \date 2003 + */ + +#include "pcm_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_asym = ""; +#endif + +/*! \page pcm_plugins + +\section pcm_plugins_asym Plugin: asym + +This plugin is a combination of playback and capture PCM streams. +Slave PCMs can be defined asymmetrically for both directions. + +\code +pcm.name { + type asym # Asym PCM + playback STR # Playback slave name + # or + playback { # Playback slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + capture STR # Capture slave name + # or + capture { # Capture slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } +} +\endcode + +For example, you can combine a dmix plugin and a dsnoop plugin as +as a single PCM for playback and capture directions, respectively. +\code +pcm.duplex { + type asym + playback.pcm "dmix" + capture.pcm "dsnoop" +} +\endcode + +By defining only a single direction, the resultant PCM becomes +half-duplex. + +\subsection pcm_plugins_asym_funcref Function reference + +
    +
  • _snd_pcm_asym_open() +
+ +*/ + +/** + * \brief Creates a new asym stream PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_asym_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_config_t *slave = NULL, *sconf; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "playback") == 0) { + if (stream == SND_PCM_STREAM_PLAYBACK) + slave = n; + continue; + } + if (strcmp(id, "capture") == 0) { + if (stream == SND_PCM_STREAM_CAPTURE) + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (! slave) { + SNDERR("%s slave is not defined", + stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_named_slave(pcmp, name, root, sconf, stream, + mode, conf); + snd_config_delete(sconf); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_asym_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c new file mode 100644 index 0000000..072bb12 --- /dev/null +++ b/src/pcm/pcm_copy.c @@ -0,0 +1,299 @@ +/** + * \file pcm/pcm_copy.c + * \ingroup PCM_Plugins + * \brief PCM Copy Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Copy conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_copy = ""; +#endif + +#ifndef DOC_HIDDEN +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; +} snd_pcm_copy_t; +#endif + +static int snd_pcm_copy_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_copy_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + return 0; +} + +static int snd_pcm_copy_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_copy_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_copy_hw_refine_cprepare, + snd_pcm_copy_hw_refine_cchange, + snd_pcm_copy_hw_refine_sprepare, + snd_pcm_copy_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_params_slave(pcm, params, + snd_pcm_copy_hw_refine_cchange, + snd_pcm_copy_hw_refine_sprepare, + snd_pcm_copy_hw_refine_schange, + snd_pcm_generic_hw_params); +} + +static snd_pcm_uframes_t +snd_pcm_copy_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + if (size > *slave_sizep) + size = *slave_sizep; + snd_pcm_areas_copy(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, pcm->format); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_copy_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + if (size > *slave_sizep) + size = *slave_sizep; + snd_pcm_areas_copy(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, pcm->format); + *slave_sizep = size; + return size; +} + +static void snd_pcm_copy_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_copy_t *copy = pcm->private_data; + snd_output_printf(out, "Copy conversion PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(copy->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_copy_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_copy_hw_refine, + .hw_params = snd_pcm_copy_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_copy_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new copy PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_copy_t *copy; + int err; + assert(pcmp && slave); + copy = calloc(1, sizeof(snd_pcm_copy_t)); + if (!copy) { + return -ENOMEM; + } + snd_pcm_plugin_init(©->plug); + copy->plug.read = snd_pcm_copy_read_areas; + copy->plug.write = snd_pcm_copy_write_areas; + copy->plug.undo_read = snd_pcm_plugin_undo_read_generic; + copy->plug.undo_write = snd_pcm_plugin_undo_write_generic; + copy->plug.gen.slave = slave; + copy->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_COPY, name, slave->stream, slave->mode); + if (err < 0) { + free(copy); + return err; + } + pcm->ops = &snd_pcm_copy_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = copy; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, ©->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, ©->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_copy Plugin: copy + +This plugin copies samples from master copy PCM to given slave PCM. +The channel count, format and rate must match for both of them. + +\code +pcm.name { + type copy # Copy PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } +} +\endcode + +\subsection pcm_plugins_copy_funcref Function reference + +
    +
  • snd_pcm_copy_open() +
  • _snd_pcm_copy_open() +
+ +*/ + +/** + * \brief Creates a new copy PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_copy_open(pcmp, name, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_copy_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c new file mode 100644 index 0000000..0a9047d --- /dev/null +++ b/src/pcm/pcm_direct.c @@ -0,0 +1,1677 @@ +/* + * PCM - Direct Stream Mixing + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_direct.h" + +/* + * + */ + +union semun { + int val; /* Value for SETVAL */ + struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* Array for GETALL, SETALL */ + struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ +}; + +/* + * FIXME: + * add possibility to use futexes here + */ + +int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix) +{ + union semun s; + struct semid_ds buf; + int i; + + dmix->semid = semget(dmix->ipc_key, DIRECT_IPC_SEMS, + IPC_CREAT | dmix->ipc_perm); + if (dmix->semid < 0) + return -errno; + if (dmix->ipc_gid < 0) + return 0; + for (i = 0; i < DIRECT_IPC_SEMS; i++) { + s.buf = &buf; + if (semctl(dmix->semid, i, IPC_STAT, s) < 0) { + int err = -errno; + snd_pcm_direct_semaphore_discard(dmix); + return err; + } + buf.sem_perm.gid = dmix->ipc_gid; + s.buf = &buf; + semctl(dmix->semid, i, IPC_SET, s); + } + return 0; +} + +#define SND_PCM_DIRECT_MAGIC (0xa15ad300 + sizeof(snd_pcm_direct_share_t)) + +/* + * global shared memory area + */ + +int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix) +{ + struct shmid_ds buf; + int tmpid, err; + +retryget: + dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t), + IPC_CREAT | dmix->ipc_perm); + err = -errno; + if (dmix->shmid < 0){ + if (errno == EINVAL) + if ((tmpid = shmget(dmix->ipc_key, 0, dmix->ipc_perm)) != -1) + if (!shmctl(tmpid, IPC_STAT, &buf)) + if (!buf.shm_nattch) + /* no users so destroy the segment */ + if (!shmctl(tmpid, IPC_RMID, NULL)) + goto retryget; + return err; + } + dmix->shmptr = shmat(dmix->shmid, 0, 0); + if (dmix->shmptr == (void *) -1) { + err = -errno; + snd_pcm_direct_shm_discard(dmix); + return err; + } + mlock(dmix->shmptr, sizeof(snd_pcm_direct_share_t)); + if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) { + err = -errno; + snd_pcm_direct_shm_discard(dmix); + return err; + } + if (buf.shm_nattch == 1) { /* we're the first user, clear the segment */ + memset(dmix->shmptr, 0, sizeof(snd_pcm_direct_share_t)); + if (dmix->ipc_gid >= 0) { + buf.shm_perm.gid = dmix->ipc_gid; + shmctl(dmix->shmid, IPC_SET, &buf); + } + dmix->shmptr->magic = SND_PCM_DIRECT_MAGIC; + return 1; + } else { + if (dmix->shmptr->magic != SND_PCM_DIRECT_MAGIC) { + snd_pcm_direct_shm_discard(dmix); + return -EINVAL; + } + } + return 0; +} + +/* discard shared memory */ +/* + * Define snd_* functions to be used in server. + * Since objects referred in a plugin can be released dynamically, a forked + * server should have statically linked functions. + * (e.g. Novell bugzilla #105772) + */ +static int _snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix) +{ + struct shmid_ds buf; + int ret = 0; + + if (dmix->shmid < 0) + return -EINVAL; + if (dmix->shmptr != (void *) -1 && shmdt(dmix->shmptr) < 0) + return -errno; + dmix->shmptr = (void *) -1; + if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) + return -errno; + if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */ + if (shmctl(dmix->shmid, IPC_RMID, NULL) < 0) + return -errno; + ret = 1; + } + dmix->shmid = -1; + return ret; +} + +/* ... and an exported version */ +int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix) +{ + return _snd_pcm_direct_shm_discard(dmix); +} + +/* + * server side + */ + +static int get_tmp_name(char *filename, size_t size) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + snprintf(filename, size, TMPDIR "/alsa-dmix-%i-%li-%li", (int)getpid(), (long)tv.tv_sec, (long)tv.tv_usec); + filename[size-1] = '\0'; + return 0; +} + +static int make_local_socket(const char *filename, int server, mode_t ipc_perm, int ipc_gid) +{ + size_t l = strlen(filename); + size_t size = offsetof(struct sockaddr_un, sun_path) + l; + struct sockaddr_un *addr = alloca(size); + int sock; + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) { + int result = -errno; + SYSERR("socket failed"); + return result; + } + + if (server) + unlink(filename); + memset(addr, 0, size); /* make valgrind happy */ + addr->sun_family = AF_LOCAL; + memcpy(addr->sun_path, filename, l); + + if (server) { + if (bind(sock, (struct sockaddr *) addr, size) < 0) { + int result = -errno; + SYSERR("bind failed: %s", filename); + close(sock); + return result; + } else { + if (chmod(filename, ipc_perm) < 0) { + int result = -errno; + SYSERR("chmod failed: %s", filename); + close(sock); + unlink(filename); + return result; + } + if (chown(filename, -1, ipc_gid) < 0) { +#if 0 /* it's not fatal */ + int result = -errno; + SYSERR("chown failed: %s", filename); + close(sock); + unlink(filename); + return result; +#endif + } + } + } else { + if (connect(sock, (struct sockaddr *) addr, size) < 0) { + int result = -errno; + SYSERR("connect failed: %s", filename); + close(sock); + return result; + } + } + return sock; +} + +#if 0 +#define SERVER_JOB_DEBUG +#define server_printf(fmt, args...) printf(fmt, ##args) +#else +#undef SERVER_JOB_DEBUG +#define server_printf(fmt, args...) /* nothing */ +#endif + +static snd_pcm_direct_t *server_job_dmix; + +static void server_cleanup(snd_pcm_direct_t *dmix) +{ + close(dmix->server_fd); + close(dmix->hw_fd); + if (dmix->server_free) + dmix->server_free(dmix); + unlink(dmix->shmptr->socket_name); + _snd_pcm_direct_shm_discard(dmix); + snd_pcm_direct_semaphore_discard(dmix); +} + +static void server_job_signal(int sig ATTRIBUTE_UNUSED) +{ + snd_pcm_direct_semaphore_down(server_job_dmix, DIRECT_IPC_SEM_CLIENT); + server_cleanup(server_job_dmix); + server_printf("DIRECT SERVER EXIT - SIGNAL\n"); + _exit(EXIT_SUCCESS); +} + +/* This is a copy from ../socket.c, provided here only for a server job + * (see the comment above) + */ +static int _snd_send_fd(int sock, void *data, size_t len, int fd) +{ + int ret; + size_t cmsg_len = CMSG_LEN(sizeof(int)); + struct cmsghdr *cmsg = alloca(cmsg_len); + int *fds = (int *) CMSG_DATA(cmsg); + struct msghdr msghdr; + struct iovec vec; + + vec.iov_base = (void *)&data; + vec.iov_len = len; + + cmsg->cmsg_len = cmsg_len; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *fds = fd; + + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = &vec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = cmsg; + msghdr.msg_controllen = cmsg_len; + msghdr.msg_flags = 0; + + ret = sendmsg(sock, &msghdr, 0 ); + if (ret < 0) + return -errno; + return ret; +} + +static void server_job(snd_pcm_direct_t *dmix) +{ + int ret, sck, i; + int max = 128, current = 0; + struct pollfd pfds[max + 1]; + + server_job_dmix = dmix; + /* don't allow to be killed */ + signal(SIGHUP, server_job_signal); + signal(SIGQUIT, server_job_signal); + signal(SIGTERM, server_job_signal); + signal(SIGKILL, server_job_signal); + /* close all files to free resources */ + i = sysconf(_SC_OPEN_MAX); +#ifdef SERVER_JOB_DEBUG + while (--i >= 3) { +#else + while (--i >= 0) { +#endif + if (i != dmix->server_fd && i != dmix->hw_fd) + close(i); + } + + /* detach from parent */ + setsid(); + + pfds[0].fd = dmix->server_fd; + pfds[0].events = POLLIN | POLLERR | POLLHUP; + + server_printf("DIRECT SERVER STARTED\n"); + while (1) { + ret = poll(pfds, current + 1, 500); + server_printf("DIRECT SERVER: poll ret = %i, revents[0] = 0x%x, errno = %i\n", ret, pfds[0].revents, errno); + if (ret < 0) { + if (errno == EINTR) + continue; + /* some error */ + break; + } + if (ret == 0 || (pfds[0].revents & (POLLERR | POLLHUP))) { /* timeout or error? */ + struct shmid_ds buf; + snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) { + _snd_pcm_direct_shm_discard(dmix); + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + continue; + } + server_printf("DIRECT SERVER: nattch = %i\n", (int)buf.shm_nattch); + if (buf.shm_nattch == 1) /* server is the last user, exit */ + break; + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + continue; + } + if (pfds[0].revents & POLLIN) { + ret--; + sck = accept(dmix->server_fd, 0, 0); + if (sck >= 0) { + server_printf("DIRECT SERVER: new connection %i\n", sck); + if (current == max) { + close(sck); + } else { + unsigned char buf = 'A'; + pfds[current+1].fd = sck; + pfds[current+1].events = POLLIN | POLLERR | POLLHUP; + _snd_send_fd(sck, &buf, 1, dmix->hw_fd); + server_printf("DIRECT SERVER: fd sent ok\n"); + current++; + } + } + } + for (i = 0; i < current && ret > 0; i++) { + struct pollfd *pfd = &pfds[i+1]; + unsigned char cmd; + server_printf("client %i revents = 0x%x\n", pfd->fd, pfd->revents); + if (pfd->revents & (POLLERR | POLLHUP)) { + ret--; + close(pfd->fd); + pfd->fd = -1; + continue; + } + if (!(pfd->revents & POLLIN)) + continue; + ret--; + if (read(pfd->fd, &cmd, 1) == 1) + cmd = 0 /*process command */; + } + for (i = 0; i < current; i++) { + if (pfds[i+1].fd < 0) { + if (i + 1 != max) + memcpy(&pfds[i+1], &pfds[i+2], sizeof(struct pollfd) * (max - i - 1)); + current--; + } + } + } + server_cleanup(dmix); + server_printf("DIRECT SERVER EXIT\n"); +#ifdef SERVER_JOB_DEBUG + close(0); close(1); close(2); +#endif + _exit(EXIT_SUCCESS); +} + +int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix) +{ + int ret; + + dmix->server_fd = -1; + + ret = get_tmp_name(dmix->shmptr->socket_name, sizeof(dmix->shmptr->socket_name)); + if (ret < 0) + return ret; + + ret = make_local_socket(dmix->shmptr->socket_name, 1, dmix->ipc_perm, dmix->ipc_gid); + if (ret < 0) + return ret; + dmix->server_fd = ret; + + ret = listen(dmix->server_fd, 4); + if (ret < 0) { + close(dmix->server_fd); + return ret; + } + + ret = fork(); + if (ret < 0) { + close(dmix->server_fd); + return ret; + } else if (ret == 0) { + ret = fork(); + if (ret == 0) + server_job(dmix); + _exit(EXIT_SUCCESS); + } else { + waitpid(ret, NULL, 0); + } + dmix->server_pid = ret; + dmix->server = 1; + return 0; +} + +int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix) +{ + if (dmix->server) { + //kill(dmix->server_pid, SIGTERM); + //waitpid(dmix->server_pid, NULL, 0); + dmix->server_pid = (pid_t)-1; + } + if (dmix->server_fd > 0) { + close(dmix->server_fd); + dmix->server_fd = -1; + } + dmix->server = 0; + return 0; +} + +/* + * client side + */ + +int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix) +{ + int ret; + unsigned char buf; + + ret = make_local_socket(dmix->shmptr->socket_name, 0, -1, -1); + if (ret < 0) + return ret; + dmix->comm_fd = ret; + + ret = snd_receive_fd(dmix->comm_fd, &buf, 1, &dmix->hw_fd); + if (ret < 1 || buf != 'A') { + close(dmix->comm_fd); + dmix->comm_fd = -1; + return ret; + } + + dmix->client = 1; + return 0; +} + +int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix) +{ + if (dmix->client) { + close(dmix->comm_fd); + dmix->comm_fd = -1; + } + return 0; +} + +/* + * plugin helpers + */ + +int snd_pcm_direct_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) +{ + /* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */ + return 0; +} + +int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + return snd_timer_async(dmix->timer, sig, pid); +} + +/* empty the timer read queue */ +void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) +{ + if (dmix->timer_need_poll) { + while (poll(&dmix->timer_fd, 1, 0) > 0) { + /* we don't need the value */ + if (dmix->tread) { + snd_timer_tread_t rbuf[4]; + snd_timer_read(dmix->timer, rbuf, sizeof(rbuf)); + } else { + snd_timer_read_t rbuf; + snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)); + } + } + } else { + if (dmix->tread) { + snd_timer_tread_t rbuf[4]; + int len; + while ((len = snd_timer_read(dmix->timer, rbuf, + sizeof(rbuf))) > 0 && + len != sizeof(rbuf[0])) + ; + } else { + snd_timer_read_t rbuf; + while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0) + ; + } + } +} + +int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) +{ + snd_timer_stop(dmix->timer); + return 0; +} + +int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + unsigned short events; + int empty = 0; + + assert(pfds && nfds == 1 && revents); + events = pfds[0].revents; + if (events & POLLIN) { + snd_pcm_uframes_t avail; + snd_pcm_avail_update(pcm); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + events |= POLLOUT; + events &= ~POLLIN; + avail = snd_pcm_mmap_playback_avail(pcm); + } else { + avail = snd_pcm_mmap_capture_avail(pcm); + } + empty = avail < pcm->avail_min; + } + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_SETUP: + events |= POLLERR; + break; + default: + if (empty) { + snd_pcm_direct_clear_timer_queue(dmix); + events &= ~(POLLOUT|POLLIN); + /* additional check */ + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_SETUP: + events |= POLLERR; + break; + default: + break; + } + } + break; + } + *revents = events; + return 0; +} + +int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + if (dmix->spcm && !dmix->shmptr->use_server) + return snd_pcm_info(dmix->spcm, info); + + memset(info, 0, sizeof(*info)); + info->stream = pcm->stream; + info->card = -1; + /* FIXME: fill this with something more useful: we know the hardware name */ + if (pcm->name) { + strncpy((char *)info->id, pcm->name, sizeof(info->id)); + strncpy((char *)info->name, pcm->name, sizeof(info->name)); + strncpy((char *)info->subname, pcm->name, sizeof(info->subname)); + } + info->subdevices_count = 1; + return 0; +} + +static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; +} + +static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; +} + +static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + snd_interval_t *src) +{ + snd_interval_t *i; + + if (!(params->rmask & (1<cmask |= 1<private_data; + static const snd_mask_t access = { .bits = { + (1<rmask & (1<cmask |= 1<rmask & (1<shmptr->hw.format)) + params->cmask |= 1<rmask & (1<channels); + if (err < 0) + return err; + } + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE, + &dshare->shmptr->hw.rate); + if (err < 0) + return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, + &dshare->shmptr->hw.period_size); + if (err < 0) + return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, + &dshare->shmptr->hw.period_time); + if (err < 0) + return err; + if (dshare->max_periods < 0) { + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + &dshare->shmptr->hw.buffer_size); + if (err < 0) + return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, + &dshare->shmptr->hw.buffer_time); + if (err < 0) + return err; + } else if (params->rmask & ((1<max_periods; + if (max_periods < 2) + max_periods = dshare->slave_buffer_size / dshare->slave_period_size; + do { + changed = 0; + err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS, + 2, max_periods); + if (err < 0) + return err; + changed |= err; + err = snd_pcm_hw_refine_soft(pcm, params); + if (err < 0) + return err; + changed |= err; + } while (changed); + } + params->info = dshare->shmptr->s.info; +#ifdef REFINE_DEBUG + snd_output_puts(log, "DMIX REFINE (end):\n"); + snd_pcm_hw_params_dump(params, log); + snd_output_close(log); +#endif + return 0; +} + +int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + params->info = dmix->shmptr->s.info; + params->rate_num = dmix->shmptr->s.rate; + params->rate_den = 1; + params->fifo_size = 0; + params->msbits = dmix->shmptr->s.msbits; + return 0; +} + +int snd_pcm_direct_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + /* values are cached in the pcm structure */ + return 0; +} + +int snd_pcm_direct_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) +{ + /* values are cached in the pcm structure */ + return 0; +} + +int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) +{ + return snd_pcm_channel_info_shm(pcm, info, -1); +} + +int snd_pcm_direct_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +int snd_pcm_direct_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +int snd_pcm_direct_resume(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + int err; + + snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + err = snd_pcm_resume(dmix->spcm); + if (err == -ENOSYS) { + /* FIXME: error handling? */ + snd_pcm_prepare(dmix->spcm); + snd_pcm_start(dmix->spcm); + err = 0; + } + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + return err; +} + +#define COPY_SLAVE(field) (dmix->shmptr->s.field = spcm->field) + +/* copy the slave setting */ +static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm) +{ + spcm->info &= ~SND_PCM_INFO_PAUSE; + + COPY_SLAVE(access); + COPY_SLAVE(format); + COPY_SLAVE(subformat); + COPY_SLAVE(channels); + COPY_SLAVE(rate); + COPY_SLAVE(period_size); + COPY_SLAVE(period_time); + COPY_SLAVE(periods); + COPY_SLAVE(tstamp_mode); + COPY_SLAVE(period_step); + COPY_SLAVE(avail_min); + COPY_SLAVE(start_threshold); + COPY_SLAVE(stop_threshold); + COPY_SLAVE(silence_threshold); + COPY_SLAVE(silence_size); + COPY_SLAVE(boundary); + COPY_SLAVE(info); + COPY_SLAVE(msbits); + COPY_SLAVE(rate_num); + COPY_SLAVE(rate_den); + COPY_SLAVE(hw_flags); + COPY_SLAVE(fifo_size); + COPY_SLAVE(buffer_size); + COPY_SLAVE(buffer_time); + COPY_SLAVE(sample_bits); + COPY_SLAVE(frame_bits); +} + +#undef COPY_SLAVE + +/* + * this function initializes hardware and starts playback operation with + * no stop threshold (it operates all time without xrun checking) + * also, the driver silences the unused ring buffer areas for us + */ +int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params) +{ + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + int ret, buffer_is_not_initialized; + snd_pcm_uframes_t boundary; + struct pollfd fd; + int loops = 10; + + snd_pcm_hw_params_alloca(&hw_params); + snd_pcm_sw_params_alloca(&sw_params); + + __again: + if (loops-- <= 0) { + SNDERR("unable to find a valid configuration for slave"); + return -EINVAL; + } + ret = snd_pcm_hw_params_any(spcm, hw_params); + if (ret < 0) { + SNDERR("snd_pcm_hw_params_any failed"); + return ret; + } + ret = snd_pcm_hw_params_set_access(spcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED); + if (ret < 0) { + ret = snd_pcm_hw_params_set_access(spcm, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + if (ret < 0) { + SNDERR("slave plugin does not support mmap interleaved or mmap noninterleaved access"); + return ret; + } + } + if (params->format == SND_PCM_FORMAT_UNKNOWN) + ret = -EINVAL; + else + ret = snd_pcm_hw_params_set_format(spcm, hw_params, + params->format); + if (ret < 0) { + static const snd_pcm_format_t dmix_formats[] = { + SND_PCM_FORMAT_S32, + SND_PCM_FORMAT_S32 ^ SND_PCM_FORMAT_S32_LE ^ SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_S16, + SND_PCM_FORMAT_S16 ^ SND_PCM_FORMAT_S16_LE ^ SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_U8, + }; + snd_pcm_format_t format; + unsigned int i; + + for (i = 0; i < sizeof dmix_formats / sizeof dmix_formats[0]; ++i) { + format = dmix_formats[i]; + ret = snd_pcm_hw_params_set_format(spcm, hw_params, format); + if (ret >= 0) + break; + } + if (ret < 0 && dmix->type != SND_PCM_TYPE_DMIX) { + /* TODO: try to choose a good format */ + ret = INTERNAL(snd_pcm_hw_params_set_format_first)(spcm, hw_params, &format); + } + if (ret < 0) { + SNDERR("requested or auto-format is not available"); + return ret; + } + params->format = format; + } + ret = INTERNAL(snd_pcm_hw_params_set_channels_near)(spcm, hw_params, (unsigned int *)¶ms->channels); + if (ret < 0) { + SNDERR("requested count of channels is not available"); + return ret; + } + ret = INTERNAL(snd_pcm_hw_params_set_rate_near)(spcm, hw_params, (unsigned int *)¶ms->rate, 0); + if (ret < 0) { + SNDERR("requested rate is not available"); + return ret; + } + + buffer_is_not_initialized = 0; + if (params->buffer_time > 0) { + ret = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(spcm, hw_params, (unsigned int *)¶ms->buffer_time, 0); + if (ret < 0) { + SNDERR("unable to set buffer time"); + return ret; + } + } else if (params->buffer_size > 0) { + ret = INTERNAL(snd_pcm_hw_params_set_buffer_size_near)(spcm, hw_params, (snd_pcm_uframes_t *)¶ms->buffer_size); + if (ret < 0) { + SNDERR("unable to set buffer size"); + return ret; + } + } else { + buffer_is_not_initialized = 1; + } + + if (params->period_time > 0) { + ret = INTERNAL(snd_pcm_hw_params_set_period_time_near)(spcm, hw_params, (unsigned int *)¶ms->period_time, 0); + if (ret < 0) { + SNDERR("unable to set period_time"); + return ret; + } + } else if (params->period_size > 0) { + ret = INTERNAL(snd_pcm_hw_params_set_period_size_near)(spcm, hw_params, (snd_pcm_uframes_t *)¶ms->period_size, 0); + if (ret < 0) { + SNDERR("unable to set period_size"); + return ret; + } + } + + if (buffer_is_not_initialized && params->periods > 0) { + unsigned int periods = params->periods; + ret = INTERNAL(snd_pcm_hw_params_set_periods_near)(spcm, hw_params, ¶ms->periods, 0); + if (ret < 0) { + SNDERR("unable to set requested periods"); + return ret; + } + if (params->periods == 1) { + params->periods = periods; + if (params->period_time > 0) { + params->period_time /= 2; + goto __again; + } else if (params->period_size > 0) { + params->period_size /= 2; + goto __again; + } + SNDERR("unable to use stream with periods == 1"); + return ret; + } + } + + ret = snd_pcm_hw_params(spcm, hw_params); + if (ret < 0) { + SNDERR("unable to install hw params"); + return ret; + } + + /* store some hw_params values to shared info */ + dmix->shmptr->hw.format = snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)); + dmix->shmptr->hw.rate = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_RATE); + dmix->shmptr->hw.buffer_size = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_BUFFER_SIZE); + dmix->shmptr->hw.buffer_time = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_BUFFER_TIME); + dmix->shmptr->hw.period_size = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIOD_SIZE); + dmix->shmptr->hw.period_time = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIOD_TIME); + dmix->shmptr->hw.periods = *hw_param_interval(hw_params, SND_PCM_HW_PARAM_PERIODS); + + + ret = snd_pcm_sw_params_current(spcm, sw_params); + if (ret < 0) { + SNDERR("unable to get current sw_params"); + return ret; + } + + ret = snd_pcm_sw_params_get_boundary(sw_params, &boundary); + if (ret < 0) { + SNDERR("unable to get boundary"); + return ret; + } + ret = snd_pcm_sw_params_set_stop_threshold(spcm, sw_params, boundary); + if (ret < 0) { + SNDERR("unable to set stop threshold"); + return ret; + } + + /* set timestamp mode to MMAP + * the slave timestamp is copied appropriately in dsnoop/dmix/dshare + * based on the tstamp_mode of each client + */ + ret = snd_pcm_sw_params_set_tstamp_mode(spcm, sw_params, + SND_PCM_TSTAMP_ENABLE); + if (ret < 0) { + SNDERR("unable to tstamp mode MMAP"); + return ret; + } + + if (dmix->type != SND_PCM_TYPE_DMIX) + goto __skip_silencing; + + ret = snd_pcm_sw_params_set_silence_threshold(spcm, sw_params, 0); + if (ret < 0) { + SNDERR("unable to set silence threshold"); + return ret; + } + ret = snd_pcm_sw_params_set_silence_size(spcm, sw_params, boundary); + if (ret < 0) { + SNDERR("unable to set silence threshold (please upgrade to 0.9.0rc8+ driver)"); + return ret; + } + + __skip_silencing: + + ret = snd_pcm_sw_params(spcm, sw_params); + if (ret < 0) { + SNDERR("unable to install sw params (please upgrade to 0.9.0rc8+ driver)"); + return ret; + } + + if (dmix->type == SND_PCM_TYPE_DSHARE) { + const snd_pcm_channel_area_t *dst_areas; + dst_areas = snd_pcm_mmap_areas(spcm); + snd_pcm_areas_silence(dst_areas, 0, spcm->channels, spcm->buffer_size, spcm->format); + } + + ret = snd_pcm_start(spcm); + if (ret < 0) { + SNDERR("unable to start PCM stream"); + return ret; + } + + if (snd_pcm_poll_descriptors_count(spcm) != 1) { + SNDERR("unable to use hardware pcm with fd more than one!!!"); + return ret; + } + snd_pcm_poll_descriptors(spcm, &fd, 1); + dmix->hw_fd = fd.fd; + + save_slave_setting(dmix, spcm); + + /* Currently, we assume that each dmix client has the same + * hw_params setting. + * If the arbitrary hw_parmas is supported in future, + * boundary has to be taken from the slave config but + * recalculated for the native boundary size (for 32bit + * emulation on 64bit arch). + */ + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = spcm->period_size; + dmix->slave_boundary = spcm->boundary; + + spcm->donot_close = 1; + + { + int ver = 0; + ioctl(spcm->poll_fd, SNDRV_PCM_IOCTL_PVERSION, &ver); + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 8)) + dmix->shmptr->use_server = 1; + } + + return 0; +} + +/* + * the trick is used here; we cannot use effectively the hardware handle because + * we cannot drive multiple accesses to appl_ptr; so we use slave timer of given + * PCM hardware handle; it's not this easy and cheap? + */ +int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) +{ + int ret; + snd_pcm_info_t *info; + char name[128]; + int capture = dmix->type == SND_PCM_TYPE_DSNOOP ? 1 : 0; + + dmix->tread = 1; + dmix->timer_need_poll = 0; + snd_pcm_info_alloca(&info); + ret = snd_pcm_info(dmix->spcm, info); + if (ret < 0) { + SNDERR("unable to info for slave pcm"); + return ret; + } + sprintf(name, "hw:CLASS=%i,SCLASS=0,CARD=%i,DEV=%i,SUBDEV=%i", + (int)SND_TIMER_CLASS_PCM, + snd_pcm_info_get_card(info), + snd_pcm_info_get_device(info), + snd_pcm_info_get_subdevice(info) * 2 + capture); + ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD); + if (ret < 0) { + dmix->tread = 0; + ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK); + if (ret < 0) { + SNDERR("unable to open timer '%s'", name); + return ret; + } + } + + if (snd_timer_poll_descriptors_count(dmix->timer) != 1) { + SNDERR("unable to use timer '%s' with more than one fd!", name); + return ret; + } + snd_timer_poll_descriptors(dmix->timer, &dmix->timer_fd, 1); + dmix->poll_fd = dmix->timer_fd.fd; + + dmix->timer_events = (1<poll_fd, SNDRV_TIMER_IOCTL_PVERSION, &ver); + /* In older versions, check via poll before read() is needed + * because of the confliction between TIMER_START and + * FIONBIO ioctls. + */ + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4)) + dmix->timer_need_poll = 1; + /* + * In older versions, timer uses pause events instead + * suspend/resume events. + */ + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) { + dmix->timer_events &= ~((1<timer_events |= (1<timer_events |= 1< LONG_MAX) { + bsize = buffer_size; + while (bsize * 2 <= LONG_MAX - buffer_size) + bsize *= 2; + } + return (snd_pcm_uframes_t)bsize; +} + +#define COPY_SLAVE(field) (spcm->field = dmix->shmptr->s.field) + +/* copy the slave setting */ +static void copy_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm) +{ + COPY_SLAVE(access); + COPY_SLAVE(format); + COPY_SLAVE(subformat); + COPY_SLAVE(channels); + COPY_SLAVE(rate); + COPY_SLAVE(period_size); + COPY_SLAVE(period_time); + COPY_SLAVE(periods); + COPY_SLAVE(tstamp_mode); + COPY_SLAVE(period_step); + COPY_SLAVE(avail_min); + COPY_SLAVE(start_threshold); + COPY_SLAVE(stop_threshold); + COPY_SLAVE(silence_threshold); + COPY_SLAVE(silence_size); + COPY_SLAVE(boundary); + COPY_SLAVE(info); + COPY_SLAVE(msbits); + COPY_SLAVE(rate_num); + COPY_SLAVE(rate_den); + COPY_SLAVE(hw_flags); + COPY_SLAVE(fifo_size); + COPY_SLAVE(buffer_size); + COPY_SLAVE(buffer_time); + COPY_SLAVE(sample_bits); + COPY_SLAVE(frame_bits); + + spcm->info &= ~SND_PCM_INFO_PAUSE; + spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size); +} + +#undef COPY_SLAVE + + +/* + * open a slave PCM as secondary client (dup'ed fd) + */ +int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name) +{ + int ret; + snd_pcm_t *spcm; + + ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0, 0); + if (ret < 0) { + SNDERR("unable to open hardware"); + return ret; + } + + spcm = *spcmp; + spcm->donot_close = 1; + spcm->setup = 1; + + copy_slave_setting(dmix, spcm); + + /* Use the slave setting as SPCM, so far */ + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = dmix->shmptr->s.period_size; + dmix->slave_boundary = spcm->boundary; + + ret = snd_pcm_mmap(spcm); + if (ret < 0) { + SNDERR("unable to mmap channels"); + return ret; + } + return 0; +} + +/* + * open a slave PCM as secondary client (dup'ed fd) + */ +int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, + snd_pcm_t *spcm, + struct slave_params *params ATTRIBUTE_UNUSED) +{ + int ret; + + spcm->donot_close = 1; + spcm->setup = 1; + + copy_slave_setting(dmix, spcm); + + /* Use the slave setting as SPCM, so far */ + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = dmix->shmptr->s.period_size; + dmix->slave_boundary = spcm->boundary; + + ret = snd_pcm_mmap(spcm); + if (ret < 0) { + SNDERR("unable to mmap channels"); + return ret; + } + return 0; +} + +int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) +{ + snd_timer_params_t *params; + unsigned int filter; + int ret; + + snd_timer_params_alloca(¶ms); + snd_timer_params_set_auto_start(params, 1); + if (dmix->type != SND_PCM_TYPE_DSNOOP) + snd_timer_params_set_early_event(params, 1); + snd_timer_params_set_ticks(params, 1); + if (dmix->tread) { + filter = (1<timer_events; + snd_timer_params_set_filter(params, filter); + } + ret = snd_timer_params(dmix->timer, params); + if (ret < 0) { + SNDERR("unable to set timer parameters"); + return ret; + } + return 0; +} + +/* + * ring buffer operation + */ +int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm) +{ + unsigned int chn, channels; + int bits, interleaved = 1; + const snd_pcm_channel_area_t *dst_areas; + const snd_pcm_channel_area_t *src_areas; + + bits = snd_pcm_format_physical_width(pcm->format); + if ((bits % 8) != 0) + interleaved = 0; + channels = dmix->channels; + dst_areas = snd_pcm_mmap_areas(dmix->spcm); + src_areas = snd_pcm_mmap_areas(pcm); + for (chn = 1; chn < channels; chn++) { + if (dst_areas[chn-1].addr != dst_areas[chn].addr) { + interleaved = 0; + break; + } + if (src_areas[chn-1].addr != src_areas[chn].addr) { + interleaved = 0; + break; + } + } + for (chn = 0; chn < channels; chn++) { + if (dmix->bindings && dmix->bindings[chn] != chn) { + interleaved = 0; + break; + } + if (dst_areas[chn].first != chn * bits || + dst_areas[chn].step != channels * bits) { + interleaved = 0; + break; + } + if (src_areas[chn].first != chn * bits || + src_areas[chn].step != channels * bits) { + interleaved = 0; + break; + } + } + return dmix->interleaved = interleaved; +} + +/* + * parse the channel map + * id == client channel + * value == slave's channel + */ +int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, + struct slave_params *params, + snd_config_t *cfg) +{ + snd_config_iterator_t i, next; + unsigned int chn, chn1, count = 0; + unsigned int *bindings; + int err; + + dmix->channels = UINT_MAX; + if (cfg == NULL) + return 0; + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("invalid type for bindings"); + return -EINVAL; + } + snd_config_for_each(i, next, cfg) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long cchannel; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0 || cchannel < 0) { + SNDERR("invalid client channel in binding: %s\n", id); + return -EINVAL; + } + if ((unsigned)cchannel >= count) + count = cchannel + 1; + } + if (count == 0) + return 0; + if (count > 1024) { + SNDERR("client channel out of range"); + return -EINVAL; + } + bindings = malloc(count * sizeof(unsigned int)); + if (bindings == NULL) + return -ENOMEM; + for (chn = 0; chn < count; chn++) + bindings[chn] = UINT_MAX; /* don't route */ + snd_config_for_each(i, next, cfg) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long cchannel, schannel; + if (snd_config_get_id(n, &id) < 0) + continue; + safe_strtol(id, &cchannel); + if (snd_config_get_integer(n, &schannel) < 0) { + SNDERR("unable to get slave channel (should be integer type) in binding: %s\n", id); + free(bindings); + return -EINVAL; + } + if (schannel < 0 || schannel >= params->channels) { + SNDERR("invalid slave channel number %ld in binding to %ld", + schannel, cchannel); + free(bindings); + return -EINVAL; + } + bindings[cchannel] = schannel; + } + if (dmix->type == SND_PCM_TYPE_DSNOOP || + ! dmix->bindings) + goto __skip_same_dst; + for (chn = 0; chn < count; chn++) { + for (chn1 = 0; chn1 < count; chn1++) { + if (chn == chn1) + continue; + if (bindings[chn] == dmix->bindings[chn1]) { + SNDERR("unable to route channels %d,%d to same destination %d", chn, chn1, bindings[chn]); + free(bindings); + return -EINVAL; + } + } + } + __skip_same_dst: + dmix->bindings = bindings; + dmix->channels = count; + return 0; +} + +/* + * parse slave config and calculate the ipc_key offset + */ + +static int _snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, + snd_config_t *sconf, + int direction, + int hop) +{ + snd_config_iterator_t i, next; + snd_config_t *pcm_conf; + int err; + long card = 0, device = 0, subdevice = 0; + const char *str; + + if (snd_config_get_string(sconf, &str) >= 0) { + if (hop > SND_CONF_MAX_HOPS) { + SNDERR("Too many definition levels (looped?)"); + return -EINVAL; + } + err = snd_config_search_definition(root, "pcm", str, &pcm_conf); + if (err < 0) { + SNDERR("Unknown slave PCM %s", str); + return err; + } + err = _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf, + direction, + hop + 1); + snd_config_delete(pcm_conf); + return err; + } + +#if 0 /* for debug purposes */ + { + snd_output_t *out; + snd_output_stdio_attach(&out, stderr, 0); + snd_config_save(sconf, out); + snd_output_close(out); + } +#endif + + if (snd_config_search(sconf, "slave", &pcm_conf) >= 0 && + (snd_config_search(pcm_conf, "pcm", &pcm_conf) >= 0 || + (snd_config_get_string(pcm_conf, &str) >= 0 && + snd_config_search_definition(root, "pcm_slave", str, &pcm_conf) >= 0 && + snd_config_search(pcm_conf, "pcm", &pcm_conf) >= 0))) + return _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf, + direction, + hop + 1); + + snd_config_for_each(i, next, sconf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id, *str; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "type") == 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid value for PCM type definition\n"); + return -EINVAL; + } + if (strcmp(str, "hw")) { + SNDERR("Invalid type '%s' for slave PCM\n", str); + return -EINVAL; + } + continue; + } + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + card = snd_card_get_index(str); + if (card < 0) { + SNDERR("Invalid value for %s", id); + return card; + } + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + continue; + } + if (strcmp(id, "subdevice") == 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + continue; + } + } + if (card < 0) + card = 0; + if (device < 0) + device = 0; + if (subdevice < 0) + subdevice = 0; + return (direction << 1) + (device << 2) + (subdevice << 8) + (card << 12); +} + +static int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, + snd_config_t *sconf, + int direction) +{ + return _snd_pcm_direct_get_slave_ipc_offset(root, sconf, direction, 0); +} + +int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, + int stream, struct snd_pcm_direct_open_conf *rec) +{ + snd_config_iterator_t i, next; + int ipc_key_add_uid = 0; + snd_config_t *n; + int err; + + rec->slave = NULL; + rec->bindings = NULL; + rec->ipc_key = 0; + rec->ipc_perm = 0600; + rec->ipc_gid = -1; + rec->slowptr = 1; + rec->max_periods = 0; + + /* read defaults */ + if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { + long val; + err = snd_config_get_integer(n, &val); + if (err >= 0) + rec->max_periods = val; + } + + snd_config_for_each(i, next, conf) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "ipc_key") == 0) { + long key; + err = snd_config_get_integer(n, &key); + if (err < 0) { + SNDERR("The field ipc_key must be an integer type"); + + return err; + } + rec->ipc_key = key; + continue; + } + if (strcmp(id, "ipc_perm") == 0) { + long perm; + err = snd_config_get_integer(n, &perm); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + if ((perm & ~0777) != 0) { + SNDERR("The field ipc_perm must be a valid file permission"); + return -EINVAL; + } + rec->ipc_perm = perm; + continue; + } + if (strcmp(id, "ipc_gid") == 0) { + char *group; + char *endp; + err = snd_config_get_ascii(n, &group); + if (err < 0) { + SNDERR("The field ipc_gid must be a valid group"); + return err; + } + if (! *group) { + rec->ipc_gid = -1; + free(group); + continue; + } + if (isdigit(*group) == 0) { + struct group *grp = getgrnam(group); + if (grp == NULL) { + SNDERR("The field ipc_gid must be a valid group (create group %s)", group); + free(group); + return -EINVAL; + } + rec->ipc_gid = grp->gr_gid; + } else { + rec->ipc_gid = strtol(group, &endp, 10); + } + free(group); + continue; + } + if (strcmp(id, "ipc_key_add_uid") == 0) { + if ((err = snd_config_get_bool(n)) < 0) { + SNDERR("The field ipc_key_add_uid must be a boolean type"); + return err; + } + ipc_key_add_uid = err; + continue; + } + if (strcmp(id, "slave") == 0) { + rec->slave = n; + continue; + } + if (strcmp(id, "bindings") == 0) { + rec->bindings = n; + continue; + } + if (strcmp(id, "slowptr") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return err; + rec->slowptr = err; + continue; + } + if (strcmp(id, "max_periods") == 0) { + long val; + err = snd_config_get_integer(n, &val); + if (err < 0) + return err; + rec->max_periods = val; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!rec->slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + if (!rec->ipc_key) { + SNDERR("Unique IPC key is not defined"); + return -EINVAL; + } + if (ipc_key_add_uid) + rec->ipc_key += getuid(); + err = snd_pcm_direct_get_slave_ipc_offset(root, conf, stream); + if (err < 0) + return err; + rec->ipc_key += err; + + return 0; +} diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h new file mode 100644 index 0000000..7f16481 --- /dev/null +++ b/src/pcm/pcm_direct.h @@ -0,0 +1,306 @@ +/* + * PCM - Direct Stream Mixing + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" + +#define DIRECT_IPC_SEMS 1 +#define DIRECT_IPC_SEM_CLIENT 0 + +typedef void (mix_areas_t)(unsigned int size, + volatile void *dst, void *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step); + +typedef void (mix_areas_16_t)(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step); + +typedef void (mix_areas_32_t)(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step); + +typedef void (mix_areas_24_t)(unsigned int size, + volatile unsigned char *dst, unsigned char *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step); + +typedef void (mix_areas_u8_t)(unsigned int size, + volatile unsigned char *dst, unsigned char *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step); + +struct slave_params { + snd_pcm_format_t format; + int rate; + int channels; + int period_time; + int buffer_time; + snd_pcm_sframes_t period_size; + snd_pcm_sframes_t buffer_size; + unsigned int periods; +}; + +/* shared among direct plugin clients - be careful to be 32/64bit compatible! */ +typedef struct { + unsigned int magic; /* magic number */ + char socket_name[256]; /* name of communication socket */ + snd_pcm_type_t type; /* PCM type (currently only hw) */ + int use_server; + struct { + unsigned int format; + snd_interval_t rate; + snd_interval_t buffer_size; + snd_interval_t buffer_time; + snd_interval_t period_size; + snd_interval_t period_time; + snd_interval_t periods; + } hw; + struct { + /* copied to slave PCMs */ + snd_pcm_access_t access; + snd_pcm_format_t format; + snd_pcm_subformat_t subformat; + unsigned int channels; + unsigned int rate; + unsigned int period_size; + unsigned int period_time; + snd_interval_t periods; + unsigned int monotonic; + snd_pcm_tstamp_t tstamp_mode; + unsigned int period_step; + unsigned int sleep_min; /* not used */ + unsigned int avail_min; + unsigned int start_threshold; + unsigned int stop_threshold; + unsigned int silence_threshold; + unsigned int silence_size; + unsigned int xfer_align; /* not used */ + unsigned long long boundary; + unsigned int info; + unsigned int msbits; + unsigned int rate_num; + unsigned int rate_den; + unsigned int hw_flags; + unsigned int fifo_size; + unsigned int buffer_size; + snd_interval_t buffer_time; + unsigned int sample_bits; + unsigned int frame_bits; + } s; + union { + struct { + unsigned long long chn_mask; + } dshare; + } u; +} snd_pcm_direct_share_t; + +typedef struct snd_pcm_direct snd_pcm_direct_t; + +struct snd_pcm_direct { + snd_pcm_type_t type; /* type (dmix, dsnoop, dshare) */ + key_t ipc_key; /* IPC key for semaphore and memory */ + mode_t ipc_perm; /* IPC socket permissions */ + int ipc_gid; /* IPC socket gid */ + int semid; /* IPC global semaphore identification */ + int shmid; /* IPC global shared memory identification */ + snd_pcm_direct_share_t *shmptr; /* pointer to shared memory area */ + snd_pcm_t *spcm; /* slave PCM handle */ + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t last_appl_ptr; + snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t avail_max; + snd_pcm_uframes_t slave_appl_ptr; + snd_pcm_uframes_t slave_hw_ptr; + snd_pcm_uframes_t slave_period_size; + snd_pcm_uframes_t slave_buffer_size; + snd_pcm_uframes_t slave_boundary; + int (*sync_ptr)(snd_pcm_t *pcm); + snd_pcm_state_t state; + snd_htimestamp_t trigger_tstamp; + snd_htimestamp_t update_tstamp; + int server, client; + int comm_fd; /* communication file descriptor (socket) */ + int hw_fd; /* hardware file descriptor */ + struct pollfd timer_fd; + int poll_fd; + int tread: 1; + int timer_need_poll: 1; + unsigned int timer_events; + int server_fd; + pid_t server_pid; + snd_timer_t *timer; /* timer used as poll_fd */ + int interleaved; /* we have interleaved buffer */ + int slowptr; /* use slow but more precise ptr updates */ + int max_periods; /* max periods (-1 = fixed periods, 0 = max buffer size) */ + unsigned int channels; /* client's channels */ + unsigned int *bindings; + union { + struct { + int shmid_sum; /* IPC global sum ring buffer memory identification */ + signed int *sum_buffer; /* shared sum buffer */ + mix_areas_16_t *mix_areas_16; + mix_areas_32_t *mix_areas_32; + mix_areas_24_t *mix_areas_24; + mix_areas_u8_t *mix_areas_u8; + mix_areas_16_t *remix_areas_16; + mix_areas_32_t *remix_areas_32; + mix_areas_24_t *remix_areas_24; + mix_areas_u8_t *remix_areas_u8; + } dmix; + struct { + } dsnoop; + struct { + unsigned long long chn_mask; + } dshare; + } u; + void (*server_free)(snd_pcm_direct_t *direct); +}; + +/* make local functions really local */ +#define snd_pcm_direct_semaphore_create_or_connect \ + snd1_pcm_direct_semaphore_create_or_connect +#define snd_pcm_direct_shm_create_or_connect \ + snd1_pcm_direct_shm_create_or_connect +#define snd_pcm_direct_shm_discard \ + snd1_pcm_direct_shm_discard +#define snd_pcm_direct_server_create \ + snd1_pcm_direct_server_create +#define snd_pcm_direct_server_discard \ + snd1_pcm_direct_server_discard +#define snd_pcm_direct_client_connect \ + snd1_pcm_direct_client_connect +#define snd_pcm_direct_client_discard \ + snd1_pcm_direct_client_discard +#define snd_pcm_direct_initialize_slave \ + snd1_pcm_direct_initialize_slave +#define snd_pcm_direct_initialize_secondary_slave \ + snd1_pcm_direct_initialize_secondary_slave +#define snd_pcm_direct_initialize_poll_fd \ + snd1_pcm_direct_initialize_poll_fd +#define snd_pcm_direct_check_interleave \ + snd1_pcm_direct_check_interleave +#define snd_pcm_direct_parse_bindings \ + snd1_pcm_direct_parse_bindings +#define snd_pcm_direct_nonblock \ + snd1_pcm_direct_nonblock +#define snd_pcm_direct_async \ + snd1_pcm_direct_async +#define snd_pcm_direct_poll_revents \ + snd1_pcm_direct_poll_revents +#define snd_pcm_direct_info \ + snd1_pcm_direct_info +#define snd_pcm_direct_hw_refine \ + snd1_pcm_direct_hw_refine +#define snd_pcm_direct_hw_params \ + snd1_pcm_direct_hw_params +#define snd_pcm_direct_hw_free \ + snd1_pcm_direct_hw_free +#define snd_pcm_direct_sw_params \ + snd1_pcm_direct_sw_params +#define snd_pcm_direct_channel_info \ + snd1_pcm_direct_channel_info +#define snd_pcm_direct_mmap \ + snd1_pcm_direct_mmap +#define snd_pcm_direct_munmap \ + snd1_pcm_direct_munmap +#define snd_pcm_direct_resume \ + snd1_pcm_direct_resume +#define snd_pcm_direct_timer_stop \ + snd1_pcm_direct_timer_stop +#define snd_pcm_direct_clear_timer_queue \ + snd1_pcm_direct_clear_timer_queue +#define snd_pcm_direct_set_timer_params \ + snd1_pcm_direct_set_timer_params +#define snd_pcm_direct_open_secondary_client \ + snd1_pcm_direct_open_secondary_client +#define snd_pcm_direct_parse_open_conf \ + snd1_pcm_direct_parse_open_conf + +int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix); + +static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix) +{ + if (dmix->semid >= 0) { + if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0) + return -errno; + dmix->semid = -1; + } + return 0; +} + +static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num) +{ + struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } }; + return semop(dmix->semid, op, 2); +} + +static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num) +{ + struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT }; + return semop(dmix->semid, &op, 1); +} + +int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix); +int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix); +int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix); +int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix); +int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix); +int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix); +int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params); +int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params); +int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix); +int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm); +int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, + struct slave_params *params, + snd_config_t *cfg); +int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock); +int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid); +int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info); +int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params); +int snd_pcm_direct_hw_free(snd_pcm_t *pcm); +int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params); +int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info); +int snd_pcm_direct_mmap(snd_pcm_t *pcm); +int snd_pcm_direct_munmap(snd_pcm_t *pcm); +int snd_pcm_direct_resume(snd_pcm_t *pcm); +int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); +void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); +int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); +int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); + +int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); +struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); + +struct snd_pcm_direct_open_conf { + key_t ipc_key; + mode_t ipc_perm; + int ipc_gid; + int slowptr; + int max_periods; + snd_config_t *slave; + snd_config_t *bindings; +}; + +int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, int stream, struct snd_pcm_direct_open_conf *rec); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c new file mode 100644 index 0000000..434fc65 --- /dev/null +++ b/src/pcm/pcm_dmix.c @@ -0,0 +1,1326 @@ +/** + * \file pcm/pcm_dmix.c + * \ingroup PCM_Plugins + * \brief PCM Direct Stream Mixing (dmix) Plugin Interface + * \author Jaroslav Kysela + * \date 2003 + */ +/* + * PCM - Direct Stream Mixing + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_direct.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_dmix = ""; +#endif + +#ifndef DOC_HIDDEN +/* start is pending - this state happens when rate plugin does a delayed commit */ +#define STATE_RUN_PENDING 1024 +#endif + +/* + * + */ + +static int shm_sum_discard(snd_pcm_direct_t *dmix); + +/* + * sum ring buffer shared memory area + */ +static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix) +{ + struct shmid_ds buf; + int tmpid, err; + size_t size; + + size = dmix->shmptr->s.channels * + dmix->shmptr->s.buffer_size * + sizeof(signed int); +retryshm: + dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size, + IPC_CREAT | dmix->ipc_perm); + err = -errno; + if (dmix->u.dmix.shmid_sum < 0) { + if (errno == EINVAL) + if ((tmpid = shmget(dmix->ipc_key + 1, 0, dmix->ipc_perm)) != -1) + if (!shmctl(tmpid, IPC_STAT, &buf)) + if (!buf.shm_nattch) + /* no users so destroy the segment */ + if (!shmctl(tmpid, IPC_RMID, NULL)) + goto retryshm; + return err; + } + if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) { + err = -errno; + shm_sum_discard(dmix); + return err; + } + if (dmix->ipc_gid >= 0) { + buf.shm_perm.gid = dmix->ipc_gid; + shmctl(dmix->u.dmix.shmid_sum, IPC_SET, &buf); + } + dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0); + if (dmix->u.dmix.sum_buffer == (void *) -1) { + err = -errno; + shm_sum_discard(dmix); + return err; + } + mlock(dmix->u.dmix.sum_buffer, size); + return 0; +} + +static int shm_sum_discard(snd_pcm_direct_t *dmix) +{ + struct shmid_ds buf; + int ret = 0; + + if (dmix->u.dmix.shmid_sum < 0) + return -EINVAL; + if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0) + return -errno; + dmix->u.dmix.sum_buffer = (void *) -1; + if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) + return -errno; + if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */ + if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0) + return -errno; + ret = 1; + } + dmix->u.dmix.shmid_sum = -1; + return ret; +} + +static void dmix_server_free(snd_pcm_direct_t *dmix) +{ + /* remove the memory region */ + shm_sum_create_or_connect(dmix); + shm_sum_discard(dmix); +} + +/* + * the main function of this plugin: mixing + * FIXME: optimize it for different architectures + */ + +#include "pcm_dmix_generic.c" +#if defined(__i386__) +#include "pcm_dmix_i386.c" +#elif defined(__x86_64__) +#include "pcm_dmix_x86_64.c" +#else +#ifndef DOC_HIDDEN +#define mix_select_callbacks(x) generic_mix_select_callbacks(x) +#define dmix_supported_format generic_dmix_supported_format +#endif +#endif + +static void mix_areas(snd_pcm_direct_t *dmix, + const snd_pcm_channel_area_t *src_areas, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t src_ofs, + snd_pcm_uframes_t dst_ofs, + snd_pcm_uframes_t size) +{ + unsigned int src_step, dst_step; + unsigned int chn, dchn, channels, sample_size; + mix_areas_t *do_mix_areas; + + channels = dmix->channels; + switch (dmix->shmptr->s.format) { + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + sample_size = 2; + do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_16; + break; + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + sample_size = 4; + do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_32; + break; + case SND_PCM_FORMAT_S24_LE: + sample_size = 4; + do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24; + break; + case SND_PCM_FORMAT_S24_3LE: + sample_size = 3; + do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24; + break; + case SND_PCM_FORMAT_U8: + sample_size = 1; + do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_u8; + break; + default: + return; + } + if (dmix->interleaved) { + /* + * process all areas in one loop + * it optimizes the memory accesses for this case + */ + do_mix_areas(size * channels, + (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, + (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, + dmix->u.dmix.sum_buffer + dst_ofs * channels, + sample_size, + sample_size, + sizeof(signed int)); + return; + } + for (chn = 0; chn < channels; chn++) { + dchn = dmix->bindings ? dmix->bindings[chn] : chn; + if (dchn >= dmix->shmptr->s.channels) + continue; + src_step = src_areas[chn].step / 8; + dst_step = dst_areas[dchn].step / 8; + do_mix_areas(size, + ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, + ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, + dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, + dst_step, + src_step, + channels * sizeof(signed int)); + } +} + +static void remix_areas(snd_pcm_direct_t *dmix, + const snd_pcm_channel_area_t *src_areas, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t src_ofs, + snd_pcm_uframes_t dst_ofs, + snd_pcm_uframes_t size) +{ + unsigned int src_step, dst_step; + unsigned int chn, dchn, channels, sample_size; + mix_areas_t *do_remix_areas; + + channels = dmix->channels; + switch (dmix->shmptr->s.format) { + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + sample_size = 2; + do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_16; + break; + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + sample_size = 4; + do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_32; + break; + case SND_PCM_FORMAT_S24_LE: + sample_size = 4; + do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24; + break; + case SND_PCM_FORMAT_S24_3LE: + sample_size = 3; + do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24; + break; + case SND_PCM_FORMAT_U8: + sample_size = 1; + do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_u8; + break; + default: + return; + } + if (dmix->interleaved) { + /* + * process all areas in one loop + * it optimizes the memory accesses for this case + */ + do_remix_areas(size * channels, + (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, + (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, + dmix->u.dmix.sum_buffer + dst_ofs * channels, + sample_size, + sample_size, + sizeof(signed int)); + return; + } + for (chn = 0; chn < channels; chn++) { + dchn = dmix->bindings ? dmix->bindings[chn] : chn; + if (dchn >= dmix->shmptr->s.channels) + continue; + src_step = src_areas[chn].step / 8; + dst_step = dst_areas[dchn].step / 8; + do_remix_areas(size, + ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, + ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, + dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, + dst_step, + src_step, + channels * sizeof(signed int)); + } +} + +/* + * if no concurrent access is allowed in the mixing routines, we need to protect + * the area via semaphore + */ +#ifndef DOC_HIDDEN +#ifdef NO_CONCURRENT_ACCESS +#define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT) +#define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT) +#else +#define dmix_down_sem(dmix) +#define dmix_up_sem(dmix) +#endif +#endif + +/* + * synchronize shm ring buffer with hardware + */ +static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; + snd_pcm_uframes_t appl_ptr, size, transfer; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + + /* calculate the size to transfer */ + /* check the available size in the local buffer + * last_appl_ptr keeps the last updated position + */ + size = dmix->appl_ptr - dmix->last_appl_ptr; + if (! size) + return; + if (size >= pcm->boundary / 2) + size = pcm->boundary - size; + + /* the slave_app_ptr can be far behind the slave_hw_ptr */ + /* reduce mixing and errors here - just skip not catched writes */ + if (dmix->slave_hw_ptr <= dmix->slave_appl_ptr) + slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr; + else + slave_size = dmix->slave_appl_ptr + (dmix->slave_boundary - dmix->slave_hw_ptr); + if (slave_size > dmix->slave_buffer_size) { + transfer = dmix->slave_buffer_size - slave_size; + if (transfer > size) + transfer = size; + dmix->last_appl_ptr += transfer; + dmix->last_appl_ptr %= pcm->boundary; + dmix->slave_appl_ptr += transfer; + dmix->slave_appl_ptr %= dmix->slave_boundary; + size = dmix->appl_ptr - dmix->last_appl_ptr; + if (! size) + return; + if (size >= pcm->boundary / 2) + size = pcm->boundary - size; + } + + /* check the available size in the slave PCM buffer */ + slave_hw_ptr = dmix->slave_hw_ptr; + /* don't write on the last active period - this area may be cleared + * by the driver during mix operation... + */ + slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size; + slave_hw_ptr += dmix->slave_buffer_size; + if (slave_hw_ptr >= dmix->slave_boundary) + slave_hw_ptr -= dmix->slave_boundary; + if (slave_hw_ptr < dmix->slave_appl_ptr) + slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr); + else + slave_size = slave_hw_ptr - dmix->slave_appl_ptr; + if (slave_size < size) + size = slave_size; + if (! size) + return; + + /* add sample areas here */ + src_areas = snd_pcm_mmap_areas(pcm); + dst_areas = snd_pcm_mmap_areas(dmix->spcm); + appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; + dmix->last_appl_ptr += size; + dmix->last_appl_ptr %= pcm->boundary; + slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; + dmix->slave_appl_ptr += size; + dmix->slave_appl_ptr %= dmix->slave_boundary; + dmix_down_sem(dmix); + for (;;) { + transfer = size; + if (appl_ptr + transfer > pcm->buffer_size) + transfer = pcm->buffer_size - appl_ptr; + if (slave_appl_ptr + transfer > dmix->slave_buffer_size) + transfer = dmix->slave_buffer_size - slave_appl_ptr; + mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); + size -= transfer; + if (! size) + break; + slave_appl_ptr += transfer; + slave_appl_ptr %= dmix->slave_buffer_size; + appl_ptr += transfer; + appl_ptr %= pcm->buffer_size; + } + dmix_up_sem(dmix); +} + +/* + * synchronize hardware pointer (hw_ptr) with ours + */ +static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dmix->state = SND_PCM_STATE_DISCONNECTED; + return -ENODEV; + default: + break; + } + if (dmix->slowptr) + snd_pcm_hwsync(dmix->spcm); + old_slave_hw_ptr = dmix->slave_hw_ptr; + slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; + if (diff == 0) /* fast path */ + return 0; + if (dmix->state != SND_PCM_STATE_RUNNING && + dmix->state != SND_PCM_STATE_DRAINING) + /* not really started yet - don't update hw_ptr */ + return 0; + if (diff < 0) { + slave_hw_ptr += dmix->slave_boundary; + diff = slave_hw_ptr - old_slave_hw_ptr; + } + dmix->hw_ptr += diff; + dmix->hw_ptr %= pcm->boundary; + if (pcm->stop_threshold >= pcm->boundary) /* don't care */ + return 0; + avail = snd_pcm_mmap_playback_avail(pcm); + if (avail > dmix->avail_max) + dmix->avail_max = avail; + if (avail >= pcm->stop_threshold) { + snd_timer_stop(dmix->timer); + gettimestamp(&dmix->trigger_tstamp, pcm->monotonic); + if (dmix->state == SND_PCM_STATE_RUNNING) { + dmix->state = SND_PCM_STATE_XRUN; + return -EPIPE; + } + dmix->state = SND_PCM_STATE_SETUP; + /* clear queue to remove pending poll events */ + snd_pcm_direct_clear_timer_queue(dmix); + } + return 0; +} + +/* + * plugin implementation + */ + +static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_state_t state; + state = snd_pcm_state(dmix->spcm); + switch (state) { + case SND_PCM_STATE_SUSPENDED: + return state; + case SND_PCM_STATE_DISCONNECTED: + return state; + default: + break; + } + if (dmix->state == STATE_RUN_PENDING) + return SNDRV_PCM_STATE_RUNNING; + return dmix->state; +} + +static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + switch (dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + snd_pcm_dmix_sync_ptr(pcm); + break; + default: + break; + } + memset(status, 0, sizeof(*status)); + status->state = snd_pcm_dmix_state(pcm); + status->trigger_tstamp = dmix->trigger_tstamp; + gettimestamp(&status->tstamp, pcm->monotonic); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max; + dmix->avail_max = 0; + return 0; +} + +static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + int err; + + switch(dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + err = snd_pcm_dmix_sync_ptr(pcm); + if (err < 0) + return err; + /* fallthru */ + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + case STATE_RUN_PENDING: + *delayp = snd_pcm_mmap_playback_hw_avail(pcm); + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EBADFD; + } +} + +static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + switch(dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + /* sync slave PCM */ + return snd_pcm_dmix_sync_ptr(pcm); + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + case STATE_RUN_PENDING: + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EBADFD; + } +} + +static int snd_pcm_dmix_prepare(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + snd_pcm_direct_check_interleave(dmix, pcm); + dmix->state = SND_PCM_STATE_PREPARED; + dmix->appl_ptr = dmix->last_appl_ptr = 0; + dmix->hw_ptr = 0; + return snd_pcm_direct_set_timer_params(dmix); +} + +static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix) +{ + dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + if (pcm->buffer_size > pcm->period_size * 2) + return; + /* If we have too litte periods, better to align the start position + * to the period boundary so that the interrupt can be handled properly + * at the right time. + */ + dmix->slave_appl_ptr = ((dmix->slave_appl_ptr + dmix->slave_period_size - 1) + / dmix->slave_period_size) * dmix->slave_period_size; +} + +static int snd_pcm_dmix_reset(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + dmix->hw_ptr %= pcm->period_size; + dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr; + reset_slave_ptr(pcm, dmix); + return 0; +} + +static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix) +{ + int err; + + snd_pcm_hwsync(dmix->spcm); + reset_slave_ptr(pcm, dmix); + err = snd_timer_start(dmix->timer); + if (err < 0) + return err; + dmix->state = SND_PCM_STATE_RUNNING; + return 0; +} + +static int snd_pcm_dmix_start(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_sframes_t avail; + int err; + + if (dmix->state != SND_PCM_STATE_PREPARED) + return -EBADFD; + avail = snd_pcm_mmap_playback_hw_avail(pcm); + if (avail == 0) + dmix->state = STATE_RUN_PENDING; + else if (avail < 0) + return 0; + else { + if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) + return err; + snd_pcm_dmix_sync_area(pcm); + } + gettimestamp(&dmix->trigger_tstamp, pcm->monotonic); + return 0; +} + +static int snd_pcm_dmix_drop(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + if (dmix->state == SND_PCM_STATE_OPEN) + return -EBADFD; + dmix->state = SND_PCM_STATE_SETUP; + snd_pcm_direct_timer_stop(dmix); + return 0; +} + +static int snd_pcm_dmix_drain(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t stop_threshold; + int err; + + if (dmix->state == SND_PCM_STATE_OPEN) + return -EBADFD; + if (pcm->mode & SND_PCM_NONBLOCK) + return -EAGAIN; + if (dmix->state == SND_PCM_STATE_PREPARED) { + if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) + snd_pcm_dmix_start(pcm); + else { + snd_pcm_dmix_drop(pcm); + return 0; + } + } + + if (dmix->state == SND_PCM_STATE_XRUN) { + snd_pcm_dmix_drop(pcm); + return 0; + } + + stop_threshold = pcm->stop_threshold; + if (pcm->stop_threshold > pcm->buffer_size) + pcm->stop_threshold = pcm->buffer_size; + dmix->state = SND_PCM_STATE_DRAINING; + do { + err = snd_pcm_dmix_sync_ptr(pcm); + if (err < 0) { + snd_pcm_dmix_drop(pcm); + return err; + } + if (dmix->state == SND_PCM_STATE_DRAINING) { + snd_pcm_dmix_sync_area(pcm); + snd_pcm_wait_nocheck(pcm, -1); + snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ + } + } while (dmix->state == SND_PCM_STATE_DRAINING); + pcm->stop_threshold = stop_threshold; + return 0; +} + +static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_hw_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t slave_appl_ptr, slave_size; + snd_pcm_uframes_t appl_ptr, size, transfer, result; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) + return snd_pcm_dmix_hwsync(pcm); + + if (dmix->last_appl_ptr < dmix->appl_ptr) + size = dmix->appl_ptr - dmix->last_appl_ptr; + else + size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr); + if (frames < size) + size = frames; + snd_pcm_mmap_appl_backward(pcm, size); + frames -= size; + if (!frames) + return size; + result = size; + + if (dmix->hw_ptr < dmix->appl_ptr) + size = dmix->appl_ptr - dmix->hw_ptr; + else + size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr); + if (size > frames) + size = frames; + if (dmix->slave_hw_ptr < dmix->slave_appl_ptr) + slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr; + else + slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr); + if (slave_size < size) + size = slave_size; + frames -= size; + result += size; + + /* add sample areas here */ + src_areas = snd_pcm_mmap_areas(pcm); + dst_areas = snd_pcm_mmap_areas(dmix->spcm); + dmix->last_appl_ptr -= size; + dmix->last_appl_ptr %= pcm->boundary; + appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; + dmix->slave_appl_ptr -= size; + dmix->slave_appl_ptr %= dmix->slave_boundary; + slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; + dmix_down_sem(dmix); + for (;;) { + transfer = size; + if (appl_ptr + transfer > pcm->buffer_size) + transfer = pcm->buffer_size - appl_ptr; + if (slave_appl_ptr + transfer > dmix->slave_buffer_size) + transfer = dmix->slave_buffer_size - slave_appl_ptr; + remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); + size -= transfer; + if (! size) + break; + slave_appl_ptr += transfer; + slave_appl_ptr %= dmix->slave_buffer_size; + appl_ptr += transfer; + appl_ptr %= pcm->buffer_size; + } + dmix->last_appl_ptr -= frames; + dmix->last_appl_ptr %= pcm->boundary; + dmix->slave_appl_ptr -= frames; + dmix->slave_appl_ptr %= dmix->slave_boundary; + dmix_up_sem(dmix); + + snd_pcm_mmap_appl_backward(pcm, frames); + + return result + frames; +} + +static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_mmap_playback_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) +{ + return -ENODEV; +} + +static snd_pcm_sframes_t snd_pcm_dmix_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) +{ + return -ENODEV; +} + +static int snd_pcm_dmix_close(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + if (dmix->timer) + snd_timer_close(dmix->timer); + snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + snd_pcm_close(dmix->spcm); + if (dmix->server) + snd_pcm_direct_server_discard(dmix); + if (dmix->client) + snd_pcm_direct_client_discard(dmix); + shm_sum_discard(dmix); + if (snd_pcm_direct_shm_discard(dmix)) { + if (snd_pcm_direct_semaphore_discard(dmix)) + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + } else + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + free(dmix->bindings); + pcm->private_data = NULL; + free(dmix); + return 0; +} + +static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + int err; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (! size) + return 0; + snd_pcm_mmap_appl_forward(pcm, size); + if (dmix->state == STATE_RUN_PENDING) { + if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) + return err; + } else if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) + snd_pcm_dmix_sync_ptr(pcm); + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) { + /* ok, we commit the changes after the validation of area */ + /* it's intended, although the result might be crappy */ + snd_pcm_dmix_sync_area(pcm); + /* clear timer queue to avoid a bogus return from poll */ + if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min) + snd_pcm_direct_clear_timer_queue(dmix); + } + return size; +} + +static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) + snd_pcm_dmix_sync_ptr(pcm); + return snd_pcm_mmap_playback_avail(pcm); +} + +static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm, + snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t avail1; + int ok = 0; + + while (1) { + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) + snd_pcm_dmix_sync_ptr(pcm); + avail1 = snd_pcm_mmap_playback_avail(pcm); + if (ok && *avail == avail1) + break; + *avail = avail1; + *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm); + } + return 0; +} + +static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + if (dmix->state == SND_PCM_STATE_RUNNING) + snd_pcm_dmix_sync_area(pcm); + return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents); +} + + +static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + + snd_output_printf(out, "Direct Stream Mixing PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + if (dmix->spcm) + snd_pcm_dump(dmix->spcm, out); +} + +static const snd_pcm_ops_t snd_pcm_dmix_ops = { + .close = snd_pcm_dmix_close, + .info = snd_pcm_direct_info, + .hw_refine = snd_pcm_direct_hw_refine, + .hw_params = snd_pcm_direct_hw_params, + .hw_free = snd_pcm_direct_hw_free, + .sw_params = snd_pcm_direct_sw_params, + .channel_info = snd_pcm_direct_channel_info, + .dump = snd_pcm_dmix_dump, + .nonblock = snd_pcm_direct_nonblock, + .async = snd_pcm_direct_async, + .mmap = snd_pcm_direct_mmap, + .munmap = snd_pcm_direct_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { + .status = snd_pcm_dmix_status, + .state = snd_pcm_dmix_state, + .hwsync = snd_pcm_dmix_hwsync, + .delay = snd_pcm_dmix_delay, + .prepare = snd_pcm_dmix_prepare, + .reset = snd_pcm_dmix_reset, + .start = snd_pcm_dmix_start, + .drop = snd_pcm_dmix_drop, + .drain = snd_pcm_dmix_drain, + .pause = snd_pcm_dmix_pause, + .rewindable = snd_pcm_dmix_rewindable, + .rewind = snd_pcm_dmix_rewind, + .forwardable = snd_pcm_dmix_forwardable, + .forward = snd_pcm_dmix_forward, + .resume = snd_pcm_direct_resume, + .link = NULL, + .link_slaves = NULL, + .unlink = NULL, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_dmix_readi, + .readn = snd_pcm_dmix_readn, + .avail_update = snd_pcm_dmix_avail_update, + .mmap_commit = snd_pcm_dmix_mmap_commit, + .htimestamp = snd_pcm_dmix_htimestamp, + .poll_descriptors = NULL, + .poll_descriptors_count = NULL, + .poll_revents = snd_pcm_dmix_poll_revents, +}; + +/** + * \brief Creates a new dmix PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param opts Direct PCM configurations + * \param params Parameters for slave + * \param root Configuration root + * \param sconf Slave configuration + * \param stream PCM Direction (stream) + * \param mode PCM Mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, + struct snd_pcm_direct_open_conf *opts, + struct slave_params *params, + snd_config_t *root, snd_config_t *sconf, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm = NULL, *spcm = NULL; + snd_pcm_direct_t *dmix = NULL; + int ret, first_instance; + int fail_sem_loop = 10; + + assert(pcmp); + + if (stream != SND_PCM_STREAM_PLAYBACK) { + SNDERR("The dmix plugin supports only playback stream"); + return -EINVAL; + } + + dmix = calloc(1, sizeof(snd_pcm_direct_t)); + if (!dmix) { + ret = -ENOMEM; + goto _err_nosem; + } + + ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings); + if (ret < 0) + goto _err_nosem; + + dmix->ipc_key = opts->ipc_key; + dmix->ipc_perm = opts->ipc_perm; + dmix->ipc_gid = opts->ipc_gid; + dmix->semid = -1; + dmix->shmid = -1; + + ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode); + if (ret < 0) + goto _err; + + + while (1) { + ret = snd_pcm_direct_semaphore_create_or_connect(dmix); + if (ret < 0) { + SNDERR("unable to create IPC semaphore"); + goto _err_nosem; + } + ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + if (ret < 0) { + snd_pcm_direct_semaphore_discard(dmix); + if (--fail_sem_loop <= 0) + goto _err_nosem; + continue; + } + break; + } + + first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix); + if (ret < 0) { + SNDERR("unable to create IPC shm instance"); + goto _err; + } + + pcm->ops = &snd_pcm_dmix_ops; + pcm->fast_ops = &snd_pcm_dmix_fast_ops; + pcm->private_data = dmix; + dmix->state = SND_PCM_STATE_OPEN; + dmix->slowptr = opts->slowptr; + dmix->max_periods = opts->max_periods; + dmix->sync_ptr = snd_pcm_dmix_sync_ptr; + + if (first_instance) { + /* recursion is already checked in + snd_pcm_direct_get_slave_ipc_offset() */ + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK, NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dmix plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_slave(dmix, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + + dmix->spcm = spcm; + + if (dmix->shmptr->use_server) { + dmix->server_free = dmix_server_free; + + ret = snd_pcm_direct_server_create(dmix); + if (ret < 0) { + SNDERR("unable to create server"); + goto _err; + } + } + + dmix->shmptr->type = spcm->type; + } else { + if (dmix->shmptr->use_server) { + /* up semaphore to avoid deadlock */ + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_client_connect(dmix); + if (ret < 0) { + SNDERR("unable to connect client"); + goto _err_nosem; + } + + snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client"); + if (ret < 0) + goto _err; + } else { + + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK | + SND_PCM_APPEND, + NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dmix plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + } + + dmix->spcm = spcm; + } + + ret = shm_sum_create_or_connect(dmix); + if (ret < 0) { + SNDERR("unable to initialize sum ring buffer"); + goto _err; + } + + ret = snd_pcm_direct_initialize_poll_fd(dmix); + if (ret < 0) { + SNDERR("unable to initialize poll_fd"); + goto _err; + } + + mix_select_callbacks(dmix); + + pcm->poll_fd = dmix->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ + + pcm->mmap_rw = 1; + snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0); + + if (dmix->channels == UINT_MAX) + dmix->channels = dmix->shmptr->s.channels; + + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + + *pcmp = pcm; + return 0; + + _err: + if (dmix->timer) + snd_timer_close(dmix->timer); + if (dmix->server) + snd_pcm_direct_server_discard(dmix); + if (dmix->client) + snd_pcm_direct_client_discard(dmix); + if (spcm) + snd_pcm_close(spcm); + if (dmix->u.dmix.shmid_sum >= 0) + shm_sum_discard(dmix); + if (dmix->shmid >= 0) + snd_pcm_direct_shm_discard(dmix); + if (snd_pcm_direct_semaphore_discard(dmix) < 0) + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + _err_nosem: + if (dmix) { + free(dmix->bindings); + free(dmix); + } + if (pcm) + snd_pcm_free(pcm); + return ret; +} + +/*! \page pcm_plugins + +\section pcm_plugins_dmix Plugin: dmix + +This plugin provides direct mixing of multiple streams. The resolution +for 32-bit mixing is only 24-bit. The low significant byte is filled with +zeros. The extra 8 bits are used for the saturation. + +\code +pcm.name { + type dmix # Direct mix + ipc_key INT # unique IPC key + ipc_key_add_uid BOOL # add current uid to unique IPC key + ipc_perm INT # IPC permissions (octal, default 0600) + slave STR + # or + slave { # Slave definition + pcm STR # slave PCM name + # or + pcm { } # slave PCM definition + format STR # format definition + rate INT # rate definition + channels INT + period_time INT # in usec + # or + period_size INT # in bytes + buffer_time INT # in usec + # or + buffer_size INT # in bytes + periods INT # when buffer_size or buffer_time is not specified + } + bindings { # note: this is client independent!!! + N INT # maps slave channel to client channel N + } + slowptr BOOL # slow but more precise pointer updates +} +\endcode + +ipc_key specfies the unique IPC key in integer. +This number must be unique for each different dmix definition, +since the shared memory is created with this key number. +When ipc_key_add_uid is set true, the uid value is +added to the value set in ipc_key. This will +avoid the confliction of the same IPC key with different users +concurrently. + +Note that the dmix plugin itself supports only a single configuration. +That is, it supports only the fixed rate (default 48000), format +(\c S16), channels (2), and period_time (125000). +For using other configuration, you have to set the value explicitly +in the slave PCM definition. The rate, format and channels can be +covered by an additional \ref pcm_plugins_dmix "plug plugin", +but there is only one base configuration, anyway. + +An example configuration for setting 44100 Hz, \c S32_LE format +as the slave PCM of "hw:0" is like below: +\code +pcm.dmix_44 { + type dmix + ipc_key 321456 # any unique value + ipc_key_add_uid true + slave { + pcm "hw:0" + format S32_LE + rate 44100 + } +} +\endcode +You can hear 48000 Hz samples still using this dmix pcm via plug plugin +like: +\code +% aplay -Dplug:dmix_44 foo_48k.wav +\endcode + +For using the dmix plugin for OSS emulation device, you have to set +the period and the buffer sizes in power of two. For example, +\code +pcm.dmixoss { + type dmix + ipc_key 321456 # any unique value + ipc_key_add_uid true + slave { + pcm "hw:0" + period_time 0 + period_size 1024 # must be power of 2 + buffer_size 8192 # ditto + } +} +\endcode +period_time 0 must be set, too, for resetting the +default value. In the case of soundcards with multi-channel IO, +adding the bindings would help +\code +pcm.dmixoss { + ... + bindings { + 0 0 # map from 0 to 0 + 1 1 # map from 1 to 1 + } +} +\endcode +so that only the first two channels are used by dmix. +Also, note that ICE1712 have the limited buffer size, 5513 frames +(corresponding to 640 kB). In this case, reduce the buffer_size +to 4096. + +\subsection pcm_plugins_dmix_funcref Function reference + +
    +
  • snd_pcm_dmix_open() +
  • _snd_pcm_dmix_open() +
+ +*/ + +/** + * \brief Creates a new dmix PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with dmix PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_t *sconf; + struct slave_params params; + struct snd_pcm_direct_open_conf dopen; + int bsize, psize; + int err; + + err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); + if (err < 0) + return err; + + /* the default settings, it might be invalid for some hardware */ + params.format = SND_PCM_FORMAT_S16; + params.rate = 48000; + params.channels = 2; + params.period_time = -1; + params.buffer_time = -1; + bsize = psize = -1; + params.periods = 3; + + err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, + SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, + SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, + SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, + SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, + SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, + SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, + SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, + SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); + if (err < 0) + return err; + + /* set a reasonable default */ + if (psize == -1 && params.period_time == -1) + params.period_time = 125000; /* 0.125 seconds */ + + if (params.format == -2) + params.format = SND_PCM_FORMAT_UNKNOWN; + else if (!(dmix_supported_format & (1ULL << params.format))) { + /* sorry, limited features */ + SNDERR("Unsupported format"); + snd_config_delete(sconf); + return -EINVAL; + } + + params.period_size = psize; + params.buffer_size = bsize; + + err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms, + root, sconf, stream, mode); + snd_config_delete(sconf); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_dmix_generic.c b/src/pcm/pcm_dmix_generic.c new file mode 100644 index 0000000..9e9d3c3 --- /dev/null +++ b/src/pcm/pcm_dmix_generic.c @@ -0,0 +1,535 @@ +#if 0 +//#if defined(__i386__) || defined(__x86_64__) +#define LOCK_PREFIX "lock ; " +#define ARCH_ADD(p,a) \ + __asm__ __volatile__(LOCK_PREFIX "addl %1,%0" \ + :"=m" (*p) \ + :"ir" (a), "m" (*p)) +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, int size) +{ + unsigned long prev; + switch (size) { + case 1: + __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + case 2: + __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + case 4: + __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + } + return old; +} + +#define ARCH_CMPXCHG(ptr,o,n)\ + ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ + (unsigned long)(n),sizeof(*(ptr)))) +#define IS_CONCURRENT 1 /* check race */ +#endif + +#ifndef ARCH_ADD +#define ARCH_ADD(p,a) (*(p) += (a)) +#define ARCH_CMPXCHG(p,a,b) (*(p)) /* fake */ +#define NO_CONCURRENT_ACCESS /* use semaphore to avoid race */ +#define IS_CONCURRENT 0 /* no race check */ +#endif + +#if IS_CONCURRENT +static void mix_areas_16(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + register signed int sample, old_sample; + + for (;;) { + sample = *src; + old_sample = *sum; + if (ARCH_CMPXCHG(dst, 0, 1) == 0) + sample -= old_sample; + ARCH_ADD(sum, sample); + do { + old_sample = *sum; + if (old_sample > 0x7fff) + sample = 0x7fff; + else if (old_sample < -0x8000) + sample = -0x8000; + else + sample = old_sample; + *dst = sample; + } while (IS_CONCURRENT && *sum != old_sample); + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void mix_areas_32(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + register signed int sample, old_sample; + + for (;;) { + sample = *src >> 8; + old_sample = *sum; + if (ARCH_CMPXCHG(dst, 0, 1) == 0) + sample -= old_sample; + ARCH_ADD(sum, sample); + do { + old_sample = *sum; + if (old_sample > 0x7fffff) + sample = 0x7fffffff; + else if (old_sample < -0x800000) + sample = -0x80000000; + else + sample = old_sample * 256; + *dst = sample; + } while (IS_CONCURRENT && *sum != old_sample); + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void mix_select_callbacks(snd_pcm_direct_t *dmix) +{ + dmix->u.dmix.mix_areas_16 = mix_areas_16; + dmix->u.dmix.mix_areas_32 = mix_areas_32; +} + +#else + +/* non-concurrent version, supporting both endians */ +#define generic_dmix_supported_format \ + ((1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S32_LE) |\ + (1ULL << SND_PCM_FORMAT_S16_BE) | (1ULL << SND_PCM_FORMAT_S32_BE) |\ + (1ULL << SND_PCM_FORMAT_S24_LE) | (1ULL << SND_PCM_FORMAT_S24_3LE) | \ + (1ULL << SND_PCM_FORMAT_U8)) + +#include + +static void generic_mix_areas_16_native(unsigned int size, + volatile signed short *dst, + signed short *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = *src; + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fff) + sample = 0x7fff; + else if (sample < -0x8000) + sample = -0x8000; + *dst = sample; + } + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_remix_areas_16_native(unsigned int size, + volatile signed short *dst, + signed short *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = *src; + if (! *dst) { + *sum = -sample; + *dst = -sample; + } else { + *sum = sample = *sum - sample; + if (sample > 0x7fff) + sample = 0x7fff; + else if (sample < -0x8000) + sample = -0x8000; + *dst = sample; + } + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_mix_areas_32_native(unsigned int size, + volatile signed int *dst, + signed int *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = *src >> 8; + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fffff) + sample = 0x7fffffff; + else if (sample < -0x800000) + sample = -0x80000000; + else + sample *= 256; + *dst = sample; + } + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_remix_areas_32_native(unsigned int size, + volatile signed int *dst, + signed int *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = *src >> 8; + if (! *dst) { + *sum = -sample; + *dst = -*src; + } else { + *sum = sample = *sum - sample; + if (sample > 0x7fffff) + sample = 0x7fffffff; + else if (sample < -0x800000) + sample = -0x80000000; + else + sample *= 256; + *dst = sample; + } + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_mix_areas_16_swap(unsigned int size, + volatile signed short *dst, + signed short *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = (signed short) bswap_16(*src); + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fff) + sample = 0x7fff; + else if (sample < -0x8000) + sample = -0x8000; + *dst = (signed short) bswap_16((signed short) sample); + } + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_remix_areas_16_swap(unsigned int size, + volatile signed short *dst, + signed short *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = (signed short) bswap_16(*src); + if (! *dst) { + *sum = -sample; + *dst = (signed short) bswap_16((signed short) -sample); + } else { + *sum = sample = *sum - sample; + if (sample > 0x7fff) + sample = 0x7fff; + else if (sample < -0x8000) + sample = -0x8000; + *dst = (signed short) bswap_16((signed short) sample); + } + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_mix_areas_32_swap(unsigned int size, + volatile signed int *dst, + signed int *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = bswap_32(*src) >> 8; + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fffff) + sample = 0x7fffffff; + else if (sample < -0x800000) + sample = -0x80000000; + else + sample *= 256; + *dst = bswap_32(sample); + } + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_remix_areas_32_swap(unsigned int size, + volatile signed int *dst, + signed int *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = bswap_32(*src) >> 8; + if (! *dst) { + *sum = -sample; + *dst = bswap_32(-sample); + } else { + *sum = sample = *sum - sample; + if (sample > 0x7fffff) + sample = 0x7fffffff; + else if (sample < -0x800000) + sample = -0x80000000; + else + sample *= 256; + *dst = bswap_32(sample); + } + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +/* always little endian */ +static void generic_mix_areas_24(unsigned int size, + volatile unsigned char *dst, + unsigned char *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = src[0] | (src[1] << 8) | (((signed char *)src)[2] << 16); + if (!(dst[0] | dst[1] | dst[2])) { + *sum = sample; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fffff) + sample = 0x7fffff; + else if (sample < -0x800000) + sample = -0x800000; + } + dst[0] = sample; + dst[1] = sample >> 8; + dst[2] = sample >> 16; + if (!--size) + return; + dst += dst_step; + src += src_step; + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_remix_areas_24(unsigned int size, + volatile unsigned char *dst, + unsigned char *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = src[0] | (src[1] << 8) | (((signed char *)src)[2] << 16); + if (!(dst[0] | dst[1] | dst[2])) { + sample = -sample; + *sum = sample; + } else { + *sum = sample = *sum - sample; + if (sample > 0x7fffff) + sample = 0x7fffff; + else if (sample < -0x800000) + sample = -0x800000; + } + dst[0] = sample; + dst[1] = sample >> 8; + dst[2] = sample >> 16; + if (!--size) + return; + dst += dst_step; + src += src_step; + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_mix_areas_u8(unsigned int size, + volatile unsigned char *dst, + unsigned char *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + for (;;) { + register int sample = *src - 0x80; + if (*dst == 0x80) { + *sum = sample; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7f) + sample = 0x7f; + else if (sample < -0x80) + sample = -0x80; + } + *dst = sample + 0x80; + if (!--size) + return; + dst += dst_step; + src += src_step; + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void generic_remix_areas_u8(unsigned int size, + volatile unsigned char *dst, + unsigned char *src, + volatile signed int *sum, + size_t dst_step, + size_t src_step, + size_t sum_step) +{ + for (;;) { + register int sample = *src - 0x80; + if (*dst == 0x80) { + sample = -sample; + *sum = sample; + } else { + *sum = sample = *sum - sample; + if (sample > 0x7f) + sample = 0x7f; + else if (sample < -0x80) + sample = -0x80; + } + *dst = sample + 0x80; + if (!--size) + return; + dst += dst_step; + src += src_step; + sum = (signed int *) ((char *)sum + sum_step); + } +} + + +static void generic_mix_select_callbacks(snd_pcm_direct_t *dmix) +{ + if (snd_pcm_format_cpu_endian(dmix->shmptr->s.format)) { + dmix->u.dmix.mix_areas_16 = generic_mix_areas_16_native; + dmix->u.dmix.mix_areas_32 = generic_mix_areas_32_native; + dmix->u.dmix.remix_areas_16 = generic_remix_areas_16_native; + dmix->u.dmix.remix_areas_32 = generic_remix_areas_32_native; + } else { + dmix->u.dmix.mix_areas_16 = generic_mix_areas_16_swap; + dmix->u.dmix.mix_areas_32 = generic_mix_areas_32_swap; + dmix->u.dmix.remix_areas_16 = generic_remix_areas_16_swap; + dmix->u.dmix.remix_areas_32 = generic_remix_areas_32_swap; + } + dmix->u.dmix.mix_areas_24 = generic_mix_areas_24; + dmix->u.dmix.mix_areas_u8 = generic_mix_areas_u8; + dmix->u.dmix.remix_areas_24 = generic_remix_areas_24; + dmix->u.dmix.remix_areas_u8 = generic_remix_areas_u8; +} + +#endif diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c new file mode 100644 index 0000000..dcc6b9a --- /dev/null +++ b/src/pcm/pcm_dmix_i386.c @@ -0,0 +1,133 @@ +/* + * optimized mixing code for i386 + */ + +#define MIX_AREAS_16 mix_areas_16 +#define MIX_AREAS_16_MMX mix_areas_16_mmx +#define MIX_AREAS_32 mix_areas_32 +#define MIX_AREAS_24 mix_areas_24 +#define MIX_AREAS_24_CMOV mix_areas_24_cmov +#define LOCK_PREFIX "" +#define XADD "addl" +#define XSUB "subl" +#include "pcm_dmix_i386.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_16_MMX +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef MIX_AREAS_24_CMOV +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define MIX_AREAS_16 remix_areas_16 +#define MIX_AREAS_16_MMX remix_areas_16_mmx +#define MIX_AREAS_32 remix_areas_32 +#define MIX_AREAS_24 remix_areas_24 +#define MIX_AREAS_24_CMOV remix_areas_24_cmov +#define LOCK_PREFIX "" +#define XADD "subl" +#define XSUB "addl" +#include "pcm_dmix_i386.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_16_MMX +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef MIX_AREAS_24_CMOV +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define MIX_AREAS_16 mix_areas_16_smp +#define MIX_AREAS_16_MMX mix_areas_16_smp_mmx +#define MIX_AREAS_32 mix_areas_32_smp +#define MIX_AREAS_24 mix_areas_24_smp +#define MIX_AREAS_24_CMOV mix_areas_24_smp_cmov +#define LOCK_PREFIX "lock ; " +#define XADD "addl" +#define XSUB "subl" +#include "pcm_dmix_i386.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_16_MMX +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef MIX_AREAS_24_CMOV +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define MIX_AREAS_16 remix_areas_16_smp +#define MIX_AREAS_16_MMX remix_areas_16_smp_mmx +#define MIX_AREAS_32 remix_areas_32_smp +#define MIX_AREAS_24 remix_areas_24_smp +#define MIX_AREAS_24_CMOV remix_areas_24_smp_cmov +#define LOCK_PREFIX "lock ; " +#define XADD "subl" +#define XSUB "addl" +#include "pcm_dmix_i386.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_16_MMX +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef MIX_AREAS_24_CMOV +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define i386_dmix_supported_format \ + ((1ULL << SND_PCM_FORMAT_S16_LE) |\ + (1ULL << SND_PCM_FORMAT_S32_LE) |\ + (1ULL << SND_PCM_FORMAT_S24_LE) |\ + (1ULL << SND_PCM_FORMAT_S24_3LE)) + +#define dmix_supported_format \ + (i386_dmix_supported_format | generic_dmix_supported_format) + +static void mix_select_callbacks(snd_pcm_direct_t *dmix) +{ + static int smp = 0, mmx = 0, cmov = 0; + + if (!((1ULL<< dmix->shmptr->s.format) & i386_dmix_supported_format)) { + generic_mix_select_callbacks(dmix); + return; + } + + if (!smp) { + FILE *in; + char line[255]; + + /* try to determine the capabilities of the CPU */ + in = fopen("/proc/cpuinfo", "r"); + if (in) { + while (!feof(in)) { + fgets(line, sizeof(line), in); + if (!strncmp(line, "processor", 9)) + smp++; + else if (!strncmp(line, "flags", 5)) { + if (strstr(line, " mmx")) + mmx = 1; + if (strstr(line, " cmov")) + cmov = 1; + } + } + fclose(in); + } + } + + if (mmx) { + dmix->u.dmix.mix_areas_16 = smp > 1 ? mix_areas_16_smp_mmx : mix_areas_16_mmx; + dmix->u.dmix.remix_areas_16 = smp > 1 ? remix_areas_16_smp_mmx : remix_areas_16_mmx; + } else { + dmix->u.dmix.mix_areas_16 = smp > 1 ? mix_areas_16_smp : mix_areas_16; + dmix->u.dmix.remix_areas_16 = smp > 1 ? remix_areas_16_smp : remix_areas_16; + } + dmix->u.dmix.mix_areas_32 = smp > 1 ? mix_areas_32_smp : mix_areas_32; + dmix->u.dmix.remix_areas_32 = smp > 1 ? remix_areas_32_smp : remix_areas_32; + if (cmov) { + dmix->u.dmix.mix_areas_24 = smp > 1 ? mix_areas_24_smp_cmov : mix_areas_24_cmov; + dmix->u.dmix.remix_areas_24 = smp > 1 ? remix_areas_24_smp_cmov : remix_areas_24_cmov; + } else { + dmix->u.dmix.mix_areas_24 = smp > 1 ? mix_areas_24_smp: mix_areas_24; + dmix->u.dmix.remix_areas_24 = smp > 1 ? remix_areas_24_smp: remix_areas_24; + } +} diff --git a/src/pcm/pcm_dmix_i386.h b/src/pcm/pcm_dmix_i386.h new file mode 100644 index 0000000..462371a --- /dev/null +++ b/src/pcm/pcm_dmix_i386.h @@ -0,0 +1,559 @@ +/** + * \file pcm/pcm_dmix_i386.h + * \ingroup PCM_Plugins + * \brief PCM Direct Stream Mixing (dmix) Plugin Interface - I386 assembler code + * \author Jaroslav Kysela + * \date 2003 + */ +/* + * PCM - Direct Stream Mixing + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * for plain i386 + */ +static void MIX_AREAS_16(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned int old_ebx; + + /* + * ESI - src + * EDI - dst + * EBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */ + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovl %1, %%edi\n" + "\tmovl %2, %%esi\n" + "\tmovl %3, %%ebx\n" + "\tcmpl $0, %0\n" + "\tjnz 2f\n" + "\tjmp 7f\n" + + + /* + * for (;;) + */ + "\t.p2align 4,,15\n" + "1:" + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + + /* + * sample = *src; + * sum_sample = *sum; + * if (cmpxchg(*dst, 0, 1) == 0) + * sample -= sum_sample; + * xadd(*sum, sample); + */ + + "2:" + "\tmovw $0, %%ax\n" + "\tmovw $1, %%cx\n" + "\tmovl (%%ebx), %%edx\n" + "\t" LOCK_PREFIX "cmpxchgw %%cx, (%%edi)\n" + "\tmovswl (%%esi), %%ecx\n" + "\tjnz 3f\n" + "\t" XSUB " %%edx, %%ecx\n" + "3:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%ebx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(v); + * *dst = sample; + * } while (v != *sum); + */ + + "4:" + "\tmovl (%%ebx), %%ecx\n" + "\tcmpl $0x7fff,%%ecx\n" + "\tjg 5f\n" + "\tcmpl $-0x8000,%%ecx\n" + "\tjl 6f\n" + "\tmovw %%cx, (%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 4b\n" + + /* + * while (size-- > 0) + */ + "\tdecl %0\n" + "\tjnz 1b\n" + "\tjmp 7f\n" + + /* + * sample > 0x7fff + */ + + "\t.p2align 4,,15\n" + + "5:" + "\tmovw $0x7fff, (%%edi)\n" + "\tcmpl %%ecx,(%%ebx)\n" + "\tjnz 4b\n" + "\tdecl %0\n" + "\tjnz 1b\n" + "\tjmp 7f\n" + + /* + * sample < -0x8000 + */ + + "\t.p2align 4,,15\n" + + "6:" + "\tmovw $-0x8000, (%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 4b\n" + "\tdecl %0\n" + "\tjnz 1b\n" + + "7:" + "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */ + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_ebx) + : "esi", "edi", "edx", "ecx", "eax" + ); +} + +/* + * MMX optimized + */ +static void MIX_AREAS_16_MMX(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned int old_ebx; + + /* + * ESI - src + * EDI - dst + * EBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */ + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovl %1, %%edi\n" + "\tmovl %2, %%esi\n" + "\tmovl %3, %%ebx\n" + "\tcmpl $0, %0\n" + "\tjnz 2f\n" + "\tjmp 5f\n" + + "\t.p2align 4,,15\n" + "1:" + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + + "2:" + /* + * sample = *src; + * sum_sample = *sum; + * if (cmpxchg(*dst, 0, 1) == 0) + * sample -= sum_sample; + * xadd(*sum, sample); + */ + "\tmovw $0, %%ax\n" + "\tmovw $1, %%cx\n" + "\tmovl (%%ebx), %%edx\n" + "\t" LOCK_PREFIX "cmpxchgw %%cx, (%%edi)\n" + "\tmovswl (%%esi), %%ecx\n" + "\tjnz 3f\n" + "\t" XSUB " %%edx, %%ecx\n" + "3:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%ebx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(v); + * *dst = sample; + * } while (v != *sum); + */ + + "4:" + "\tmovl (%%ebx), %%ecx\n" + "\tmovd %%ecx, %%mm0\n" + "\tpackssdw %%mm1, %%mm0\n" + "\tmovd %%mm0, %%eax\n" + "\tmovw %%ax, (%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 4b\n" + + /* + * while (size-- > 0) + */ + "\tdecl %0\n" + "\tjnz 1b\n" + "\temms\n" + "5:" + "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */ + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_ebx) + : "esi", "edi", "edx", "ecx", "eax" + ); +} + +/* + * for plain i386, 32-bit version (24-bit resolution) + */ +static void MIX_AREAS_32(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned int old_ebx; + + /* + * ESI - src + * EDI - dst + * EBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */ + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovl %1, %%edi\n" + "\tmovl %2, %%esi\n" + "\tmovl %3, %%ebx\n" + "\tcmpl $0, %0\n" + "\tjnz 1f\n" + "\tjmp 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (cmpxchg(*dst, 0, 1) == 0) + * sample -= sum_sample; + * xadd(*sum, sample); + */ + "\tmovl $0, %%eax\n" + "\tmovl $1, %%ecx\n" + "\tmovl (%%ebx), %%edx\n" + "\t" LOCK_PREFIX "cmpxchgl %%ecx, (%%edi)\n" + "\tjnz 2f\n" + "\tmovl (%%esi), %%ecx\n" + /* sample >>= 8 */ + "\tsarl $8, %%ecx\n" + "\t" XSUB " %%edx, %%ecx\n" + "\tjmp 21f\n" + "2:" + "\tmovl (%%esi), %%ecx\n" + /* sample >>= 8 */ + "\tsarl $8, %%ecx\n" + "21:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%ebx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(v); + * *dst = sample; + * } while (v != *sum); + */ + + "3:" + "\tmovl (%%ebx), %%ecx\n" + /* + * if (sample > 0x7fff00) + */ + "\tmovl $0x7fffff, %%eax\n" + "\tcmpl %%eax, %%ecx\n" + "\tjg 4f\n" + /* + * if (sample < -0x800000) + */ + "\tmovl $-0x800000, %%eax\n" + "\tcmpl %%eax, %%ecx\n" + "\tjl 4f\n" + "\tmovl %%ecx, %%eax\n" + "4:" + /* + * sample <<= 8; + */ + "\tsall $8, %%eax\n" + "\tmovl %%eax, (%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tdecl %0\n" + "\tjz 6f\n" + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + "\tjmp 1b\n" + + "6:" + "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */ + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_ebx) + : "esi", "edi", "edx", "ecx", "eax" + ); +} + +/* + * 24-bit version for plain i386 + */ +static void MIX_AREAS_24(unsigned int size, + volatile unsigned char *dst, unsigned char *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned int old_ebx; + + /* + * ESI - src + * EDI - dst + * EBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */ + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovl %1, %%edi\n" + "\tmovl %2, %%esi\n" + "\tmovl %3, %%ebx\n" + "\tcmpl $0, %0\n" + "\tjnz 1f\n" + "\tjmp 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (test_and_set_bit(0, dst) == 0) + * sample -= sum_sample; + * *sum += sample; + */ + "\tmovsbl 2(%%esi), %%eax\n" + "\tmovzwl (%%esi), %%ecx\n" + "\tmovl (%%ebx), %%edx\n" + "\tsall $16, %%eax\n" + "\torl %%eax, %%ecx\n" + "\t" LOCK_PREFIX "btsw $0, (%%edi)\n" + "\tjc 2f\n" + "\t" XSUB " %%edx, %%ecx\n" + "2:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%ebx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(sample); + * *dst = sample | 1; + * } while (old_sample != *sum); + */ + + "3:" + "\tmovl (%%ebx), %%ecx\n" + /* + * if (sample > 0x7fffff) + */ + "\tmovl $0x7fffff, %%eax\n" + "\tcmpl %%eax, %%ecx\n" + "\tjg 4f\n" + /* + * if (sample < -0x7fffff) + */ + "\tmovl $-0x7fffff, %%eax\n" + "\tcmpl %%eax, %%ecx\n" + "\tjl 4f\n" + "\tmovl %%ecx, %%eax\n" + "\torl $1, %%eax\n" + "4:" + "\tmovw %%ax, (%%edi)\n" + "\tshrl $16, %%eax\n" + "\tmovb %%al, 2(%%edi)\n" + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tdecl %0\n" + "\tjz 6f\n" + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + "\tjmp 1b\n" + + "6:" + "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */ + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_ebx) + : "esi", "edi", "edx", "ecx", "eax" + ); +} + +/* + * 24-bit version for Pentium Pro/II + */ +static void MIX_AREAS_24_CMOV(unsigned int size, + volatile unsigned char *dst, unsigned char *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned int old_ebx; + + /* + * ESI - src + * EDI - dst + * EBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */ + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovl %1, %%edi\n" + "\tmovl %2, %%esi\n" + "\tmovl %3, %%ebx\n" + "\tcmpl $0, %0\n" + "\tjz 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (test_and_set_bit(0, dst) == 0) + * sample -= sum_sample; + * *sum += sample; + */ + "\tmovsbl 2(%%esi), %%eax\n" + "\tmovzwl (%%esi), %%ecx\n" + "\tmovl (%%ebx), %%edx\n" + "\tsall $16, %%eax\n" + "\t" LOCK_PREFIX "btsw $0, (%%edi)\n" + "\tleal (%%ecx,%%eax,1), %%ecx\n" + "\tjc 2f\n" + "\t" XSUB " %%edx, %%ecx\n" + "2:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%ebx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(sample); + * *dst = sample | 1; + * } while (old_sample != *sum); + */ + + "3:" + "\tmovl (%%ebx), %%ecx\n" + + "\tmovl $0x7fffff, %%eax\n" + "\tmovl $-0x7fffff, %%edx\n" + "\tcmpl %%eax, %%ecx\n" + "\tcmovng %%ecx, %%eax\n" + "\tcmpl %%edx, %%ecx\n" + "\tcmovl %%edx, %%eax\n" + + "\torl $1, %%eax\n" + "\tmovw %%ax, (%%edi)\n" + "\tshrl $16, %%eax\n" + "\tmovb %%al, 2(%%edi)\n" + + "\tcmpl %%ecx, (%%ebx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tadd %4, %%edi\n" + "\tadd %5, %%esi\n" + "\tadd %6, %%ebx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + + "6:" + "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */ + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_ebx) + : "esi", "edi", "edx", "ecx", "eax" + ); +} diff --git a/src/pcm/pcm_dmix_x86_64.c b/src/pcm/pcm_dmix_x86_64.c new file mode 100644 index 0000000..831046d --- /dev/null +++ b/src/pcm/pcm_dmix_x86_64.c @@ -0,0 +1,100 @@ +/* + * optimized mixing code for x86-64 + */ + +#define MIX_AREAS_16 mix_areas_16 +#define MIX_AREAS_32 mix_areas_32 +#define MIX_AREAS_24 mix_areas_24 +#define LOCK_PREFIX "" +#define XADD "addl" +#define XSUB "subl" +#include "pcm_dmix_x86_64.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define MIX_AREAS_16 remix_areas_16 +#define MIX_AREAS_32 remix_areas_32 +#define MIX_AREAS_24 remix_areas_24 +#define LOCK_PREFIX "" +#define XADD "subl" +#define XSUB "addl" +#include "pcm_dmix_x86_64.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define MIX_AREAS_16 mix_areas_16_smp +#define MIX_AREAS_32 mix_areas_32_smp +#define MIX_AREAS_24 mix_areas_24_smp +#define LOCK_PREFIX "lock ; " +#define XADD "addl" +#define XSUB "subl" +#include "pcm_dmix_x86_64.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define MIX_AREAS_16 remix_areas_16_smp +#define MIX_AREAS_32 remix_areas_32_smp +#define MIX_AREAS_24 remix_areas_24_smp +#define LOCK_PREFIX "lock ; " +#define XADD "subl" +#define XSUB "addl" +#include "pcm_dmix_x86_64.h" +#undef MIX_AREAS_16 +#undef MIX_AREAS_32 +#undef MIX_AREAS_24 +#undef LOCK_PREFIX +#undef XADD +#undef XSUB + +#define x86_64_dmix_supported_format \ + ((1ULL << SND_PCM_FORMAT_S16_LE) |\ + (1ULL << SND_PCM_FORMAT_S32_LE) |\ + (1ULL << SND_PCM_FORMAT_S24_3LE)) + +#define dmix_supported_format \ + (x86_64_dmix_supported_format | generic_dmix_supported_format) + +static void mix_select_callbacks(snd_pcm_direct_t *dmix) +{ + static int smp = 0; + + if (!((1ULL<< dmix->shmptr->s.format) & x86_64_dmix_supported_format)) { + generic_mix_select_callbacks(dmix); + return; + } + + if (!smp) { + FILE *in; + char line[255]; + + /* try to determine, if we have SMP */ + in = fopen("/proc/cpuinfo", "r"); + if (in) { + while (!feof(in)) { + fgets(line, sizeof(line), in); + if (!strncmp(line, "processor", 9)) + smp++; + } + fclose(in); + } + } + // printf("SMP: %i\n", smp); + dmix->u.dmix.mix_areas_16 = smp > 1 ? mix_areas_16_smp : mix_areas_16; + dmix->u.dmix.remix_areas_16 = smp > 1 ? remix_areas_16_smp : remix_areas_16; + dmix->u.dmix.mix_areas_32 = smp > 1 ? mix_areas_32_smp : mix_areas_32; + dmix->u.dmix.remix_areas_32 = smp > 1 ? remix_areas_32_smp : remix_areas_32; + dmix->u.dmix.mix_areas_24 = smp > 1 ? mix_areas_24_smp : mix_areas_24; + dmix->u.dmix.remix_areas_24 = smp > 1 ? remix_areas_24_smp : remix_areas_24; +} diff --git a/src/pcm/pcm_dmix_x86_64.h b/src/pcm/pcm_dmix_x86_64.h new file mode 100644 index 0000000..ab40f50 --- /dev/null +++ b/src/pcm/pcm_dmix_x86_64.h @@ -0,0 +1,341 @@ +/** + * \file pcm/pcm_dmix_x86_64.h + * \ingroup PCM_Plugins + * \brief PCM Direct Stream Mixing (dmix) Plugin Interface - X86-64 assembler code + * \author Takashi Iwai + * \date 2003 + */ +/* + * PCM - Direct Stream Mixing + * Copyright (c) 2003 by Jaroslav Kysela + * Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * MMX optimized + */ +static void MIX_AREAS_16(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned long long old_rbx; + + /* + * RSI - src + * RDI - dst + * RBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovq %%rbx, %7\n" + /* + * initialization, load RSI, RDI, RBX registers + */ + "\tmovq %1, %%rdi\n" + "\tmovq %2, %%rsi\n" + "\tmovq %3, %%rbx\n" + + /* + * while (size-- > 0) { + */ + "\tcmpl $0, %0\n" + "jz 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (cmpxchg(*dst, 0, 1) == 0) + * sample -= sum_sample; + * xadd(*sum, sample); + */ + "\tmovw $0, %%ax\n" + "\tmovw $1, %%cx\n" + "\tmovl (%%rbx), %%edx\n" + "\t" LOCK_PREFIX "cmpxchgw %%cx, (%%rdi)\n" + "\tmovswl (%%rsi), %%ecx\n" + "\tjnz 2f\n" + "\t" XSUB " %%edx, %%ecx\n" + "2:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%rbx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(v); + * *dst = sample; + * } while (v != *sum); + */ + + "3:" + "\tmovl (%%rbx), %%ecx\n" + "\tmovd %%ecx, %%mm0\n" + "\tpackssdw %%mm1, %%mm0\n" + "\tmovd %%mm0, %%eax\n" + "\tmovw %%ax, (%%rdi)\n" + "\tcmpl %%ecx, (%%rbx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tadd %4, %%rdi\n" + "\tadd %5, %%rsi\n" + "\tadd %6, %%rbx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + + "6:" + + "\temms\n" + "\tmovq %7, %%rbx\n" + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_rbx) + : "rsi", "rdi", "edx", "ecx", "eax" + ); +} + +/* + * 32-bit version (24-bit resolution) + */ +static void MIX_AREAS_32(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned long long old_rbx; + + /* + * RSI - src + * RDI - dst + * RBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovq %%rbx, %7\n" + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovq %1, %%rdi\n" + "\tmovq %2, %%rsi\n" + "\tmovq %3, %%rbx\n" + + /* + * while (size-- > 0) { + */ + "\tcmpl $0, %0\n" + "jz 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (cmpxchg(*dst, 0, 1) == 0) + * sample -= sum_sample; + * xadd(*sum, sample); + */ + "\tmovl $0, %%eax\n" + "\tmovl $1, %%ecx\n" + "\tmovl (%%rbx), %%edx\n" + "\t" LOCK_PREFIX "cmpxchgl %%ecx, (%%rdi)\n" + "\tjnz 2f\n" + "\tmovl (%%rsi), %%ecx\n" + /* sample >>= 8 */ + "\tsarl $8, %%ecx\n" + "\t" XSUB " %%edx, %%ecx\n" + "\tjmp 21f\n" + "2:" + "\tmovl (%%rsi), %%ecx\n" + /* sample >>= 8 */ + "\tsarl $8, %%ecx\n" + "21:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%rbx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(v); + * *dst = sample; + * } while (v != *sum); + */ + + "3:" + "\tmovl (%%rbx), %%ecx\n" + /* + * if (sample > 0x7fff00) + */ + "\tmovl $0x7fffff, %%eax\n" + "\tcmpl %%eax, %%ecx\n" + "\tjg 4f\n" + /* + * if (sample < -0x800000) + */ + "\tmovl $-0x800000, %%eax\n" + "\tcmpl %%eax, %%ecx\n" + "\tjl 4f\n" + "\tmovl %%ecx, %%eax\n" + "4:" + /* + * sample <<= 8; + */ + "\tsall $8, %%eax\n" + "\tmovl %%eax, (%%rdi)\n" + "\tcmpl %%ecx, (%%rbx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tadd %4, %%rdi\n" + "\tadd %5, %%rsi\n" + "\tadd %6, %%rbx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + + "6:" + "\tmovq %7, %%rbx\n" + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_rbx) + : "rsi", "rdi", "edx", "ecx", "eax" + ); +} + +/* + * 24-bit version + */ +static void MIX_AREAS_24(unsigned int size, + volatile unsigned char *dst, unsigned char *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + unsigned long long old_rbx; + + /* + * RSI - src + * RDI - dst + * RBX - sum + * ECX - old sample + * EAX - sample / temporary + * EDX - temporary + */ + __asm__ __volatile__ ( + "\n" + + "\tmovq %%rbx, %7\n" + /* + * initialization, load ESI, EDI, EBX registers + */ + "\tmovq %1, %%rdi\n" + "\tmovq %2, %%rsi\n" + "\tmovq %3, %%rbx\n" + + /* + * while (size-- > 0) { + */ + "\tcmpl $0, %0\n" + "jz 6f\n" + + "\t.p2align 4,,15\n" + + "1:" + + /* + * sample = *src; + * sum_sample = *sum; + * if (test_and_set_bit(0, dst) == 0) + * sample -= sum_sample; + * *sum += sample; + */ + "\tmovsbl 2(%%rsi), %%eax\n" + "\tmovzwl (%%rsi), %%ecx\n" + "\tmovl (%%rbx), %%edx\n" + "\tsall $16, %%eax\n" + "\torl %%eax, %%ecx\n" + "\t" LOCK_PREFIX "btsw $0, (%%rdi)\n" + "\tjc 2f\n" + "\t" XSUB " %%edx, %%ecx\n" + "2:" + "\t" LOCK_PREFIX XADD " %%ecx, (%%rbx)\n" + + /* + * do { + * sample = old_sample = *sum; + * saturate(sample); + * *dst = sample | 1; + * } while (old_sample != *sum); + */ + + "3:" + "\tmovl (%%rbx), %%ecx\n" + + "\tmovl $0x7fffff, %%eax\n" + "\tmovl $-0x7fffff, %%edx\n" + "\tcmpl %%eax, %%ecx\n" + "\tcmovng %%ecx, %%eax\n" + "\tcmpl %%edx, %%ecx\n" + "\tcmovl %%edx, %%eax\n" + + "\torl $1, %%eax\n" + "\tmovw %%ax, (%%rdi)\n" + "\tshrl $16, %%eax\n" + "\tmovb %%al, 2(%%rdi)\n" + + "\tcmpl %%ecx, (%%rbx)\n" + "\tjnz 3b\n" + + /* + * while (size-- > 0) + */ + "\tadd %4, %%rdi\n" + "\tadd %5, %%rsi\n" + "\tadd %6, %%rbx\n" + "\tdecl %0\n" + "\tjnz 1b\n" + + "6:" + "\tmovq %7, %%rbx\n" + + : /* no output regs */ + : "m" (size), "m" (dst), "m" (src), + "m" (sum), "m" (dst_step), "m" (src_step), + "m" (sum_step), "m" (old_rbx) + : "rsi", "rdi", "edx", "ecx", "eax" + ); +} diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c new file mode 100644 index 0000000..77789a5 --- /dev/null +++ b/src/pcm/pcm_dshare.c @@ -0,0 +1,939 @@ +/** + * \file pcm/pcm_dshare.c + * \ingroup PCM_Plugins + * \brief PCM Direct Sharing of Channels Plugin Interface + * \author Jaroslav Kysela + * \date 2003 + */ +/* + * PCM - Direct Sharing of Channels + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_direct.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_dshare = ""; +#endif + +#ifndef DOC_HIDDEN +/* start is pending - this state happens when rate plugin does a delayed commit */ +#define STATE_RUN_PENDING 1024 +#endif + +static void do_silence(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + const snd_pcm_channel_area_t *dst_areas; + unsigned int chn, dchn, channels; + snd_pcm_format_t format; + + dst_areas = snd_pcm_mmap_areas(dshare->spcm); + channels = dshare->channels; + format = dshare->shmptr->s.format; + for (chn = 0; chn < channels; chn++) { + dchn = dshare->bindings ? dshare->bindings[chn] : chn; + snd_pcm_area_silence(&dst_areas[dchn], 0, dshare->shmptr->s.buffer_size, format); + } +} + +static void share_areas(snd_pcm_direct_t *dshare, + const snd_pcm_channel_area_t *src_areas, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t src_ofs, + snd_pcm_uframes_t dst_ofs, + snd_pcm_uframes_t size) +{ + unsigned int chn, dchn, channels; + snd_pcm_format_t format; + + channels = dshare->channels; + format = dshare->shmptr->s.format; + if (dshare->interleaved) { + unsigned int fbytes = snd_pcm_format_physical_width(format) / 8; + memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes), + ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes), + size * channels * fbytes); + } else { + for (chn = 0; chn < channels; chn++) { + dchn = dshare->bindings ? dshare->bindings[chn] : chn; + snd_pcm_area_copy(&dst_areas[dchn], dst_ofs, &src_areas[chn], src_ofs, size, format); + + } + } +} + +/* + * synchronize shm ring buffer with hardware + */ +static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; + snd_pcm_uframes_t appl_ptr, size; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + + /* calculate the size to transfer */ + size = dshare->appl_ptr - dshare->last_appl_ptr; + if (! size) + return; + slave_hw_ptr = dshare->slave_hw_ptr; + /* don't write on the last active period - this area may be cleared + * by the driver during write operation... + */ + slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size; + slave_hw_ptr += dshare->slave_buffer_size; + if (dshare->slave_hw_ptr > dshare->slave_boundary) + slave_hw_ptr -= dshare->slave_boundary; + if (slave_hw_ptr < dshare->slave_appl_ptr) + slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr); + else + slave_size = slave_hw_ptr - dshare->slave_appl_ptr; + if (slave_size < size) + size = slave_size; + if (! size) + return; + + /* add sample areas here */ + src_areas = snd_pcm_mmap_areas(pcm); + dst_areas = snd_pcm_mmap_areas(dshare->spcm); + appl_ptr = dshare->last_appl_ptr % pcm->buffer_size; + dshare->last_appl_ptr += size; + dshare->last_appl_ptr %= pcm->boundary; + slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size; + dshare->slave_appl_ptr += size; + dshare->slave_appl_ptr %= dshare->slave_boundary; + for (;;) { + snd_pcm_uframes_t transfer = size; + if (appl_ptr + transfer > pcm->buffer_size) + transfer = pcm->buffer_size - appl_ptr; + if (slave_appl_ptr + transfer > dshare->slave_buffer_size) + transfer = dshare->slave_buffer_size - slave_appl_ptr; + share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); + size -= transfer; + if (! size) + break; + slave_appl_ptr += transfer; + slave_appl_ptr %= dshare->slave_buffer_size; + appl_ptr += transfer; + appl_ptr %= pcm->buffer_size; + } +} + +/* + * synchronize hardware pointer (hw_ptr) with ours + */ +static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dshare->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; + default: + break; + } + if (dshare->slowptr) + snd_pcm_hwsync(dshare->spcm); + old_slave_hw_ptr = dshare->slave_hw_ptr; + slave_hw_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; + if (diff == 0) /* fast path */ + return 0; + if (dshare->state != SND_PCM_STATE_RUNNING && + dshare->state != SND_PCM_STATE_DRAINING) + /* not really started yet - don't update hw_ptr */ + return 0; + if (diff < 0) { + slave_hw_ptr += dshare->slave_boundary; + diff = slave_hw_ptr - old_slave_hw_ptr; + } + dshare->hw_ptr += diff; + dshare->hw_ptr %= pcm->boundary; + // printf("sync ptr diff = %li\n", diff); + if (pcm->stop_threshold >= pcm->boundary) /* don't care */ + return 0; + avail = snd_pcm_mmap_playback_avail(pcm); + if (avail > dshare->avail_max) + dshare->avail_max = avail; + if (avail >= pcm->stop_threshold) { + snd_timer_stop(dshare->timer); + gettimestamp(&dshare->trigger_tstamp, pcm->monotonic); + if (dshare->state == SND_PCM_STATE_RUNNING) { + dshare->state = SND_PCM_STATE_XRUN; + return -EPIPE; + } + dshare->state = SND_PCM_STATE_SETUP; + /* clear queue to remove pending poll events */ + snd_pcm_direct_clear_timer_queue(dshare); + } + return 0; +} + +/* + * plugin implementation + */ + +static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + switch (dshare->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + snd_pcm_dshare_sync_ptr(pcm); + break; + default: + break; + } + memset(status, 0, sizeof(*status)); + status->state = snd_pcm_state(dshare->spcm); + status->trigger_tstamp = dshare->trigger_tstamp; + gettimestamp(&status->tstamp, pcm->monotonic); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max; + dshare->avail_max = 0; + return 0; +} + +static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return SND_PCM_STATE_SUSPENDED; + case SND_PCM_STATE_DISCONNECTED: + return SND_PCM_STATE_DISCONNECTED; + default: + break; + } + if (dshare->state == STATE_RUN_PENDING) + return SNDRV_PCM_STATE_RUNNING; + return dshare->state; +} + +static int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + int err; + + switch (dshare->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + err = snd_pcm_dshare_sync_ptr(pcm); + if (err < 0) + return err; + /* fallthru */ + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + case STATE_RUN_PENDING: + *delayp = snd_pcm_mmap_playback_hw_avail(pcm); + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EBADFD; + } +} + +static int snd_pcm_dshare_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + switch(dshare->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + return snd_pcm_dshare_sync_ptr(pcm); + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EBADFD; + } +} + +static int snd_pcm_dshare_prepare(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + snd_pcm_direct_check_interleave(dshare, pcm); + dshare->state = SND_PCM_STATE_PREPARED; + dshare->appl_ptr = dshare->last_appl_ptr = 0; + dshare->hw_ptr = 0; + return snd_pcm_direct_set_timer_params(dshare); +} + +static int snd_pcm_dshare_reset(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + dshare->hw_ptr %= pcm->period_size; + dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr; + dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr; + return 0; +} + +static int snd_pcm_dshare_start_timer(snd_pcm_direct_t *dshare) +{ + int err; + + snd_pcm_hwsync(dshare->spcm); + dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr; + err = snd_timer_start(dshare->timer); + if (err < 0) + return err; + dshare->state = SND_PCM_STATE_RUNNING; + return 0; +} + +static int snd_pcm_dshare_start(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_sframes_t avail; + int err; + + if (dshare->state != SND_PCM_STATE_PREPARED) + return -EBADFD; + avail = snd_pcm_mmap_playback_hw_avail(pcm); + if (avail == 0) + dshare->state = STATE_RUN_PENDING; + else if (avail < 0) + return 0; + else { + if ((err = snd_pcm_dshare_start_timer(dshare)) < 0) + return err; + snd_pcm_dshare_sync_area(pcm); + } + gettimestamp(&dshare->trigger_tstamp, pcm->monotonic); + return 0; +} + +static int snd_pcm_dshare_drop(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + if (dshare->state == SND_PCM_STATE_OPEN) + return -EBADFD; + dshare->state = SND_PCM_STATE_SETUP; + snd_pcm_direct_timer_stop(dshare); + do_silence(pcm); + return 0; +} + +static int snd_pcm_dshare_drain(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_uframes_t stop_threshold; + int err; + + if (dshare->state == SND_PCM_STATE_OPEN) + return -EBADFD; + if (pcm->mode & SND_PCM_NONBLOCK) + return -EAGAIN; + if (dshare->state == SND_PCM_STATE_PREPARED) { + if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) + snd_pcm_dshare_start(pcm); + else { + snd_pcm_dshare_drop(pcm); + return 0; + } + } + + if (dshare->state == SND_PCM_STATE_XRUN) { + snd_pcm_dshare_drop(pcm); + return 0; + } + + stop_threshold = pcm->stop_threshold; + if (pcm->stop_threshold > pcm->buffer_size) + pcm->stop_threshold = pcm->buffer_size; + dshare->state = SND_PCM_STATE_DRAINING; + do { + err = snd_pcm_dshare_sync_ptr(pcm); + if (err < 0) { + snd_pcm_dshare_drop(pcm); + break; + } + if (dshare->state == SND_PCM_STATE_DRAINING) { + snd_pcm_dshare_sync_area(pcm); + snd_pcm_wait_nocheck(pcm, -1); + snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */ + } + } while (dshare->state == SND_PCM_STATE_DRAINING); + pcm->stop_threshold = stop_threshold; + return 0; +} + +static int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +static snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_playback_hw_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_mmap_playback_hw_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_backward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t snd_pcm_dshare_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_playback_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_mmap_playback_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) +{ + return -ENODEV; +} + +static snd_pcm_sframes_t snd_pcm_dshare_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) +{ + return -ENODEV; +} + +static int snd_pcm_dshare_close(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + if (dshare->timer) + snd_timer_close(dshare->timer); + do_silence(pcm); + snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); + dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask; + snd_pcm_close(dshare->spcm); + if (dshare->server) + snd_pcm_direct_server_discard(dshare); + if (dshare->client) + snd_pcm_direct_client_discard(dshare); + if (snd_pcm_direct_shm_discard(dshare)) + snd_pcm_direct_semaphore_discard(dshare); + else + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + free(dshare->bindings); + pcm->private_data = NULL; + free(dshare); + return 0; +} + +static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + int err; + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (! size) + return 0; + snd_pcm_mmap_appl_forward(pcm, size); + if (dshare->state == STATE_RUN_PENDING) { + if ((err = snd_pcm_dshare_start_timer(dshare)) < 0) + return err; + } else if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) + snd_pcm_dshare_sync_ptr(pcm); + if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) { + /* ok, we commit the changes after the validation of area */ + /* it's intended, although the result might be crappy */ + snd_pcm_dshare_sync_area(pcm); + /* clear timer queue to avoid a bogus return from poll */ + if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min) + snd_pcm_direct_clear_timer_queue(dshare); + } + return size; +} + +static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) + snd_pcm_dshare_sync_ptr(pcm); + return snd_pcm_mmap_playback_avail(pcm); +} + +static int snd_pcm_dshare_htimestamp(snd_pcm_t *pcm, + snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_uframes_t avail1; + int ok = 0; + + while (1) { + if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) + snd_pcm_dshare_sync_ptr(pcm); + avail1 = snd_pcm_mmap_playback_avail(pcm); + if (ok && *avail == avail1) + break; + *avail = avail1; + *tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm); + } + return 0; +} + +static void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + snd_output_printf(out, "Direct Share PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + if (dshare->spcm) + snd_pcm_dump(dshare->spcm, out); +} + +static const snd_pcm_ops_t snd_pcm_dshare_ops = { + .close = snd_pcm_dshare_close, + .info = snd_pcm_direct_info, + .hw_refine = snd_pcm_direct_hw_refine, + .hw_params = snd_pcm_direct_hw_params, + .hw_free = snd_pcm_direct_hw_free, + .sw_params = snd_pcm_direct_sw_params, + .channel_info = snd_pcm_direct_channel_info, + .dump = snd_pcm_dshare_dump, + .nonblock = snd_pcm_direct_nonblock, + .async = snd_pcm_direct_async, + .mmap = snd_pcm_direct_mmap, + .munmap = snd_pcm_direct_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { + .status = snd_pcm_dshare_status, + .state = snd_pcm_dshare_state, + .hwsync = snd_pcm_dshare_hwsync, + .delay = snd_pcm_dshare_delay, + .prepare = snd_pcm_dshare_prepare, + .reset = snd_pcm_dshare_reset, + .start = snd_pcm_dshare_start, + .drop = snd_pcm_dshare_drop, + .drain = snd_pcm_dshare_drain, + .pause = snd_pcm_dshare_pause, + .rewindable = snd_pcm_dshare_rewindable, + .rewind = snd_pcm_dshare_rewind, + .forwardable = snd_pcm_dshare_forwardable, + .forward = snd_pcm_dshare_forward, + .resume = snd_pcm_direct_resume, + .link = NULL, + .link_slaves = NULL, + .unlink = NULL, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_dshare_readi, + .readn = snd_pcm_dshare_readn, + .avail_update = snd_pcm_dshare_avail_update, + .mmap_commit = snd_pcm_dshare_mmap_commit, + .htimestamp = snd_pcm_dshare_htimestamp, + .poll_descriptors = NULL, + .poll_descriptors_count = NULL, + .poll_revents = snd_pcm_direct_poll_revents, +}; + +/** + * \brief Creates a new dshare PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param opts Direct PCM configurations + * \param params Parameters for slave + * \param root Configuration root + * \param sconf Slave configuration + * \param stream PCM Direction (stream) + * \param mode PCM Mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, + struct snd_pcm_direct_open_conf *opts, + struct slave_params *params, + snd_config_t *root, snd_config_t *sconf, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm = NULL, *spcm = NULL; + snd_pcm_direct_t *dshare = NULL; + int ret, first_instance; + unsigned int chn; + int fail_sem_loop = 10; + + assert(pcmp); + + if (stream != SND_PCM_STREAM_PLAYBACK) { + SNDERR("The dshare plugin supports only playback stream"); + return -EINVAL; + } + + dshare = calloc(1, sizeof(snd_pcm_direct_t)); + if (!dshare) { + ret = -ENOMEM; + goto _err_nosem; + } + + ret = snd_pcm_direct_parse_bindings(dshare, params, opts->bindings); + if (ret < 0) + goto _err_nosem; + + if (!dshare->bindings) { + SNDERR("dshare: specify bindings!!!"); + ret = -EINVAL; + goto _err_nosem; + } + + dshare->ipc_key = opts->ipc_key; + dshare->ipc_perm = opts->ipc_perm; + dshare->ipc_gid = opts->ipc_gid; + dshare->semid = -1; + dshare->shmid = -1; + + ret = snd_pcm_new(&pcm, dshare->type = SND_PCM_TYPE_DSHARE, name, stream, mode); + if (ret < 0) + goto _err_nosem; + + while (1) { + ret = snd_pcm_direct_semaphore_create_or_connect(dshare); + if (ret < 0) { + SNDERR("unable to create IPC semaphore"); + goto _err_nosem; + } + + ret = snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); + if (ret < 0) { + snd_pcm_direct_semaphore_discard(dshare); + if (--fail_sem_loop <= 0) + goto _err_nosem; + continue; + } + break; + } + + first_instance = ret = snd_pcm_direct_shm_create_or_connect(dshare); + if (ret < 0) { + SNDERR("unable to create IPC shm instance"); + goto _err; + } + + pcm->ops = &snd_pcm_dshare_ops; + pcm->fast_ops = &snd_pcm_dshare_fast_ops; + pcm->private_data = dshare; + dshare->state = SND_PCM_STATE_OPEN; + dshare->slowptr = opts->slowptr; + dshare->max_periods = opts->max_periods; + dshare->sync_ptr = snd_pcm_dshare_sync_ptr; + + if (first_instance) { + /* recursion is already checked in + snd_pcm_direct_get_slave_ipc_offset() */ + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK, NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dshare plugin can be only connected to hw plugin"); + goto _err; + } + + ret = snd_pcm_direct_initialize_slave(dshare, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + + dshare->spcm = spcm; + + if (dshare->shmptr->use_server) { + ret = snd_pcm_direct_server_create(dshare); + if (ret < 0) { + SNDERR("unable to create server"); + goto _err; + } + } + + dshare->shmptr->type = spcm->type; + } else { + if (dshare->shmptr->use_server) { + /* up semaphore to avoid deadlock */ + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_client_connect(dshare); + if (ret < 0) { + SNDERR("unable to connect client"); + goto _err_nosem; + } + + snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client"); + if (ret < 0) + goto _err; + + } else { + + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK | + SND_PCM_APPEND, + NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dshare plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + } + + dshare->spcm = spcm; + } + + for (chn = 0; chn < dshare->channels; chn++) + dshare->u.dshare.chn_mask |= (1ULL<bindings[chn]); + if (dshare->shmptr->u.dshare.chn_mask & dshare->u.dshare.chn_mask) { + SNDERR("destination channel specified in bindings is already used"); + dshare->u.dshare.chn_mask = 0; + ret = -EINVAL; + goto _err; + } + dshare->shmptr->u.dshare.chn_mask |= dshare->u.dshare.chn_mask; + + ret = snd_pcm_direct_initialize_poll_fd(dshare); + if (ret < 0) { + SNDERR("unable to initialize poll_fd"); + goto _err; + } + + pcm->poll_fd = dshare->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ + + pcm->mmap_rw = 1; + snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0); + + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + + *pcmp = pcm; + return 0; + + _err: + if (dshare->shmptr) + dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask; + if (dshare->timer) + snd_timer_close(dshare->timer); + if (dshare->server) + snd_pcm_direct_server_discard(dshare); + if (dshare->client) + snd_pcm_direct_client_discard(dshare); + if (spcm) + snd_pcm_close(spcm); + if (dshare->shmid >= 0) + snd_pcm_direct_shm_discard(dshare); + if (snd_pcm_direct_semaphore_discard(dshare) < 0) + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + _err_nosem: + if (dshare) { + free(dshare->bindings); + free(dshare); + } + if (pcm) + snd_pcm_free(pcm); + return ret; +} + +/*! \page pcm_plugins + +\section pcm_plugins_dshare Plugin: dshare + +This plugin provides sharing channels. +Unlike \ref pcm_plugins_share "share plugin", this plugin doesn't need +the explicit server program but accesses the shared buffer concurrently +from each client as well as \ref pcm_plugins_dmix "dmix" and +\ref pcm_plugins_dsnoop "dsnoop" plugins do. +The parameters below are almost identical with these plugins. + +\code +pcm.name { + type dshare # Direct sharing + ipc_key INT # unique IPC key + ipc_key_add_uid BOOL # add current uid to unique IPC key + ipc_perm INT # IPC permissions (octal, default 0600) + slave STR + # or + slave { # Slave definition + pcm STR # slave PCM name + # or + pcm { } # slave PCM definition + format STR # format definition + rate INT # rate definition + channels INT + period_time INT # in usec + # or + period_size INT # in bytes + buffer_time INT # in usec + # or + buffer_size INT # in bytes + periods INT # when buffer_size or buffer_time is not specified + } + bindings { # note: this is client independent!!! + N INT # maps slave channel to client channel N + } + slowptr BOOL # slow but more precise pointer updates +} +\endcode + +\subsection pcm_plugins_dshare_funcref Function reference + +
    +
  • snd_pcm_dshare_open() +
  • _snd_pcm_dshare_open() +
+ +*/ + +/** + * \brief Creates a new dshare PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with dshare PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_t *sconf; + struct slave_params params; + struct snd_pcm_direct_open_conf dopen; + int bsize, psize; + int err; + + err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); + if (err < 0) + return err; + + /* the default settings, it might be invalid for some hardware */ + params.format = SND_PCM_FORMAT_S16; + params.rate = 48000; + params.channels = 2; + params.period_time = -1; + params.buffer_time = -1; + bsize = psize = -1; + params.periods = 3; + err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, + SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, + SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, + SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, + SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, + SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, + SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, + SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, + SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); + if (err < 0) + return err; + + /* set a reasonable default */ + if (psize == -1 && params.period_time == -1) + params.period_time = 125000; /* 0.125 seconds */ + + if (params.format == -2) + params.format = SND_PCM_FORMAT_UNKNOWN; + + params.period_size = psize; + params.buffer_size = bsize; + + err = snd_pcm_dshare_open(pcmp, name, &dopen, ¶ms, + root, sconf, stream, mode); + snd_config_delete(sconf); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_dshare_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c new file mode 100644 index 0000000..988f1f4 --- /dev/null +++ b/src/pcm/pcm_dsnoop.c @@ -0,0 +1,835 @@ +/** + * \file pcm/pcm_dsnoop.c + * \ingroup PCM_Plugins + * \brief PCM Capture Stream Snooping (dsnoop) Plugin Interface + * \author Jaroslav Kysela + * \date 2003 + */ +/* + * PCM - Capture Stream Snooping + * Copyright (c) 2003 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_direct.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_dsnoop = ""; +#endif + +/* + * + */ + +static int snoop_timestamp(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_uframes_t ptr1 = -2LL /* invalid value */, ptr2; + + /* loop is required to sync hw.ptr with timestamp */ + while (1) { + ptr2 = *dsnoop->spcm->hw.ptr; + if (ptr1 == ptr2) + break; + ptr1 = ptr2; + dsnoop->update_tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm); + } + dsnoop->slave_hw_ptr = ptr1; + return 0; +} + +static void snoop_areas(snd_pcm_direct_t *dsnoop, + const snd_pcm_channel_area_t *src_areas, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t src_ofs, + snd_pcm_uframes_t dst_ofs, + snd_pcm_uframes_t size) +{ + unsigned int chn, schn, channels; + snd_pcm_format_t format; + + channels = dsnoop->channels; + format = dsnoop->shmptr->s.format; + if (dsnoop->interleaved) { + unsigned int fbytes = snd_pcm_format_physical_width(format) / 8; + memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes), + ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes), + size * channels * fbytes); + } else { + for (chn = 0; chn < channels; chn++) { + schn = dsnoop->bindings ? dsnoop->bindings[chn] : chn; + snd_pcm_area_copy(&dst_areas[chn], dst_ofs, &src_areas[schn], src_ofs, size, format); + } + } +} + +/* + * synchronize shm ring buffer with hardware + */ +static void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr, snd_pcm_uframes_t size) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_uframes_t hw_ptr = dsnoop->hw_ptr; + snd_pcm_uframes_t transfer; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + + /* add sample areas here */ + dst_areas = snd_pcm_mmap_areas(pcm); + src_areas = snd_pcm_mmap_areas(dsnoop->spcm); + hw_ptr %= pcm->buffer_size; + slave_hw_ptr %= dsnoop->slave_buffer_size; + while (size > 0) { + transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size; + transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ? + dsnoop->slave_buffer_size - slave_hw_ptr : transfer; + size -= transfer; + snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer); + slave_hw_ptr += transfer; + slave_hw_ptr %= dsnoop->slave_buffer_size; + hw_ptr += transfer; + hw_ptr %= pcm->buffer_size; + } +} + +/* + * synchronize hardware pointer (hw_ptr) with ours + */ +static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + + switch (snd_pcm_state(dsnoop->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; + default: + break; + } + if (dsnoop->slowptr) + snd_pcm_hwsync(dsnoop->spcm); + old_slave_hw_ptr = dsnoop->slave_hw_ptr; + snoop_timestamp(pcm); + slave_hw_ptr = dsnoop->slave_hw_ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; + if (diff == 0) /* fast path */ + return 0; + if (diff < 0) { + slave_hw_ptr += dsnoop->slave_boundary; + diff = slave_hw_ptr - old_slave_hw_ptr; + } + snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff); + dsnoop->hw_ptr += diff; + dsnoop->hw_ptr %= pcm->boundary; + // printf("sync ptr diff = %li\n", diff); + if (pcm->stop_threshold >= pcm->boundary) /* don't care */ + return 0; + if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) { + gettimestamp(&dsnoop->trigger_tstamp, pcm->monotonic); + dsnoop->state = SND_PCM_STATE_XRUN; + dsnoop->avail_max = avail; + return -EPIPE; + } + if (avail > dsnoop->avail_max) + dsnoop->avail_max = avail; + return 0; +} + +/* + * plugin implementation + */ + +static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_state_t state; + + switch(dsnoop->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + snd_pcm_dsnoop_sync_ptr(pcm); + break; + default: + break; + } + memset(status, 0, sizeof(*status)); + state = snd_pcm_state(dsnoop->spcm); + status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state; + status->trigger_tstamp = dsnoop->trigger_tstamp; + status->tstamp = dsnoop->update_tstamp; + status->avail = snd_pcm_mmap_capture_avail(pcm); + status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max; + dsnoop->avail_max = 0; + return 0; +} + +static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + switch (snd_pcm_state(dsnoop->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return SND_PCM_STATE_SUSPENDED; + case SND_PCM_STATE_DISCONNECTED: + dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; + default: + break; + } + return dsnoop->state; +} + +static int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + int err; + + switch(dsnoop->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + err = snd_pcm_dsnoop_sync_ptr(pcm); + if (err < 0) + return err; + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + *delayp = snd_pcm_mmap_capture_hw_avail(pcm); + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EBADFD; + } +} + +static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + + switch(dsnoop->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + return snd_pcm_dsnoop_sync_ptr(pcm); + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + case SNDRV_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EBADFD; + } +} + +static int snd_pcm_dsnoop_prepare(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + + snd_pcm_direct_check_interleave(dsnoop, pcm); + dsnoop->state = SND_PCM_STATE_PREPARED; + dsnoop->appl_ptr = 0; + dsnoop->hw_ptr = 0; + return snd_pcm_direct_set_timer_params(dsnoop); +} + +static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + dsnoop->hw_ptr %= pcm->period_size; + dsnoop->appl_ptr = dsnoop->hw_ptr; + dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr; + return 0; +} + +static int snd_pcm_dsnoop_start(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + int err; + + if (dsnoop->state != SND_PCM_STATE_PREPARED) + return -EBADFD; + snd_pcm_hwsync(dsnoop->spcm); + snoop_timestamp(pcm); + dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr; + err = snd_timer_start(dsnoop->timer); + if (err < 0) + return err; + dsnoop->state = SND_PCM_STATE_RUNNING; + dsnoop->trigger_tstamp = dsnoop->update_tstamp; + return 0; +} + +static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + if (dsnoop->state == SND_PCM_STATE_OPEN) + return -EBADFD; + dsnoop->state = SND_PCM_STATE_SETUP; + snd_timer_stop(dsnoop->timer); + return 0; +} + +static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_uframes_t stop_threshold; + int err; + + if (dsnoop->state == SND_PCM_STATE_OPEN) + return -EBADFD; + stop_threshold = pcm->stop_threshold; + if (pcm->stop_threshold > pcm->buffer_size) + pcm->stop_threshold = pcm->buffer_size; + while (dsnoop->state == SND_PCM_STATE_RUNNING) { + err = snd_pcm_dsnoop_sync_ptr(pcm); + if (err < 0) + break; + if (pcm->mode & SND_PCM_NONBLOCK) + return -EAGAIN; + snd_pcm_wait(pcm, -1); + } + pcm->stop_threshold = stop_threshold; + return snd_pcm_dsnoop_drop(pcm); +} + +static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_capture_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_mmap_capture_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_backward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_capture_hw_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_mmap_capture_hw_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_writei(snd_pcm_t *pcm ATTRIBUTE_UNUSED, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) +{ + return -ENODEV; +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_writen(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) +{ + return -ENODEV; +} + +static int snd_pcm_dsnoop_close(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + + if (dsnoop->timer) + snd_timer_close(dsnoop->timer); + snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); + snd_pcm_close(dsnoop->spcm); + if (dsnoop->server) + snd_pcm_direct_server_discard(dsnoop); + if (dsnoop->client) + snd_pcm_direct_client_discard(dsnoop); + if (snd_pcm_direct_shm_discard(dsnoop)) + snd_pcm_direct_semaphore_discard(dsnoop); + else + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); + free(dsnoop->bindings); + pcm->private_data = NULL; + free(dsnoop); + return 0; +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + int err; + + switch (snd_pcm_state(dsnoop->spcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (dsnoop->state == SND_PCM_STATE_RUNNING) { + err = snd_pcm_dsnoop_sync_ptr(pcm); + if (err < 0) + return err; + } + snd_pcm_mmap_appl_forward(pcm, size); + /* clear timer queue to avoid a bogus return from poll */ + if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min) + snd_pcm_direct_clear_timer_queue(dsnoop); + return size; +} + +static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + int err; + + if (dsnoop->state == SND_PCM_STATE_RUNNING) { + err = snd_pcm_dsnoop_sync_ptr(pcm); + if (err < 0) + return err; + } + return snd_pcm_mmap_capture_avail(pcm); +} + +static int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm, + snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_uframes_t avail1; + int ok = 0; + + while (1) { + if (dsnoop->state == SND_PCM_STATE_RUNNING || + dsnoop->state == SND_PCM_STATE_DRAINING) + snd_pcm_dsnoop_sync_ptr(pcm); + avail1 = snd_pcm_mmap_capture_avail(pcm); + if (ok && *avail == avail1) + break; + *avail = avail1; + *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm); + } + return 0; +} + +static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + + snd_output_printf(out, "Direct Snoop PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + if (dsnoop->spcm) + snd_pcm_dump(dsnoop->spcm, out); +} + +static const snd_pcm_ops_t snd_pcm_dsnoop_ops = { + .close = snd_pcm_dsnoop_close, + .info = snd_pcm_direct_info, + .hw_refine = snd_pcm_direct_hw_refine, + .hw_params = snd_pcm_direct_hw_params, + .hw_free = snd_pcm_direct_hw_free, + .sw_params = snd_pcm_direct_sw_params, + .channel_info = snd_pcm_direct_channel_info, + .dump = snd_pcm_dsnoop_dump, + .nonblock = snd_pcm_direct_nonblock, + .async = snd_pcm_direct_async, + .mmap = snd_pcm_direct_mmap, + .munmap = snd_pcm_direct_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { + .status = snd_pcm_dsnoop_status, + .state = snd_pcm_dsnoop_state, + .hwsync = snd_pcm_dsnoop_hwsync, + .delay = snd_pcm_dsnoop_delay, + .prepare = snd_pcm_dsnoop_prepare, + .reset = snd_pcm_dsnoop_reset, + .start = snd_pcm_dsnoop_start, + .drop = snd_pcm_dsnoop_drop, + .drain = snd_pcm_dsnoop_drain, + .pause = snd_pcm_dsnoop_pause, + .rewindable = snd_pcm_dsnoop_rewindable, + .rewind = snd_pcm_dsnoop_rewind, + .forwardable = snd_pcm_dsnoop_forwardable, + .forward = snd_pcm_dsnoop_forward, + .resume = snd_pcm_direct_resume, + .link = NULL, + .link_slaves = NULL, + .unlink = NULL, + .writei = snd_pcm_dsnoop_writei, + .writen = snd_pcm_dsnoop_writen, + .readi = snd_pcm_mmap_readi, + .readn = snd_pcm_mmap_readn, + .avail_update = snd_pcm_dsnoop_avail_update, + .mmap_commit = snd_pcm_dsnoop_mmap_commit, + .htimestamp = snd_pcm_dsnoop_htimestamp, + .poll_descriptors = NULL, + .poll_descriptors_count = NULL, + .poll_revents = snd_pcm_direct_poll_revents, +}; + +/** + * \brief Creates a new dsnoop PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param opts Direct PCM configurations + * \param params Parameters for slave + * \param root Configuration root + * \param sconf Slave configuration + * \param stream PCM Direction (stream) + * \param mode PCM Mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, + struct snd_pcm_direct_open_conf *opts, + struct slave_params *params, + snd_config_t *root, snd_config_t *sconf, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm = NULL, *spcm = NULL; + snd_pcm_direct_t *dsnoop = NULL; + int ret, first_instance, fail_sem_loop = 10; + + assert(pcmp); + + if (stream != SND_PCM_STREAM_CAPTURE) { + SNDERR("The dsnoop plugin supports only capture stream"); + return -EINVAL; + } + + dsnoop = calloc(1, sizeof(snd_pcm_direct_t)); + if (!dsnoop) { + ret = -ENOMEM; + goto _err_nosem; + } + + ret = snd_pcm_direct_parse_bindings(dsnoop, params, opts->bindings); + if (ret < 0) + goto _err_nosem; + + dsnoop->ipc_key = opts->ipc_key; + dsnoop->ipc_perm = opts->ipc_perm; + dsnoop->ipc_gid = opts->ipc_gid; + dsnoop->semid = -1; + dsnoop->shmid = -1; + + ret = snd_pcm_new(&pcm, dsnoop->type = SND_PCM_TYPE_DSNOOP, name, stream, mode); + if (ret < 0) + goto _err_nosem; + + while (1) { + ret = snd_pcm_direct_semaphore_create_or_connect(dsnoop); + if (ret < 0) { + SNDERR("unable to create IPC semaphore"); + goto _err_nosem; + } + + ret = snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); + if (ret < 0) { + snd_pcm_direct_semaphore_discard(dsnoop); + if (--fail_sem_loop <= 0) + goto _err_nosem; + continue; + } + break; + } + + first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop); + if (ret < 0) { + SNDERR("unable to create IPC shm instance"); + goto _err; + } + + pcm->ops = &snd_pcm_dsnoop_ops; + pcm->fast_ops = &snd_pcm_dsnoop_fast_ops; + pcm->private_data = dsnoop; + dsnoop->state = SND_PCM_STATE_OPEN; + dsnoop->slowptr = opts->slowptr; + dsnoop->max_periods = opts->max_periods; + dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; + + if (first_instance) { + /* recursion is already checked in + snd_pcm_direct_get_slave_ipc_offset() */ + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK, NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dsnoop plugin can be only connected to hw plugin"); + goto _err; + } + + ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + + dsnoop->spcm = spcm; + + if (dsnoop->shmptr->use_server) { + ret = snd_pcm_direct_server_create(dsnoop); + if (ret < 0) { + SNDERR("unable to create server"); + goto _err; + } + } + + dsnoop->shmptr->type = spcm->type; + } else { + if (dsnoop->shmptr->use_server) { + /* up semaphore to avoid deadlock */ + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_client_connect(dsnoop); + if (ret < 0) { + SNDERR("unable to connect client"); + goto _err_nosem; + } + + snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); + + ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client"); + if (ret < 0) + goto _err; + } else { + + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK | + SND_PCM_APPEND, + NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dsnoop plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + } + + dsnoop->spcm = spcm; + } + + ret = snd_pcm_direct_initialize_poll_fd(dsnoop); + if (ret < 0) { + SNDERR("unable to initialize poll_fd"); + goto _err; + } + + pcm->poll_fd = dsnoop->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ + + pcm->mmap_rw = 1; + snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0); + + if (dsnoop->channels == UINT_MAX) + dsnoop->channels = dsnoop->shmptr->s.channels; + + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); + + *pcmp = pcm; + return 0; + + _err: + if (dsnoop->timer) + snd_timer_close(dsnoop->timer); + if (dsnoop->server) + snd_pcm_direct_server_discard(dsnoop); + if (dsnoop->client) + snd_pcm_direct_client_discard(dsnoop); + if (spcm) + snd_pcm_close(spcm); + if (dsnoop->shmid >= 0) + snd_pcm_direct_shm_discard(dsnoop); + if (snd_pcm_direct_semaphore_discard(dsnoop) < 0) + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); + _err_nosem: + if (dsnoop) { + free(dsnoop->bindings); + free(dsnoop); + } + if (pcm) + snd_pcm_free(pcm); + return ret; +} + +/*! \page pcm_plugins + +\section pcm_plugins_dsnoop Plugin: dsnoop + +This plugin splits one capture stream to more. +It works the reverse way of \ref pcm_plugins_dmix "dmix plugin", +reading the shared capture buffer from many clients concurrently. +The meaning of parameters below are almost identical with +dmix plugin. + +\code +pcm.name { + type dsnoop # Direct snoop + ipc_key INT # unique IPC key + ipc_key_add_uid BOOL # add current uid to unique IPC key + ipc_perm INT # IPC permissions (octal, default 0600) + slave STR + # or + slave { # Slave definition + pcm STR # slave PCM name + # or + pcm { } # slave PCM definition + format STR # format definition + rate INT # rate definition + channels INT + period_time INT # in usec + # or + period_size INT # in bytes + buffer_time INT # in usec + # or + buffer_size INT # in bytes + periods INT # when buffer_size or buffer_time is not specified + } + bindings { # note: this is client independent!!! + N INT # maps slave channel to client channel N + } + slowptr BOOL # slow but more precise pointer updates +} +\endcode + +\subsection pcm_plugins_dsnoop_funcref Function reference + +
    +
  • snd_pcm_dsnoop_open() +
  • _snd_pcm_dsnoop_open() +
+ +*/ + +/** + * \brief Creates a new dsnoop PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with dsnoop PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_t *sconf; + struct slave_params params; + struct snd_pcm_direct_open_conf dopen; + int bsize, psize; + int err; + + err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); + if (err < 0) + return err; + + /* the default settings, it might be invalid for some hardware */ + params.format = SND_PCM_FORMAT_S16; + params.rate = 48000; + params.channels = 2; + params.period_time = -1; + params.buffer_time = -1; + bsize = psize = -1; + params.periods = 3; + err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, + SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, + SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, + SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, + SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, + SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, + SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, + SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, + SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); + if (err < 0) + return err; + + /* set a reasonable default */ + if (psize == -1 && params.period_time == -1) + params.period_time = 125000; /* 0.125 seconds */ + + if (params.format == -2) + params.format = SND_PCM_FORMAT_UNKNOWN; + + params.period_size = psize; + params.buffer_size = bsize; + + err = snd_pcm_dsnoop_open(pcmp, name, &dopen, ¶ms, + root, sconf, stream, mode); + snd_config_delete(sconf); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_empty.c b/src/pcm/pcm_empty.c new file mode 100644 index 0000000..070850c --- /dev/null +++ b/src/pcm/pcm_empty.c @@ -0,0 +1,110 @@ +/** + * \file pcm/pcm_empty.c + * \ingroup PCM_Plugins + * \brief PCM Null Plugin Interface + * \author Jaroslav Kysela + * \date 2006 + */ +/* + * PCM - Null plugin + * Copyright (c) 2006 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_empty = ""; +#endif + +/*! \page pcm_plugins + +\section pcm_plugins_null Plugin: Null + +This plugin discards contents of a PCM stream or creates a stream with zero +samples. + +Note: This implementation uses devices /dev/null (playback, must be writable) +and /dev/full (capture, must be readable). + +\code +pcm.name { + type null # Null PCM +} +\endcode + +\subsection pcm_plugins_null_funcref Function reference + +
    +
  • _snd_pcm_empty_open() +
+ +*/ + +/** + * \brief Creates a new Empty PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with empty PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_empty_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_t *slave = NULL, *sconf; + snd_config_iterator_t i, next; + int err; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_named_slave(pcmp, name, root, sconf, stream, + mode, conf); + snd_config_delete(sconf); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_empty_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_ext_parm.h b/src/pcm/pcm_ext_parm.h new file mode 100644 index 0000000..d25f2ab --- /dev/null +++ b/src/pcm/pcm_ext_parm.h @@ -0,0 +1,41 @@ +/* hw_params */ +struct snd_ext_parm { + unsigned int min, max; + unsigned int num_list; + unsigned int *list; + unsigned int active: 1; + unsigned int integer: 1; +}; + +static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; +} + +static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; +} + +/* make local functions really local */ +#define snd_ext_parm_set_minmax \ + snd1_ext_parm_set_minmax +#define snd_ext_parm_set_list \ + snd1_ext_parm_set_list +#define snd_ext_parm_clear \ + snd1_ext_parm_clear +#define snd_interval_list \ + snd1_interval_list +#define snd_ext_parm_interval_refine \ + snd1_ext_parm_interval_refine +#define snd_ext_parm_mask_refine \ + snd1_ext_parm_mask_refine + +int snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max); +int snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, const unsigned int *list); +void snd_ext_parm_clear(struct snd_ext_parm *parm); +int snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list); +int snd_ext_parm_interval_refine(snd_interval_t *ival, struct snd_ext_parm *parm, int type); +int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int type); diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c new file mode 100644 index 0000000..a34706f --- /dev/null +++ b/src/pcm/pcm_extplug.c @@ -0,0 +1,813 @@ +/** + * \file pcm/pcm_extplug.c + * \ingroup Plugin_SDK + * \brief External Filter Plugin SDK + * \author Takashi Iwai + * \date 2005 + */ +/* + * PCM - External Filter Plugin SDK + * Copyright (c) 2005 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" +#include "pcm_plugin.h" +#include "pcm_extplug.h" +#include "pcm_ext_parm.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_extplug = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef struct snd_pcm_extplug_priv { + snd_pcm_plugin_t plug; + snd_pcm_extplug_t *data; + struct snd_ext_parm params[SND_PCM_EXTPLUG_HW_PARAMS]; + struct snd_ext_parm sparams[SND_PCM_EXTPLUG_HW_PARAMS]; +} extplug_priv_t; + +static const int hw_params_type[SND_PCM_EXTPLUG_HW_PARAMS] = { + [SND_PCM_EXTPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, + [SND_PCM_EXTPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS +}; + +#define is_mask_type(i) (hw_params_type[i] < SND_PCM_HW_PARAM_FIRST_INTERVAL) + +static const unsigned int excl_parbits[SND_PCM_EXTPLUG_HW_PARAMS] = { + [SND_PCM_EXTPLUG_HW_FORMAT] = (SND_PCM_HW_PARBIT_FORMAT| + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS), + [SND_PCM_EXTPLUG_HW_CHANNELS] = (SND_PCM_HW_PARBIT_CHANNELS| + SND_PCM_HW_PARBIT_FRAME_BITS), +}; + +/* + * set min/max values for the given parameter + */ +int snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max) +{ + parm->num_list = 0; + free(parm->list); + parm->list = NULL; + parm->min = min; + parm->max = max; + parm->active = 1; + return 0; +} + +/* + * set the list of available values for the given parameter + */ +static int val_compar(const void *ap, const void *bp) +{ + return *(const unsigned int *)ap - *(const unsigned int *)bp; +} + +int snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, const unsigned int *list) +{ + unsigned int *new_list; + + new_list = malloc(sizeof(*new_list) * num_list); + if (new_list == NULL) + return -ENOMEM; + memcpy(new_list, list, sizeof(*new_list) * num_list); + qsort(new_list, num_list, sizeof(*new_list), val_compar); + + free(parm->list); + parm->num_list = num_list; + parm->list = new_list; + parm->active = 1; + return 0; +} + +void snd_ext_parm_clear(struct snd_ext_parm *parm) +{ + free(parm->list); + memset(parm, 0, sizeof(*parm)); +} + +/* + * limit the interval to the given list + */ +int snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list) +{ + int imin, imax; + int changed = 0; + + if (snd_interval_empty(ival)) + return -ENOENT; + for (imin = 0; imin < num_list; imin++) { + if (ival->min == list[imin] && ! ival->openmin) + break; + if (ival->min <= list[imin]) { + ival->min = list[imin]; + ival->openmin = 0; + changed = 1; + break; + } + } + if (imin >= num_list) + return -EINVAL; + for (imax = num_list - 1; imax >= imin; imax--) { + if (ival->max == list[imax] && ! ival->openmax) + break; + if (ival->max >= list[imax]) { + ival->max = list[imax]; + ival->openmax = 0; + changed = 1; + break; + } + } + if (imax < imin) + return -EINVAL; + return changed; +} + +/* + * refine the interval parameter + */ +int snd_ext_parm_interval_refine(snd_interval_t *ival, struct snd_ext_parm *parm, int type) +{ + parm += type; + if (! parm->active) + return 0; + ival->integer |= parm->integer; + if (parm->num_list) { + return snd_interval_list(ival, parm->num_list, parm->list); + } else if (parm->min || parm->max) { + snd_interval_t t; + memset(&t, 0, sizeof(t)); + snd_interval_set_minmax(&t, parm->min, parm->max); + t.integer = ival->integer; + return snd_interval_refine(ival, &t); + } + return 0; +} + +/* + * refine the mask parameter + */ +int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int type) +{ + snd_mask_t bits; + unsigned int i; + + parm += type; + memset(&bits, 0, sizeof(bits)); + for (i = 0; i < parm->num_list; i++) + bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32); + return snd_mask_refine(mask, &bits); +} + + +/* + * hw_refine callback + */ +static int extplug_hw_refine(snd_pcm_hw_params_t *hw_params, + struct snd_ext_parm *parm) +{ + int i, err, change = 0; + for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { + int type = hw_params_type[i]; + if (is_mask_type(i)) + err = snd_ext_parm_mask_refine(hw_param_mask(hw_params, type), + parm, i); + else + err = snd_ext_parm_interval_refine(hw_param_interval(hw_params, type), + parm, i); + if (err < 0) + return err; + change |= err; + } + return change; +} + +static int snd_pcm_extplug_hw_refine_cprepare(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + extplug_priv_t *ext = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = extplug_hw_refine(params, ext->params); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_extplug_hw_refine_sprepare(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams) +{ + extplug_priv_t *ext = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + extplug_hw_refine(sparams, ext->sparams); + return 0; +} + +static unsigned int get_links(struct snd_ext_parm *params) +{ + int i; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS | + SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_FRAME_BITS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + + for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { + if (params[i].active) + links &= ~excl_parbits[i]; + } + return links; +} + +static int snd_pcm_extplug_hw_refine_schange(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + extplug_priv_t *ext = pcm->private_data; + unsigned int links = get_links(ext->sparams); + + return _snd_pcm_hw_params_refine(sparams, links, params); +} + +static int snd_pcm_extplug_hw_refine_cchange(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + extplug_priv_t *ext = pcm->private_data; + unsigned int links = get_links(ext->params); + + return _snd_pcm_hw_params_refine(params, links, sparams); +} + +static int snd_pcm_extplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int err = snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_extplug_hw_refine_cprepare, + snd_pcm_extplug_hw_refine_cchange, + snd_pcm_extplug_hw_refine_sprepare, + snd_pcm_extplug_hw_refine_schange, + snd_pcm_generic_hw_refine); + return err; +} + +/* + * hw_params callback + */ +static int snd_pcm_extplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + + extplug_priv_t *ext = pcm->private_data; + snd_pcm_t *slave = ext->plug.gen.slave; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_extplug_hw_refine_cchange, + snd_pcm_extplug_hw_refine_sprepare, + snd_pcm_extplug_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + ext->data->slave_format = slave->format; + ext->data->slave_subformat = slave->subformat; + ext->data->slave_channels = slave->channels; + ext->data->rate = slave->rate; + INTERNAL(snd_pcm_hw_params_get_format)(params, &ext->data->format); + INTERNAL(snd_pcm_hw_params_get_subformat)(params, &ext->data->subformat); + INTERNAL(snd_pcm_hw_params_get_channels)(params, &ext->data->channels); + + if (ext->data->callback->hw_params) { + err = ext->data->callback->hw_params(ext->data, params); + if (err < 0) + return err; + } + return 0; +} + +/* + * hw_free callback + */ +static int snd_pcm_extplug_hw_free(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + + snd_pcm_hw_free(ext->plug.gen.slave); + if (ext->data->callback->hw_free) + return ext->data->callback->hw_free(ext->data); + return 0; +} + +/* + * write_areas skeleton - call transfer callback + */ +static snd_pcm_uframes_t +snd_pcm_extplug_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + extplug_priv_t *ext = pcm->private_data; + + if (size > *slave_sizep) + size = *slave_sizep; + size = ext->data->callback->transfer(ext->data, slave_areas, slave_offset, + areas, offset, size); + *slave_sizep = size; + return size; +} + +/* + * read_areas skeleton - call transfer callback + */ +static snd_pcm_uframes_t +snd_pcm_extplug_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + extplug_priv_t *ext = pcm->private_data; + + if (size > *slave_sizep) + size = *slave_sizep; + size = ext->data->callback->transfer(ext->data, areas, offset, + slave_areas, slave_offset, size); + *slave_sizep = size; + return size; +} + +/* + * call init callback + */ +static int snd_pcm_extplug_init(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + return ext->data->callback->init(ext->data); +} + +/* + * dump setup + */ +static void snd_pcm_extplug_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + extplug_priv_t *ext = pcm->private_data; + + if (ext->data->callback->dump) + ext->data->callback->dump(ext->data, out); + else { + if (ext->data->name) + snd_output_printf(out, "%s\n", ext->data->name); + else + snd_output_printf(out, "External PCM Plugin\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(ext->plug.gen.slave, out); +} + +static void clear_ext_params(extplug_priv_t *ext) +{ + int i; + for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { + snd_ext_parm_clear(&ext->params[i]); + snd_ext_parm_clear(&ext->sparams[i]); + } +} + +static int snd_pcm_extplug_close(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + + snd_pcm_close(ext->plug.gen.slave); + clear_ext_params(ext); + if (ext->data->callback->close) + ext->data->callback->close(ext->data); + free(ext); + return 0; +} + +static const snd_pcm_ops_t snd_pcm_extplug_ops = { + .close = snd_pcm_extplug_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_extplug_hw_refine, + .hw_params = snd_pcm_extplug_hw_params, + .hw_free = snd_pcm_extplug_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_extplug_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +#endif /* !DOC_HIDDEN */ + +/* + * Exported functions + */ + +/*! \page pcm_external_plugins PCM External Plugin SDK + +\section pcm_externals External Plugins + +The external plugins are implemented in a shared object file located +at /usr/lib/alsa-lib (the exact location depends on the build option +and asoundrc configuration). It has to be the file like +libasound_module_pcm_MYPLUGIN.so, where MYPLUGIN corresponds to your +own plugin name. + +The entry point of the plugin is defined via +#SND_PCM_PLUGIN_DEFINE_FUNC() macro. This macro defines the function +with a proper name to be referred from alsa-lib. The function takes +the following 6 arguments: +\code +int (snd_pcm_t **pcmp, const char *name, snd_config_t *root, + snd_config_t *conf, snd_pcm_stream_t stream, int mode) +\endcode +The first argument, pcmp, is the pointer to store the resultant PCM +handle. The arguments name, root, stream and mode are the parameters +to be passed to the plugin constructor. The conf is the configuration +tree for the plugin. The arguments above are defined in the macro +itself, so don't use variables with the same names to shadow +parameters. + +After parsing the configuration parameters in the given conf tree, +usually you will call the external plugin API function, +#snd_pcm_extplug_create() or #snd_pcm_ioplug_create(), depending +on the plugin type. The PCM handle must be filled *pcmp in return. +Then this function must return either a value 0 when succeeded, or a +negative value as the error code. + +Finally, add #SND_PCM_PLUGIN_SYMBOL() with the name of your +plugin as the argument at the end. This defines the proper versioned +symbol as the reference. + +The typical code would look like below: +\code +struct myplug_info { + snd_pcm_extplug_t ext; + int my_own_data; + ... +}; + +SND_PCM_PLUGIN_DEFINE_FUNC(myplug) +{ + snd_config_iterator_t i, next; + snd_config_t *slave = NULL; + struct myplug_info *myplug; + int err; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "my_own_parameter") == 0) { + .... + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + + if (! slave) { + SNDERR("No slave defined for myplug"); + return -EINVAL; + } + + myplug = calloc(1, sizeof(*myplug)); + if (myplug == NULL) + return -ENOMEM; + + myplug->ext.version = SND_PCM_EXTPLUG_VERSION; + myplug->ext.name = "My Own Plugin"; + myplug->ext.callback = &my_own_callback; + myplug->ext.private_data = myplug; + .... + + err = snd_pcm_extplug_create(&myplug->ext, name, root, conf, stream, mode); + if (err < 0) { + myplug_free(myplug); + return err; + } + + *pcmp = myplug->ext.pcm; + return 0; +} + +SND_PCM_PLUGIN_SYMBOL(myplug); +\endcode + +Read the codes in alsa-plugins package for the real examples. + + +\section pcm_extplug External Plugin: Filter-Type Plugin + +The filter-type plugin is a plugin to convert the PCM signals from the input +and feeds to the output. Thus, this plugin always needs a slave PCM as its output. + +The plugin can modify the format and the channels of the input/output PCM. +It can not modify the sample rate (because of simplicity reason). + +The following fields have to be filled in extplug record before calling +#snd_pcm_extplug_create() : version, name, callback. +Otherfields are optional and should be initialized with zero. + +The constant #SND_PCM_EXTPLUG_VERSION must be passed to the version +field for the version check in alsa-lib. A non-NULL ASCII string +has to be passed to the name field. The callback field contains the +table of callback functions for this plugin (defined as +#snd_pcm_extplug_callback_t). + +The driver can set an arbitrary value (pointer) to private_data +field to refer its own data in the callbacks. + +The rest fields are filled by #snd_pcm_extplug_create(). The pcm field +is the resultant PCM handle. The others are the current status of the +PCM. + +The callback functions in #snd_pcm_extplug_callback_t define the real +behavior of the driver. +At least, transfer callback must be given. This callback is called +at each time certain size of data block is transfered to the slave +PCM. Other callbacks are optional. + +The close callback is called when the PCM is closed. If the plugin +allocates private resources, this is the place to release them +again. The hw_params and hw_free callbacks are called at +#snd_pcm_hw_params() and #snd_pcm_hw_free() API calls, +respectively. The last, dump callback, is called for printing the +information of the given plugin. + +The init callback is called when the PCM is at prepare state or any +initialization is issued. Use this callback to reset the PCM instance +to a sane initial state. + +The hw_params constraints can be defined via either +#snd_pcm_extplug_set_param_minmax() and #snd_pcm_extplug_set_param_list() +functions after calling #snd_pcm_extplug_create(). +The former defines the minimal and maximal acceptable values for the +given hw_params parameter (SND_PCM_EXTPLUG_HW_XXX). +This function can't be used for the format parameter. The latter +function specifies the available parameter values as the list. +As mentioned above, the rate can't be changed. Only changeable +parameters are sample format and channels. + +To define the constraints of the slave PCM configuration, use +either #snd_pcm_extplug_set_slave_param_minmax() and +#snd_pcm_extplug_set_slave_param_list(). The arguments are as same +as former functions. + +To clear the parameter constraints, call #snd_pcm_extplug_params_reset() +function. + +*/ + +/** + * \brief Create an extplug instance + * \param extplug the extplug handle + * \param name name of the PCM + * \param root configuration tree root + * \param slave_conf slave configuration root + * \param stream stream direction + * \param mode PCM open mode + * \return 0 if successful, or a negative error code + * + * Creates the extplug instance based on the given handle. + * The slave_conf argument is mandatory, and usually taken from the config tree of the + * PCM plugin as "slave" config value. + * name, root, stream and mode arguments are the values used for opening the PCM. + * + * The callback is the mandatory field of extplug handle. At least, start, stop and + * pointer callbacks must be set before calling this function. + */ +int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, + snd_config_t *root, snd_config_t *slave_conf, + snd_pcm_stream_t stream, int mode) +{ + extplug_priv_t *ext; + int err; + snd_pcm_t *spcm, *pcm; + snd_config_t *sconf; + + assert(root); + assert(extplug && extplug->callback); + assert(extplug->callback->transfer); + assert(slave_conf); + + if (extplug->version != SND_PCM_EXTPLUG_VERSION) { + SNDERR("extplug: Plugin version mismatch\n"); + return -ENXIO; + } + + err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL); + snd_config_delete(sconf); + if (err < 0) + return err; + + ext = calloc(1, sizeof(*ext)); + if (! ext) + return -ENOMEM; + + ext->data = extplug; + extplug->stream = stream; + + snd_pcm_plugin_init(&ext->plug); + ext->plug.read = snd_pcm_extplug_read_areas; + ext->plug.write = snd_pcm_extplug_write_areas; + ext->plug.undo_read = snd_pcm_plugin_undo_read_generic; + ext->plug.undo_write = snd_pcm_plugin_undo_write_generic; + ext->plug.gen.slave = spcm; + ext->plug.gen.close_slave = 1; + if (extplug->callback->init) + ext->plug.init = snd_pcm_extplug_init; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_EXTPLUG, name, stream, mode); + if (err < 0) { + free(ext); + return err; + } + + extplug->pcm = pcm; + pcm->ops = &snd_pcm_extplug_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = ext; + pcm->poll_fd = spcm->poll_fd; + pcm->poll_events = spcm->poll_events; + snd_pcm_set_hw_ptr(pcm, &ext->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &ext->plug.appl_ptr, -1, 0); + + return 0; +} + +/** + * \brief Delete the extplug instance + * \param extplug the extplug handle to delete + * \return 0 if successful, or a negative error code + * + * The destructor of extplug instance. + * Closes the PCM and deletes the associated resources. + */ +int snd_pcm_extplug_delete(snd_pcm_extplug_t *extplug) +{ + return snd_pcm_close(extplug->pcm); +} + + +/** + * \brief Reset extplug parameters + * \param extplug the extplug handle + * + * Resets the all parameters for the given extplug handle. + */ +void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *extplug) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + clear_ext_params(ext); +} + +/** + * \brief Set slave parameter as the list + * \param extplug the extplug handle + * \param type parameter type + * \param num_list number of available values + * \param list the list of available values + * \return 0 if successful, or a negative error code + * + * Sets the slave parameter as the list. + * The available values of the given parameter type of the slave PCM is restricted + * to the ones of the given list. + */ +int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_list(&ext->sparams[type], num_list, list); +} + +/** + * \brief Set slave parameter as the min/max values + * \param extplug the extplug handle + * \param type parameter type + * \param min the minimum value + * \param max the maximum value + * \return 0 if successful, or a negative error code + * + * Sets the slave parameter as the min/max values. + * The available values of the given parameter type of the slave PCM is restricted + * between the given minimum and maximum values. + */ +int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (is_mask_type(type)) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_minmax(&ext->sparams[type], min, max); +} + +/** + * \brief Set master parameter as the list + * \param extplug the extplug handle + * \param type parameter type + * \param num_list number of available values + * \param list the list of available values + * \return 0 if successful, or a negative error code + * + * Sets the master parameter as the list. + * The available values of the given parameter type of this PCM (as input) is restricted + * to the ones of the given list. + */ +int snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_list(&ext->params[type], num_list, list); +} + +/** + * \brief Set master parameter as the min/max values + * \param extplug the extplug handle + * \param type parameter type + * \param min the minimum value + * \param max the maximum value + * \return 0 if successful, or a negative error code + * + * Sets the master parameter as the min/max values. + * The available values of the given parameter type of this PCM (as input) is restricted + * between the given minimum and maximum values. + */ +int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (is_mask_type(type)) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_minmax(&ext->params[type], min, max); +} + diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c new file mode 100644 index 0000000..bfa1cc8 --- /dev/null +++ b/src/pcm/pcm_file.c @@ -0,0 +1,965 @@ +/** + * \file pcm/pcm_file.c + * \ingroup PCM_Plugins + * \brief PCM File Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - File plugin + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_file = ""; +#endif + +#ifndef DOC_HIDDEN + +/* keys to be replaced by real values in the filename */ +#define LEADING_KEY '%' /* i.e. %r, %c, %b ... */ +#define RATE_KEY 'r' +#define CHANNELS_KEY 'c' +#define BWIDTH_KEY 'b' +#define FORMAT_KEY 'f' + +/* maximum length of a value */ +#define VALUE_MAXLEN 64 + +typedef enum _snd_pcm_file_format { + SND_PCM_FILE_FORMAT_RAW, + SND_PCM_FILE_FORMAT_WAV +} snd_pcm_file_format_t; + +/* WAV format chunk */ +struct wav_fmt { + short fmt; + short chan; + int rate; + int bps; + short bwidth; + short bits; +}; + +typedef struct { + snd_pcm_generic_t gen; + char *fname; + char *final_fname; + int trunc; + int perm; + int fd; + char *ifname; + int ifd; + int format; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t file_ptr_bytes; + snd_pcm_uframes_t wbuf_size; + size_t wbuf_size_bytes; + size_t wbuf_used_bytes; + char *wbuf; + size_t rbuf_size_bytes; + size_t rbuf_used_bytes; + char *rbuf; + snd_pcm_channel_area_t *wbuf_areas; + size_t buffer_bytes; + struct wav_fmt wav_header; + size_t filelen; +} snd_pcm_file_t; + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define TO_LE32(x) (x) +#define TO_LE16(x) (x) +#else +#define TO_LE32(x) bswap_32(x) +#define TO_LE16(x) bswap_16(x) +#endif + +static int snd_pcm_file_append_value(char **string_p, char **index_ch_p, + int *len_p, const char *value) +{ + char *string, *index_ch; + int index, len, value_len; + /* input pointer values */ + len = *(len_p); + string = *(string_p); + index_ch = *(index_ch_p); + + value_len = strlen(value); + /* reallocation to accommodate the value */ + index = index_ch - string; + len += value_len; + string = realloc(string, len + 1); + if (!string) + return -ENOMEM; + index_ch = string + index; + /* concatenating the new value */ + strcpy(index_ch, value); + index_ch += value_len; + /* return values */ + *(len_p) = len; + *(string_p) = string; + *(index_ch_p) = index_ch; + return 0; +} + +static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p) +{ + char value[VALUE_MAXLEN]; + char *fname = file->fname; + char *new_fname = NULL; + char *old_last_ch, *old_index_ch, *new_index_ch; + int old_len, new_len, err; + + snd_pcm_t *pcm = file->gen.slave; + + /* we want to keep fname, const */ + old_len = new_len = strlen(fname); + old_last_ch = fname + old_len - 1; + new_fname = malloc(new_len + 1); + if (!new_fname) + return -ENOMEM; + + old_index_ch = fname; /* first character of the old name */ + new_index_ch = new_fname; /* first char of the new name */ + + while (old_index_ch <= old_last_ch) { + if (*(old_index_ch) == LEADING_KEY && + old_index_ch != old_last_ch) { + /* is %, not last char, skipping and checking + next char */ + switch (*(++old_index_ch)) { + case RATE_KEY: + snprintf(value, sizeof(value), "%d", + pcm->rate); + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, value); + if (err < 0) + return err; + break; + + case CHANNELS_KEY: + snprintf(value, sizeof(value), "%d", + pcm->channels); + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, value); + if (err < 0) + return err; + break; + + case BWIDTH_KEY: + snprintf(value, sizeof(value), "%d", + pcm->frame_bits/pcm->channels); + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, value); + if (err < 0) + return err; + break; + + case FORMAT_KEY: + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, + snd_pcm_format_name(pcm->format)); + if (err < 0) + return err; + break; + + default: + /* non-key char, just copying */ + *(new_index_ch++) = *(old_index_ch); + } + /* next old char */ + old_index_ch++; + } else { + /* plain copying, shifting both strings to next chars */ + *(new_index_ch++) = *(old_index_ch++); + } + } + /* closing the new string */ + *(new_index_ch) = '\0'; + *(new_fname_p) = new_fname; + return 0; + +} + +static int snd_pcm_file_open_output_file(snd_pcm_file_t *file) +{ + int err, fd; + + /* fname can contain keys, generating final_fname */ + err = snd_pcm_file_replace_fname(file, &(file->final_fname)); + if (err < 0) + return err; + /*printf("DEBUG - original fname: %s, final fname: %s\n", + file->fname, file->final_fname);*/ + + if (file->final_fname[0] == '|') { + /* pipe mode */ + FILE *pipe; + /* clearing */ + pipe = popen(file->final_fname + 1, "w"); + if (!pipe) { + SYSERR("running %s for writing failed", + file->final_fname); + return -errno; + } + fd = fileno(pipe); + } else { + if (file->trunc) + fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC, + file->perm); + else { + fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL, + file->perm); + if (fd < 0) { + char *tmpfname = NULL; + int idx, len; + len = strlen(file->final_fname) + 6; + tmpfname = malloc(len); + if (!tmpfname) + return -ENOMEM; + for (idx = 1; idx < 10000; idx++) { + snprintf(tmpfname, len, + "%s.%04d", file->final_fname, + idx); + fd = open(tmpfname, + O_WRONLY|O_CREAT|O_EXCL, + file->perm); + if (fd >= 0) { + free(file->final_fname); + file->final_fname = tmpfname; + break; + } + } + if (fd < 0) { + SYSERR("open %s for writing failed", + file->final_fname); + free(tmpfname); + return -errno; + } + } + } + } + file->fd = fd; + return 0; +} + +static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt) +{ + fmt->fmt = TO_LE16(0x01); + fmt->chan = TO_LE16(pcm->channels); + fmt->rate = TO_LE32(pcm->rate); + fmt->bwidth = pcm->frame_bits / 8; + fmt->bps = fmt->bwidth * pcm->rate; + fmt->bits = snd_pcm_format_width(pcm->format); + fmt->bps = TO_LE32(fmt->bps); + fmt->bwidth = TO_LE16(fmt->bwidth); + fmt->bits = TO_LE16(fmt->bits); +} + +static int write_wav_header(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + static const char header[] = { + 'R', 'I', 'F', 'F', + 0x24, 0, 0, 0, + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 0x10, 0, 0, 0, + }; + static const char header2[] = { + 'd', 'a', 't', 'a', + 0, 0, 0, 0 + }; + + setup_wav_header(pcm, &file->wav_header); + + if (write(file->fd, header, sizeof(header)) != sizeof(header) || + write(file->fd, &file->wav_header, sizeof(file->wav_header)) != + sizeof(file->wav_header) || + write(file->fd, header2, sizeof(header2)) != sizeof(header2)) { + int err = errno; + SYSERR("Write error.\n"); + return -err; + } + return 0; +} + +/* fix up the length fields in WAV header */ +static void fixup_wav_header(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + int len, ret; + + /* RIFF length */ + if (lseek(file->fd, 4, SEEK_SET) == 4) { + len = (file->filelen + 0x24) > 0x7fffffff ? + 0x7fffffff : (int)(file->filelen + 0x24); + len = TO_LE32(len); + ret = write(file->fd, &len, 4); + if (ret < 0) + return; + } + /* data length */ + if (lseek(file->fd, 0x28, SEEK_SET) == 0x28) { + len = file->filelen > 0x7fffffff ? + 0x7fffffff : (int)file->filelen; + len = TO_LE32(len); + ret = write(file->fd, &len, 4); + if (ret < 0) + return; + } +} +#endif /* DOC_HIDDEN */ + + + +static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes) +{ + snd_pcm_file_t *file = pcm->private_data; + assert(bytes <= file->wbuf_used_bytes); + + if (file->format == SND_PCM_FILE_FORMAT_WAV && + !file->wav_header.fmt) { + if (write_wav_header(pcm) < 0) + return; + } + + while (bytes > 0) { + snd_pcm_sframes_t err; + size_t n = bytes; + size_t cont = file->wbuf_size_bytes - file->file_ptr_bytes; + if (n > cont) + n = cont; + err = write(file->fd, file->wbuf + file->file_ptr_bytes, n); + if (err < 0) { + SYSERR("write failed"); + break; + } + bytes -= err; + file->wbuf_used_bytes -= err; + file->file_ptr_bytes += err; + if (file->file_ptr_bytes == file->wbuf_size_bytes) + file->file_ptr_bytes = 0; + file->filelen += err; + if ((snd_pcm_uframes_t)err != n) + break; + } +} + +static void snd_pcm_file_add_frames(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t frames) +{ + snd_pcm_file_t *file = pcm->private_data; + while (frames > 0) { + snd_pcm_uframes_t n = frames; + snd_pcm_uframes_t cont = file->wbuf_size - file->appl_ptr; + snd_pcm_uframes_t avail = file->wbuf_size - snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); + if (n > cont) + n = cont; + if (n > avail) + n = avail; + snd_pcm_areas_copy(file->wbuf_areas, file->appl_ptr, + areas, offset, + pcm->channels, n, pcm->format); + frames -= n; + offset += n; + file->appl_ptr += n; + if (file->appl_ptr == file->wbuf_size) + file->appl_ptr = 0; + file->wbuf_used_bytes += snd_pcm_frames_to_bytes(pcm, n); + if (file->wbuf_used_bytes > file->buffer_bytes) + snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes - file->buffer_bytes); + assert(file->wbuf_used_bytes < file->wbuf_size_bytes); + } +} + +static int snd_pcm_file_close(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + if (file->fname) { + if (file->wav_header.fmt) + fixup_wav_header(pcm); + free((void *)file->fname); + close(file->fd); + } + if (file->ifname) { + free((void *)file->ifname); + close(file->ifd); + } + return snd_pcm_generic_close(pcm); +} + +static int snd_pcm_file_reset(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + int err = snd_pcm_reset(file->gen.slave); + if (err >= 0) { + /* FIXME: Questionable here */ + snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); + assert(file->wbuf_used_bytes == 0); + } + return err; +} + +static int snd_pcm_file_drop(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + int err = snd_pcm_drop(file->gen.slave); + if (err >= 0) { + /* FIXME: Questionable here */ + snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); + assert(file->wbuf_used_bytes == 0); + } + return err; +} + +static int snd_pcm_file_drain(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + int err = snd_pcm_drain(file->gen.slave); + if (err >= 0) { + snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); + assert(file->wbuf_used_bytes == 0); + } + return err; +} + +static snd_pcm_sframes_t snd_pcm_file_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_sframes_t res = snd_pcm_rewindable(pcm); + snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); + if (res > n) + res = n; + return res; +} + +static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_sframes_t err; + snd_pcm_uframes_t n; + + n = snd_pcm_frames_to_bytes(pcm, frames); + if (n > file->wbuf_used_bytes) + frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes); + err = snd_pcm_rewind(file->gen.slave, frames); + if (err > 0) { + file->appl_ptr = (file->appl_ptr - err + file->wbuf_size) % file->wbuf_size; + n = snd_pcm_frames_to_bytes(pcm, err); + file->wbuf_used_bytes -= n; + } + return err; +} + +static snd_pcm_sframes_t snd_pcm_file_forwardable(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_sframes_t res = snd_pcm_forwardable(pcm); + snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes); + if (res > n) + res = n; + return res; +} + +static snd_pcm_sframes_t snd_pcm_file_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_sframes_t err; + snd_pcm_uframes_t n; + + n = snd_pcm_frames_to_bytes(pcm, frames); + if (file->wbuf_used_bytes + n > file->wbuf_size_bytes) + frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes); + err = INTERNAL(snd_pcm_forward)(file->gen.slave, frames); + if (err > 0) { + file->appl_ptr = (file->appl_ptr + err) % file->wbuf_size; + n = snd_pcm_frames_to_bytes(pcm, err); + file->wbuf_used_bytes += n; + } + return err; +} + +static snd_pcm_sframes_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_sframes_t n = snd_pcm_writei(file->gen.slave, buffer, size); + if (n > 0) { + snd_pcm_areas_from_buf(pcm, areas, (void*) buffer); + snd_pcm_file_add_frames(pcm, areas, 0, n); + } + return n; +} + +static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_sframes_t n = snd_pcm_writen(file->gen.slave, bufs, size); + if (n > 0) { + snd_pcm_areas_from_bufs(pcm, areas, bufs); + snd_pcm_file_add_frames(pcm, areas, 0, n); + } + return n; +} + +static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_sframes_t n; + + n = snd_pcm_readi(file->gen.slave, buffer, size); + if (n <= 0) + return n; + if (file->ifd >= 0) { + n = read(file->ifd, buffer, n * pcm->frame_bits / 8); + if (n < 0) + return n; + return n * 8 / pcm->frame_bits; + } + snd_pcm_areas_from_buf(pcm, areas, buffer); + snd_pcm_file_add_frames(pcm, areas, 0, n); + return n; +} + +static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_sframes_t n; + + if (file->ifd >= 0) { + SNDERR("DEBUG: Noninterleaved read not yet implemented.\n"); + return 0; /* TODO: Noninterleaved read */ + } + + n = snd_pcm_readn(file->gen.slave, bufs, size); + if (n > 0) { + snd_pcm_areas_from_bufs(pcm, areas, bufs); + snd_pcm_file_add_frames(pcm, areas, 0, n); + } + return n; +} + +static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_uframes_t ofs; + snd_pcm_uframes_t siz = size; + const snd_pcm_channel_area_t *areas; + snd_pcm_sframes_t result; + + snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); + assert(ofs == offset && siz == size); + result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); + if (result > 0) + snd_pcm_file_add_frames(pcm, areas, ofs, result); + return result; +} + +static int snd_pcm_file_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_file_t *file = pcm->private_data; + free(file->wbuf); + free(file->wbuf_areas); + file->wbuf = NULL; + file->wbuf_areas = NULL; + return snd_pcm_hw_free(file->gen.slave); +} + +static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_file_t *file = pcm->private_data; + unsigned int channel; + snd_pcm_t *slave = file->gen.slave; + int err = _snd_pcm_hw_params(slave, params); + if (err < 0) + return err; + file->buffer_bytes = snd_pcm_frames_to_bytes(slave, slave->buffer_size); + file->wbuf_size = slave->buffer_size * 2; + file->wbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->wbuf_size); + file->wbuf_used_bytes = 0; + assert(!file->wbuf); + file->wbuf = malloc(file->wbuf_size_bytes); + if (file->wbuf == NULL) { + snd_pcm_file_hw_free(pcm); + return -ENOMEM; + } + file->wbuf_areas = malloc(sizeof(*file->wbuf_areas) * slave->channels); + if (file->wbuf_areas == NULL) { + snd_pcm_file_hw_free(pcm); + return -ENOMEM; + } + file->appl_ptr = file->file_ptr_bytes = 0; + for (channel = 0; channel < slave->channels; ++channel) { + snd_pcm_channel_area_t *a = &file->wbuf_areas[channel]; + a->addr = file->wbuf; + a->first = slave->sample_bits * channel; + a->step = slave->frame_bits; + } + if (file->fd < 0) { + err = snd_pcm_file_open_output_file(file); + if (err < 0) { + SYSERR("failed opening output file %s", file->fname); + return err; + } + } + return 0; +} + +static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_file_t *file = pcm->private_data; + if (file->fname) + snd_output_printf(out, "File PCM (file=%s)\n", file->fname); + else + snd_output_printf(out, "File PCM (fd=%d)\n", file->fd); + if (file->final_fname) + snd_output_printf(out, "Final file PCM (file=%s)\n", + file->final_fname); + + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(file->gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_file_ops = { + .close = snd_pcm_file_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_generic_hw_refine, + .hw_params = snd_pcm_file_hw_params, + .hw_free = snd_pcm_file_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_file_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { + .status = snd_pcm_generic_status, + .state = snd_pcm_generic_state, + .hwsync = snd_pcm_generic_hwsync, + .delay = snd_pcm_generic_delay, + .prepare = snd_pcm_generic_prepare, + .reset = snd_pcm_file_reset, + .start = snd_pcm_generic_start, + .drop = snd_pcm_file_drop, + .drain = snd_pcm_file_drain, + .pause = snd_pcm_generic_pause, + .rewindable = snd_pcm_file_rewindable, + .rewind = snd_pcm_file_rewind, + .forwardable = snd_pcm_file_forwardable, + .forward = snd_pcm_file_forward, + .resume = snd_pcm_generic_resume, + .link = snd_pcm_generic_link, + .link_slaves = snd_pcm_generic_link_slaves, + .unlink = snd_pcm_generic_unlink, + .writei = snd_pcm_file_writei, + .writen = snd_pcm_file_writen, + .readi = snd_pcm_file_readi, + .readn = snd_pcm_file_readn, + .avail_update = snd_pcm_generic_avail_update, + .mmap_commit = snd_pcm_file_mmap_commit, + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_generic_poll_revents, +}; + +/** + * \brief Creates a new File PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param fname Output filename (or NULL if file descriptor fd is available) + * \param fd Output file descriptor + * \param ifname Input filename (or NULL if file descriptor ifd is available) + * \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input + * redirection will be performed) + * \param trunc Truncate the file if it already exists + * \param fmt File format ("raw" or "wav" are available) + * \param perm File permission + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, + const char *fname, int fd, const char *ifname, int ifd, + int trunc, + const char *fmt, int perm, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_file_t *file; + snd_pcm_file_format_t format; + struct timespec timespec; + int err; + + assert(pcmp); + if (fmt == NULL || + strcmp(fmt, "raw") == 0) + format = SND_PCM_FILE_FORMAT_RAW; + else if (!strcmp(fmt, "wav")) + format = SND_PCM_FILE_FORMAT_WAV; + else { + SNDERR("file format %s is unknown", fmt); + return -EINVAL; + } + file = calloc(1, sizeof(snd_pcm_file_t)); + if (!file) { + return -ENOMEM; + } + + /* opening output fname is delayed until writing, + when PCM params are known */ + if (fname) + file->fname = strdup(fname); + file->trunc = trunc; + file->perm = perm; + + if (ifname) { + ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */ + if (ifd < 0) { + SYSERR("open %s for reading failed", ifname); + free(file); + return -errno; + } + file->ifname = strdup(ifname); + } + file->fd = fd; + file->ifd = ifd; + file->format = format; + file->gen.slave = slave; + file->gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode); + if (err < 0) { + free(file->fname); + free(file); + return err; + } + pcm->ops = &snd_pcm_file_ops; + pcm->fast_ops = &snd_pcm_file_fast_ops; + pcm->private_data = file; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + pcm->monotonic = clock_gettime(CLOCK_MONOTONIC, ×pec) == 0; +#else + pcm->monotonic = 0; +#endif + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_file Plugin: File + +This plugin stores contents of a PCM stream to file or pipes the stream +to a command, and optionally uses an existing file as an input data source +(i.e., "virtual mic") + +\code +pcm.name { + type file # File PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + file STR # Output filename (or shell command the stream + # will be piped to if STR starts with the pipe + # char). + # STR can contain format keys, replaced by + # real values corresponding to the stream: + # %r rate (replaced with: 48000) + # %c channels (replaced with: 2) + # %b bits per sample (replaced with: 16) + # %f sample format string + # (replaced with: S16_LE) + # %% replaced with % + or + file INT # Output file descriptor number + infile STR # Input filename - only raw format + or + infile INT # Input file descriptor number + [format STR] # File format ("raw" or "wav") + [perm INT] # Output file permission (octal, def. 0600) +} +\endcode + +\subsection pcm_plugins_file_funcref Function reference + +
    +
  • snd_pcm_file_open() +
  • _snd_pcm_file_open() +
+ +*/ + +/** + * \brief Creates a new File PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with File PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + const char *fname = NULL, *ifname = NULL; + const char *format = NULL; + long fd = -1, ifd = -1, trunc = 1; + long perm = 0600; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "format") == 0) { + err = snd_config_get_string(n, &format); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "file") == 0) { + err = snd_config_get_string(n, &fname); + if (err < 0) { + err = snd_config_get_integer(n, &fd); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + } + continue; + } + if (strcmp(id, "infile") == 0) { + err = snd_config_get_string(n, &ifname); + if (err < 0) { + err = snd_config_get_integer(n, &ifd); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + } + continue; + } + if (strcmp(id, "perm") == 0) { + err = snd_config_get_integer(n, &perm); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + if ((perm & ~0777) != 0) { + SNDERR("The field perm must be a valid file permission"); + return -EINVAL; + } + continue; + } + if (strcmp(id, "truncate") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return -EINVAL; + trunc = err; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!format) { + snd_config_t *n; + /* read defaults */ + if (snd_config_search(root, "defaults.pcm.file_format", &n) >= 0) { + err = snd_config_get_string(n, &format); + if (err < 0) { + SNDERR("Invalid file format"); + return -EINVAL; + } + } + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + if ((!fname || strlen(fname) == 0) && fd < 0 && !ifname) { + snd_config_delete(sconf); + SNDERR("file is not defined"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd, + trunc, format, perm, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_file_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c new file mode 100644 index 0000000..84ea85f --- /dev/null +++ b/src/pcm/pcm_generic.c @@ -0,0 +1,326 @@ +/** + * \file pcm/pcm_generic.c + * \ingroup PCM + * \brief PCM Interface + * \author Jaroslav Kysela + * \date 2004 + */ +/* + * PCM - Common generic plugin code + * Copyright (c) 2004 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "pcm_local.h" +#include "pcm_generic.h" + +#ifndef DOC_HIDDEN + +int snd_pcm_generic_close(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + int err = 0; + if (generic->close_slave) + err = snd_pcm_close(generic->slave); + free(generic); + return 0; +} + +int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_nonblock(generic->slave, nonblock); +} + +int snd_pcm_generic_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_async(generic->slave, sig, pid); +} + +int snd_pcm_generic_poll_descriptors_count(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_poll_descriptors_count(generic->slave); +} + +int snd_pcm_generic_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_poll_descriptors(generic->slave, pfds, space); +} + +int snd_pcm_generic_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_poll_descriptors_revents(generic->slave, pfds, nfds, revents); +} + +int snd_pcm_generic_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_info(generic->slave, info); +} + +int snd_pcm_generic_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_hw_free(generic->slave); +} + +int snd_pcm_generic_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_sw_params(generic->slave, params); +} + +int snd_pcm_generic_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_hw_refine(generic->slave, params); +} + +int snd_pcm_generic_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return _snd_pcm_hw_params(generic->slave, params); +} + +int snd_pcm_generic_prepare(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_prepare(generic->slave); +} + +int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) +{ + snd_pcm_generic_t *generic = pcm->private_data; + if (pcm->mmap_shadow) { + /* No own buffer is required - the plugin won't change + * the data on the buffer, or do safely on-the-place + * conversion + */ + return snd_pcm_channel_info(generic->slave, info); + } else { + /* Allocate own buffer */ + return snd_pcm_channel_info_shm(pcm, info, -1); + } +} + +int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_status(generic->slave, status); +} + +snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_state(generic->slave); +} + +int snd_pcm_generic_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_hwsync(generic->slave); +} + +int snd_pcm_generic_reset(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_reset(generic->slave); +} + +int snd_pcm_generic_start(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_start(generic->slave); +} + +int snd_pcm_generic_drop(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_drop(generic->slave); +} + +int snd_pcm_generic_drain(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_drain(generic->slave); +} + +int snd_pcm_generic_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_pause(generic->slave, enable); +} + +int snd_pcm_generic_resume(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_resume(generic->slave); +} + +int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_delay(generic->slave, delayp); +} + +snd_pcm_sframes_t snd_pcm_generic_forwardable(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_forwardable(generic->slave); +} + +snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return INTERNAL(snd_pcm_forward)(generic->slave, frames); +} + +snd_pcm_sframes_t snd_pcm_generic_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_rewindable(generic->slave); +} + +snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_rewind(generic->slave, frames); +} + +int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + snd_pcm_generic_t *generic = pcm1->private_data; + if (generic->slave->fast_ops->link) + return generic->slave->fast_ops->link(generic->slave->fast_op_arg, pcm2); + return -ENOSYS; +} + +int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master) +{ + snd_pcm_generic_t *generic = pcm->private_data; + if (generic->slave->fast_ops->link_slaves) + return generic->slave->fast_ops->link_slaves(generic->slave->fast_op_arg, master); + return -ENOSYS; +} + +int snd_pcm_generic_unlink(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + if (generic->slave->fast_ops->unlink) + return generic->slave->fast_ops->unlink(generic->slave->fast_op_arg); + return -ENOSYS; +} + +snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_writei(generic->slave, buffer, size); +} + +snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_writen(generic->slave, bufs, size); +} + +snd_pcm_sframes_t snd_pcm_generic_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_readi(generic->slave, buffer, size); +} + +snd_pcm_sframes_t snd_pcm_generic_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_readn(generic->slave, bufs, size); +} + +snd_pcm_sframes_t snd_pcm_generic_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_mmap_commit(generic->slave, offset, size); +} + +snd_pcm_sframes_t snd_pcm_generic_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_avail_update(generic->slave); +} + +int snd_pcm_generic_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_htimestamp(generic->slave, avail, tstamp); +} + +/* stand-alone version - similar like snd_pcm_hw_htimestamp but + * taking the tstamp via gettimestamp(). + */ +int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_sframes_t avail1; + int ok = 0; + + while (1) { + avail1 = snd_pcm_avail_update(pcm); + if (avail1 < 0) + return avail1; + if (ok && (snd_pcm_uframes_t)avail1 == *avail) + break; + *avail = avail1; + gettimestamp(tstamp, pcm->monotonic); + ok = 1; + } + return 0; +} + +int snd_pcm_generic_mmap(snd_pcm_t *pcm) +{ + if (pcm->mmap_shadow) { + /* Copy the slave mmapped buffer data */ + snd_pcm_generic_t *generic = pcm->private_data; + pcm->mmap_channels = generic->slave->mmap_channels; + pcm->running_areas = generic->slave->running_areas; + pcm->stopped_areas = generic->slave->stopped_areas; + } + return 0; +} + +int snd_pcm_generic_munmap(snd_pcm_t *pcm) +{ + if (pcm->mmap_shadow) { + /* Clean up */ + pcm->mmap_channels = NULL; + pcm->running_areas = NULL; + pcm->stopped_areas = NULL; + } + return 0; +} + +#endif /* DOC_HIDDEN */ diff --git a/src/pcm/pcm_generic.h b/src/pcm/pcm_generic.h new file mode 100644 index 0000000..430b8cf --- /dev/null +++ b/src/pcm/pcm_generic.h @@ -0,0 +1,151 @@ +/* + * PCM - Common generic plugin code + * Copyright (c) 2004 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +typedef struct { + snd_pcm_t *slave; + int close_slave; +} snd_pcm_generic_t; + +/* make local functions really local */ +#define snd_pcm_generic_close \ + snd1_pcm_generic_close +#define snd_pcm_generic_nonblock \ + snd1_pcm_generic_nonblock +#define snd_pcm_generic_async \ + snd1_pcm_generic_async +#define snd_pcm_generic_poll_descriptors_count \ + snd1_pcm_generic_poll_descriptors_count +#define snd_pcm_generic_poll_descriptors \ + snd1_pcm_generic_poll_descriptors +#define snd_pcm_generic_poll_revents \ + snd1_pcm_generic_poll_revents +#define snd_pcm_generic_info \ + snd1_pcm_generic_info +#define snd_pcm_generic_hw_free \ + snd1_pcm_generic_hw_free +#define snd_pcm_generic_sw_params \ + snd1_pcm_generic_sw_params +#define snd_pcm_generic_hw_refine \ + snd1_pcm_generic_hw_refine +#define snd_pcm_generic_hw_params \ + snd1_pcm_generic_hw_params +#define snd_pcm_generic_channel_info \ + snd1_pcm_generic_channel_info +#define snd_pcm_generic_channel_info_no_buffer \ + snd1_pcm_generic_channel_info_no_buffer +#define snd_pcm_generic_status \ + snd1_pcm_generic_status +#define snd_pcm_generic_state \ + snd1_pcm_generic_state +#define snd_pcm_generic_prepare \ + snd1_pcm_generic_prepare +#define snd_pcm_generic_hwsync \ + snd1_pcm_generic_hwsync +#define snd_pcm_generic_reset \ + snd1_pcm_generic_reset +#define snd_pcm_generic_start \ + snd1_pcm_generic_start +#define snd_pcm_generic_drop \ + snd1_pcm_generic_drop +#define snd_pcm_generic_drain \ + snd1_pcm_generic_drain +#define snd_pcm_generic_pause \ + snd1_pcm_generic_pause +#define snd_pcm_generic_resume \ + snd1_pcm_generic_resume +#define snd_pcm_generic_delay \ + snd1_pcm_generic_delay +#define snd_pcm_generic_forwardable \ + snd1_pcm_generic_forwardable +#define snd_pcm_generic_forward \ + snd1_pcm_generic_forward +#define snd_pcm_generic_rewindable \ + snd1_pcm_generic_rewindable +#define snd_pcm_generic_rewind \ + snd1_pcm_generic_rewind +#define snd_pcm_generic_link \ + snd1_pcm_generic_link +#define snd_pcm_generic_link_slaves \ + snd1_pcm_generic_link_slaves +#define snd_pcm_generic_unlink \ + snd1_pcm_generic_unlink +#define snd_pcm_generic_writei \ + snd1_pcm_generic_writei +#define snd_pcm_generic_writen \ + snd1_pcm_generic_writen +#define snd_pcm_generic_readi \ + snd1_pcm_generic_readi +#define snd_pcm_generic_readn \ + snd1_pcm_generic_readn +#define snd_pcm_generic_mmap_commit \ + snd1_pcm_generic_mmap_commit +#define snd_pcm_generic_avail_update \ + snd1_pcm_generic_avail_update +#define snd_pcm_generic_mmap \ + snd1_pcm_generic_mmap +#define snd_pcm_generic_munmap \ + snd1_pcm_generic_munmap + +int snd_pcm_generic_close(snd_pcm_t *pcm); +int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock); +int snd_pcm_generic_async(snd_pcm_t *pcm, int sig, pid_t pid); +int snd_pcm_generic_poll_descriptors_count(snd_pcm_t *pcm); +int snd_pcm_generic_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); +int snd_pcm_generic_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_pcm_generic_info(snd_pcm_t *pcm, snd_pcm_info_t * info); +int snd_pcm_generic_hw_free(snd_pcm_t *pcm); +int snd_pcm_generic_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); +int snd_pcm_generic_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_generic_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info); +int snd_pcm_generic_channel_info_no_buffer(snd_pcm_t *pcm, snd_pcm_channel_info_t * info); +int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status); +snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm); +int snd_pcm_generic_prepare(snd_pcm_t *pcm); +int snd_pcm_generic_hwsync(snd_pcm_t *pcm); +int snd_pcm_generic_reset(snd_pcm_t *pcm); +int snd_pcm_generic_start(snd_pcm_t *pcm); +int snd_pcm_generic_drop(snd_pcm_t *pcm); +int snd_pcm_generic_drain(snd_pcm_t *pcm); +int snd_pcm_generic_pause(snd_pcm_t *pcm, int enable); +int snd_pcm_generic_resume(snd_pcm_t *pcm); +int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); +snd_pcm_sframes_t snd_pcm_generic_forwardable(snd_pcm_t *pcm); +snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_generic_rewindable(snd_pcm_t *pcm); +snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2); +int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master); +int snd_pcm_generic_unlink(snd_pcm_t *pcm); +snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_generic_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_generic_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_generic_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_generic_avail_update(snd_pcm_t *pcm); +int snd_pcm_generic_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *timestamp); +int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp); +int snd_pcm_generic_mmap(snd_pcm_t *pcm); +int snd_pcm_generic_munmap(snd_pcm_t *pcm); diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c new file mode 100644 index 0000000..3a99d55 --- /dev/null +++ b/src/pcm/pcm_hooks.c @@ -0,0 +1,722 @@ +/** + * \file pcm/pcm_hooks.c + * \ingroup PCM_Hook + * \brief PCM Hook Interface + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2000-2001 + */ +/* + * PCM - Hook functions + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" +#include "pcm_generic.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_hooks = ""; +#endif + +#ifndef DOC_HIDDEN +struct _snd_pcm_hook { + snd_pcm_t *pcm; + snd_pcm_hook_func_t func; + void *private_data; + struct list_head list; +}; + +struct snd_pcm_hook_dllist { + void *dlobj; + struct list_head list; +}; + +typedef struct { + snd_pcm_generic_t gen; + struct list_head hooks[SND_PCM_HOOK_TYPE_LAST + 1]; + struct list_head dllist; +} snd_pcm_hooks_t; +#endif + +static int hook_add_dlobj(snd_pcm_t *pcm, void *dlobj) +{ + snd_pcm_hooks_t *h = pcm->private_data; + struct snd_pcm_hook_dllist *dl; + + dl = malloc(sizeof(*dl)); + if (!dl) + return -ENOMEM; + + dl->dlobj = dlobj; + list_add_tail(&dl->list, &h->dllist); + return 0; +} + +static void hook_remove_dlobj(struct snd_pcm_hook_dllist *dl) +{ + list_del(&dl->list); + snd_dlclose(dl->dlobj); + free(dl); +} + +static int snd_pcm_hooks_close(snd_pcm_t *pcm) +{ + snd_pcm_hooks_t *h = pcm->private_data; + struct list_head *pos, *next; + unsigned int k; + int res = 0, err; + + list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_CLOSE]) { + snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); + err = hook->func(hook); + if (err < 0) + res = err; + } + for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) { + struct list_head *hooks = &h->hooks[k]; + while (!list_empty(hooks)) { + snd_pcm_hook_t *hook; + pos = hooks->next; + hook = list_entry(pos, snd_pcm_hook_t, list); + snd_pcm_hook_remove(hook); + } + } + while (!list_empty(&h->dllist)) { + pos = h->dllist.next; + hook_remove_dlobj(list_entry(pos, struct snd_pcm_hook_dllist, list)); + } + err = snd_pcm_generic_close(pcm); + if (err < 0) + res = err; + return res; +} + +static int snd_pcm_hooks_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_hooks_t *h = pcm->private_data; + struct list_head *pos, *next; + int err = snd_pcm_generic_hw_params(pcm, params); + if (err < 0) + return err; + list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_PARAMS]) { + snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); + err = hook->func(hook); + if (err < 0) + return err; + } + return 0; +} + +static int snd_pcm_hooks_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_hooks_t *h = pcm->private_data; + struct list_head *pos, *next; + int err = snd_pcm_generic_hw_free(pcm); + if (err < 0) + return err; + list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_FREE]) { + snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); + err = hook->func(hook); + if (err < 0) + return err; + } + return 0; +} + +static void snd_pcm_hooks_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_hooks_t *h = pcm->private_data; + snd_output_printf(out, "Hooks PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(h->gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_hooks_ops = { + .close = snd_pcm_hooks_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_generic_hw_refine, + .hw_params = snd_pcm_hooks_hw_params, + .hw_free = snd_pcm_hooks_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_hooks_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { + .status = snd_pcm_generic_status, + .state = snd_pcm_generic_state, + .hwsync = snd_pcm_generic_hwsync, + .delay = snd_pcm_generic_delay, + .prepare = snd_pcm_generic_prepare, + .reset = snd_pcm_generic_reset, + .start = snd_pcm_generic_start, + .drop = snd_pcm_generic_drop, + .drain = snd_pcm_generic_drain, + .pause = snd_pcm_generic_pause, + .rewindable = snd_pcm_generic_rewindable, + .rewind = snd_pcm_generic_rewind, + .forwardable = snd_pcm_generic_forwardable, + .forward = snd_pcm_generic_forward, + .resume = snd_pcm_generic_resume, + .link = snd_pcm_generic_link, + .link_slaves = snd_pcm_generic_link_slaves, + .unlink = snd_pcm_generic_unlink, + .writei = snd_pcm_generic_writei, + .writen = snd_pcm_generic_writen, + .readi = snd_pcm_generic_readi, + .readn = snd_pcm_generic_readn, + .avail_update = snd_pcm_generic_avail_update, + .mmap_commit = snd_pcm_generic_mmap_commit, + .htimestamp = snd_pcm_generic_htimestamp, + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_generic_poll_revents, +}; + +/** + * \brief Creates a new hooks PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param slave Slave PCM + * \param close_slave If set, slave PCM handle is closed when hooks PCM is closed + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_hooks_t *h; + unsigned int k; + int err; + assert(pcmp && slave); + h = calloc(1, sizeof(snd_pcm_hooks_t)); + if (!h) + return -ENOMEM; + h->gen.slave = slave; + h->gen.close_slave = close_slave; + for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) { + INIT_LIST_HEAD(&h->hooks[k]); + } + INIT_LIST_HEAD(&h->dllist); + err = snd_pcm_new(&pcm, SND_PCM_TYPE_HOOKS, name, slave->stream, slave->mode); + if (err < 0) { + free(h); + return err; + } + pcm->ops = &snd_pcm_hooks_ops; + pcm->fast_ops = &snd_pcm_hooks_fast_ops; + pcm->private_data = h; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; + pcm->monotonic = slave->monotonic; + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_hooks Plugin: hooks + +This plugin is used to call some 'hook' function when this plugin is opened, +modified or closed. +Typically, it is used to change control values for a certain state +specially for the PCM (see the example below). + +\code +# Hook arguments definition +hook_args.NAME { + ... # Arbitrary arguments +} + +# PCM hook type +pcm_hook_type.NAME { + [lib STR] # Library file (default libasound.so) + [install STR] # Install function (default _snd_pcm_hook_NAME_install) +} + +# PCM hook definition +pcm_hook.NAME { + type STR # PCM Hook type (see pcm_hook_type) + [args STR] # Arguments for install function (see hook_args) + # or + [args { }] # Arguments for install function +} + +# PCM hook plugin +pcm.NAME { + type hooks # PCM with hooks + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + hooks { + ID STR # Hook name (see pcm_hook) + # or + ID { } # Hook definition (see pcm_hook) + } +} +\endcode + +Example: + +\code + hooks.0 { + type ctl_elems + hook_args [ + { + name "Wave Surround Playback Volume" + preserve true + lock true + optional true + value [ 0 0 ] + } + { + name "EMU10K1 PCM Send Volume" + index { @func private_pcm_subdevice } + lock true + value [ 0 0 0 0 0 0 255 0 0 0 0 255 ] + } + ] + } +\endcode +Here, the controls "Wave Surround Playback Volume" and "EMU10K1 PCM Send Volume" +are set to the given values when this pcm is accessed. Since these controls +take multi-dimensional values, the value field is written as +an array. +When preserve is true, the old values are saved and restored +when the pcm is closed. The lock means that the control is +locked during this pcm is opened, and cannot be changed by others. +When optional is set, no error is returned but ignored +even if the specified control doesn't exist. + +\subsection pcm_plugins_hooks_funcref Function reference + +
    +
  • The function ctl_elems - _snd_pcm_hook_ctl_elems_install() - installs + CTL settings described by given configuration. +
  • snd_pcm_hooks_open() +
  • _snd_pcm_hooks_open() +
+ +*/ + +static int snd_pcm_hook_add_conf(snd_pcm_t *pcm, snd_config_t *root, snd_config_t *conf) +{ + int err; + char buf[256]; + const char *str, *id; + const char *lib = NULL, *install = NULL; + snd_config_t *type = NULL, *args = NULL; + snd_config_iterator_t i, next; + int (*install_func)(snd_pcm_t *pcm, snd_config_t *args) = NULL; + void *h = NULL; + + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid hook definition"); + return -EINVAL; + } + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) { + type = n; + continue; + } + if (strcmp(id, "hook_args") == 0) { + args = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!type) { + SNDERR("type is not defined"); + return -EINVAL; + } + err = snd_config_get_id(type, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(type, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(root, "pcm_hook_type", str, &type); + if (err >= 0) { + if (snd_config_get_type(type) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for PCM type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "install") == 0) { + err = snd_config_get_string(n, &install); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!install) { + install = buf; + snprintf(buf, sizeof(buf), "_snd_pcm_hook_%s_install", str); + } + h = snd_dlopen(lib, RTLD_NOW); + install_func = h ? snd_dlsym(h, install, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION)) : NULL; + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", + lib ? lib : "[builtin]"); + err = -ENOENT; + } else if (!install_func) { + SNDERR("symbol %s is not defined inside %s", install, + lib ? lib : "[builtin]"); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type) + snd_config_delete(type); + if (err < 0) + return err; + + if (args && snd_config_get_string(args, &str) >= 0) { + err = snd_config_search_definition(root, "hook_args", str, &args); + if (err < 0) + SNDERR("unknown hook_args %s", str); + else + err = install_func(pcm, args); + snd_config_delete(args); + } else + err = install_func(pcm, args); + + if (err >= 0) + err = hook_add_dlobj(pcm, h); + + if (err < 0) { + snd_dlclose(h); + return err; + } + return 0; +} + +/** + * \brief Creates a new hooks PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with hooks PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *rpcm = NULL, *spcm; + snd_config_t *slave = NULL, *sconf; + snd_config_t *hooks = NULL; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "hooks") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + hooks = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_hooks_open(&rpcm, name, spcm, 1); + if (err < 0) { + snd_pcm_close(spcm); + return err; + } + if (!hooks) + goto _done; + snd_config_for_each(i, next, hooks) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *str; + if (snd_config_get_string(n, &str) >= 0) { + err = snd_config_search_definition(root, "pcm_hook", str, &n); + if (err < 0) { + SNDERR("unknown pcm_hook %s", str); + } else { + err = snd_pcm_hook_add_conf(rpcm, root, n); + snd_config_delete(n); + } + } else + err = snd_pcm_hook_add_conf(rpcm, root, n); + if (err < 0) { + snd_pcm_close(rpcm); + return err; + } + } + _done: + *pcmp = rpcm; + return 0; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_hooks_open, SND_PCM_DLSYM_VERSION); +#endif + +/** + * \brief Get PCM handle for a PCM hook + * \param hook PCM hook handle + * \return PCM handle + */ +snd_pcm_t *snd_pcm_hook_get_pcm(snd_pcm_hook_t *hook) +{ + assert(hook); + return hook->pcm; +} + +/** + * \brief Get callback function private data for a PCM hook + * \param hook PCM hook handle + * \return callback function private data + */ +void *snd_pcm_hook_get_private(snd_pcm_hook_t *hook) +{ + assert(hook); + return hook->private_data; +} + +/** + * \brief Set callback function private data for a PCM hook + * \param hook PCM hook handle + * \param private_data The private data value + */ +void snd_pcm_hook_set_private(snd_pcm_hook_t *hook, void *private_data) +{ + assert(hook); + hook->private_data = private_data; +} + +/** + * \brief Add a PCM hook at end of hooks chain + * \param hookp Returned PCM hook handle + * \param pcm PCM handle + * \param type PCM hook type + * \param func PCM hook callback function + * \param private_data PCM hook private data + * \return 0 on success otherwise a negative error code + * + * Warning: an hook callback function cannot remove an hook of the same type + * different from itself + */ +int snd_pcm_hook_add(snd_pcm_hook_t **hookp, snd_pcm_t *pcm, + snd_pcm_hook_type_t type, + snd_pcm_hook_func_t func, void *private_data) +{ + snd_pcm_hook_t *h; + snd_pcm_hooks_t *hooks; + assert(hookp && func); + assert(snd_pcm_type(pcm) == SND_PCM_TYPE_HOOKS); + h = calloc(1, sizeof(*h)); + if (!h) + return -ENOMEM; + h->pcm = pcm; + h->func = func; + h->private_data = private_data; + hooks = pcm->private_data; + list_add_tail(&h->list, &hooks->hooks[type]); + *hookp = h; + return 0; +} + +/** + * \brief Remove a PCM hook + * \param hook PCM hook handle + * \return 0 on success otherwise a negative error code + * + * Warning: an hook callback cannot remove an hook of the same type + * different from itself + */ +int snd_pcm_hook_remove(snd_pcm_hook_t *hook) +{ + assert(hook); + list_del(&hook->list); + free(hook); + return 0; +} + +/* + * + */ + +static int snd_pcm_hook_ctl_elems_hw_params(snd_pcm_hook_t *hook) +{ + snd_sctl_t *h = snd_pcm_hook_get_private(hook); + return snd_sctl_install(h); +} + +static int snd_pcm_hook_ctl_elems_hw_free(snd_pcm_hook_t *hook) +{ + snd_sctl_t *h = snd_pcm_hook_get_private(hook); + return snd_sctl_remove(h); +} + +static int snd_pcm_hook_ctl_elems_close(snd_pcm_hook_t *hook) +{ + snd_sctl_t *h = snd_pcm_hook_get_private(hook); + int err = snd_sctl_free(h); + snd_pcm_hook_set_private(hook, NULL); + return err; +} + +/** + * \brief Install CTL settings using hardware associated with PCM handle + * \param pcm PCM handle + * \param conf Configuration node with CTL settings + * \return zero on success otherwise a negative error code + */ +int _snd_pcm_hook_ctl_elems_install(snd_pcm_t *pcm, snd_config_t *conf) +{ + int err; + int card; + snd_pcm_info_t *info; + char ctl_name[16]; + snd_ctl_t *ctl; + snd_sctl_t *sctl = NULL; + snd_config_t *pcm_conf = NULL; + snd_pcm_hook_t *h_hw_params = NULL, *h_hw_free = NULL, *h_close = NULL; + assert(conf); + assert(snd_config_get_type(conf) == SND_CONFIG_TYPE_COMPOUND); + snd_pcm_info_alloca(&info); + err = snd_pcm_info(pcm, info); + if (err < 0) + return err; + card = snd_pcm_info_get_card(info); + if (card < 0) { + SNDERR("No card for this PCM"); + return -EINVAL; + } + sprintf(ctl_name, "hw:%d", card); + err = snd_ctl_open(&ctl, ctl_name, 0); + if (err < 0) { + SNDERR("Cannot open CTL %s", ctl_name); + return err; + } + err = snd_config_imake_pointer(&pcm_conf, "pcm_handle", pcm); + if (err < 0) + goto _err; + err = snd_sctl_build(&sctl, ctl, conf, pcm_conf, 0); + if (err < 0) + goto _err; + err = snd_pcm_hook_add(&h_hw_params, pcm, SND_PCM_HOOK_TYPE_HW_PARAMS, + snd_pcm_hook_ctl_elems_hw_params, sctl); + if (err < 0) + goto _err; + err = snd_pcm_hook_add(&h_hw_free, pcm, SND_PCM_HOOK_TYPE_HW_FREE, + snd_pcm_hook_ctl_elems_hw_free, sctl); + if (err < 0) + goto _err; + err = snd_pcm_hook_add(&h_close, pcm, SND_PCM_HOOK_TYPE_CLOSE, + snd_pcm_hook_ctl_elems_close, sctl); + if (err < 0) + goto _err; + snd_config_delete(pcm_conf); + return 0; + _err: + if (h_hw_params) + snd_pcm_hook_remove(h_hw_params); + if (h_hw_free) + snd_pcm_hook_remove(h_hw_free); + if (h_close) + snd_pcm_hook_remove(h_close); + if (sctl) + snd_sctl_free(sctl); + if (pcm_conf) + snd_config_delete(pcm_conf); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_hook_ctl_elems_install, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c new file mode 100644 index 0000000..9d243d5 --- /dev/null +++ b/src/pcm/pcm_hw.c @@ -0,0 +1,1570 @@ +/** + * \file pcm/pcm_hw.c + * \ingroup PCM_Plugins + * \brief PCM HW Plugin Interface + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2000-2001 + */ +/* + * PCM - Hardware + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_local.h" +#include "../control/control_local.h" +#include "../timer/timer_local.h" + +//#define DEBUG_RW /* use to debug readi/writei/readn/writen */ +//#define DEBUG_MMAP /* debug mmap_commit */ + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_hw = ""; +#endif + +#ifndef DOC_HIDDEN + +#ifndef F_SETSIG +#define F_SETSIG 10 +#endif + +/* + * Compatibility + */ + +struct sndrv_pcm_hw_params_old { + unsigned int flags; + unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - + SNDRV_PCM_HW_PARAM_ACCESS + 1]; + struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - + SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; + unsigned int rmask; + unsigned int cmask; + unsigned int info; + unsigned int msbits; + unsigned int rate_num; + unsigned int rate_den; + sndrv_pcm_uframes_t fifo_size; + unsigned char reserved[64]; +}; + +#define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old) +#define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old) + +static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params); +static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm); +static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops; +static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer; + +/* + * + */ + +typedef struct { + int version; + int fd; + int card, device, subdevice; + int sync_ptr_ioctl; + volatile struct sndrv_pcm_mmap_status * mmap_status; + struct sndrv_pcm_mmap_control *mmap_control; + struct sndrv_pcm_sync_ptr *sync_ptr; + snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t appl_ptr; + int period_event; + snd_timer_t *period_timer; + struct pollfd period_timer_pfd; + int period_timer_need_poll; + /* restricted parameters */ + snd_pcm_format_t format; + int rate; + int channels; +} snd_pcm_hw_t; + +#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip" +#define SNDRV_FILE_PCM_STREAM_CAPTURE ALSA_DEVICE_DIRECTORY "pcmC%iD%ic" +#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 9) + +/* update appl_ptr with driver */ +#define FAST_PCM_STATE(hw) \ + ((enum sndrv_pcm_state) (hw)->mmap_status->state) +#define FAST_PCM_TSTAMP(hw) \ + ((hw)->mmap_status->tstamp) + +struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm) +{ + struct timespec res; + snd_pcm_hw_t *hw = pcm->private_data; + res = FAST_PCM_TSTAMP(hw); + if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) + res.tv_nsec *= 1000L; + return res; +} +#endif /* DOC_HIDDEN */ + +static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) +{ + int err; + hw->sync_ptr->flags = flags; + err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr); + if (err < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); + return err; + } + return 0; +} + +static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) +{ + return hw->sync_ptr ? sync_ptr1(hw, flags) : 0; +} + +static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) +{ + if (hw->period_timer_need_poll) { + while (poll(&hw->period_timer_pfd, 1, 0) > 0) { + snd_timer_tread_t rbuf[4]; + snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf)); + } + } else { + snd_timer_tread_t rbuf[4]; + snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf)); + } + return 0; +} + +static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 2; +} + +static int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + snd_pcm_hw_t *hw = pcm->private_data; + + if (space < 2) + return -ENOMEM; + pfds[0].fd = hw->fd; + pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL; + pfds[1].fd = hw->period_timer_pfd.fd; + pfds[1].events = POLLIN | POLLERR | POLLNVAL; + return 2; +} + +static int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents) +{ + snd_pcm_hw_t *hw = pcm->private_data; + unsigned int events; + + if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd) + return -EINVAL; + events = pfds[0].revents; + if (pfds[1].revents & POLLIN) { + snd_pcm_hw_clear_timer_queue(hw); + events |= pcm->poll_events & ~(POLLERR|POLLNVAL); + } + *revents = events; + return 0; +} + +static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock) +{ + long flags; + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + + if ((flags = fcntl(fd, F_GETFL)) < 0) { + err = -errno; + SYSMSG("F_GETFL failed (%i)", err); + return err; + } + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) < 0) { + err = -errno; + SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err); + return err; + } + return 0; +} + +static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + long flags; + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + + if ((flags = fcntl(fd, F_GETFL)) < 0) { + err = -errno; + SYSMSG("F_GETFL failed (%i)", err); + return err; + } + if (sig >= 0) + flags |= O_ASYNC; + else + flags &= ~O_ASYNC; + if (fcntl(fd, F_SETFL, flags) < 0) { + err = -errno; + SYSMSG("F_SETFL for O_ASYNC failed (%i)", err); + return err; + } + if (sig < 0) + return 0; + if (fcntl(fd, F_SETSIG, (long)sig) < 0) { + err = -errno; + SYSMSG("F_SETSIG failed (%i)", err); + return err; + } + if (fcntl(fd, F_SETOWN, (long)pid) < 0) { + err = -errno; + SYSMSG("F_SETOWN failed (%i)", err); + return err; + } + return 0; +} + +static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err); + return err; + } + return 0; +} + +static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params) +{ + /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */ + if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version) + return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params); + return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params); +} + +static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + + if (hw->format != SND_PCM_FORMAT_UNKNOWN) { + err = _snd_pcm_hw_params_set_format(params, hw->format); + if (err < 0) + return err; + } + if (hw->channels > 0) { + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, + hw->channels, 0); + if (err < 0) + return err; + } + if (hw->rate > 0) { + err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE, + hw->rate, 0, hw->rate + 1, -1); + if (err < 0) + return err; + } + + if (hw_refine_call(hw, params) < 0) { + err = -errno; + // SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed"); + return err; + } + + if (params->info != ~0U) { + params->info &= ~0xf0000000; + params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0); + } + + return 0; +} + +static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params) +{ + /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */ + if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version) + return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params); + return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params); +} + +static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (hw_params_call(hw, params) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err); + return err; + } + params->info &= ~0xf0000000; + params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0); + err = sync_ptr(hw, 0); + if (err < 0) + return err; + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_CONTROL); + } + return 0; +} + +static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) +{ + if (hw->period_timer) { + snd_timer_close(hw->period_timer); + hw->period_timer = NULL; + } +} + +static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable) +{ + snd_pcm_hw_t *hw = pcm->private_data; + snd_timer_params_t *params; + unsigned int suspend, resume; + int err; + + if (enable) { + snd_timer_params_alloca(¶ms); + err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, (hw->subdevice << 1) | (pcm->stream & 1), SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD); + if (err < 0) { + err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, (hw->subdevice << 1) | (pcm->stream & 1), SND_TIMER_OPEN_NONBLOCK); + return err; + } + if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) { + snd_pcm_hw_close_timer(hw); + return -EINVAL; + } + hw->period_timer_pfd.events = POLLIN; + hw->period_timer_pfd.revents = 0; + snd_timer_poll_descriptors(hw->period_timer, &hw->period_timer_pfd, 1); + hw->period_timer_need_poll = 0; + suspend = 1<period_timer_pfd.fd, SNDRV_TIMER_IOCTL_PVERSION, &ver); + /* In older versions, check via poll before read() is needed + * because of the confliction between TIMER_START and + * FIONBIO ioctls. + */ + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4)) + hw->period_timer_need_poll = 1; + /* + * In older versions, timer uses pause events instead + * suspend/resume events. + */ + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) { + suspend = 1<period_timer, params); + if (err < 0) { + snd_pcm_hw_close_timer(hw); + return err; + } + err = snd_timer_start(hw->period_timer); + if (err < 0) { + snd_pcm_hw_close_timer(hw); + return err; + } + pcm->fast_ops = &snd_pcm_hw_fast_ops_timer; + } else { + snd_pcm_hw_close_timer(hw); + pcm->fast_ops = &snd_pcm_hw_fast_ops; + hw->period_event = 0; + } + return 0; +} + +static int snd_pcm_hw_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + snd_pcm_hw_change_timer(pcm, 0); + if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed (%i)", err); + return err; + } + return 0; +} + +static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + int old_period_event = params->period_event; + params->period_event = 0; + if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode && + params->period_step == pcm->period_step && + params->start_threshold == pcm->start_threshold && + params->stop_threshold == pcm->stop_threshold && + params->silence_threshold == pcm->silence_threshold && + params->silence_size == pcm->silence_size && + old_period_event == hw->period_event) { + hw->mmap_control->avail_min = params->avail_min; + return sync_ptr(hw, 0); + } + if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); + return err; + } + params->period_event = old_period_event; + hw->mmap_control->avail_min = params->avail_min; + if (hw->period_event != old_period_event) { + err = snd_pcm_hw_change_timer(pcm, old_period_event); + if (err < 0) + return err; + hw->period_event = old_period_event; + } + return 0; +} + +static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) +{ + snd_pcm_hw_t *hw = pcm->private_data; + struct sndrv_pcm_channel_info i; + int fd = hw->fd, err; + i.channel = info->channel; + if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err); + return err; + } + info->channel = i.channel; + info->addr = 0; + info->first = i.first; + info->step = i.step; + info->type = SND_PCM_AREA_MMAP; + info->u.mmap.fd = fd; + info->u.mmap.offset = i.offset; + return 0; +} + +static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err); + return err; + } + if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) { + status->tstamp.tv_nsec *= 1000L; + status->trigger_tstamp.tv_nsec *= 1000L; + } + return 0; +} + +static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err = sync_ptr(hw, 0); + if (err < 0) + return err; + return (snd_pcm_state_t) hw->mmap_status->state; +} + +static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err); + return err; + } + return 0; +} + +static int snd_pcm_hw_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) { + if (hw->sync_ptr) { + err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); + if (err < 0) + return err; + } else { + if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err); + return err; + } + } + } else { + snd_pcm_sframes_t delay; + int err = snd_pcm_hw_delay(pcm, &delay); + if (err < 0) { + switch (FAST_PCM_STATE(hw)) { + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_SUSPENDED: + return 0; + default: + return err; + } + } + } + return 0; +} + +static int snd_pcm_hw_prepare(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err); + return err; + } + return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); +} + +static int snd_pcm_hw_reset(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err); + return err; + } + return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); +} + +static int snd_pcm_hw_start(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; +#if 0 + assert(pcm->stream != SND_PCM_STREAM_PLAYBACK || + snd_pcm_mmap_playback_hw_avail(pcm) > 0); +#endif + sync_ptr(hw, 0); + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err); +#if 0 + if (err == -EBADFD) + SNDERR("PCM state = %s", snd_pcm_state_name(snd_pcm_hw_state(pcm))); +#endif + return err; + } + return 0; +} + +static int snd_pcm_hw_drop(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err); + return err; + } else { + } + return 0; +} + +static int snd_pcm_hw_drain(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err); + return err; + } + return 0; +} + +static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err); + return err; + } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_hw_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err); + return err; + } + err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); + if (err < 0) + return err; + return frames; +} + +static snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (SNDRV_PROTOCOL_VERSION(2, 0, 4) <= hw->version) { + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_FORWARD, &frames) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err); + return err; + } + err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); + if (err < 0) + return err; + return frames; + } else { + snd_pcm_sframes_t avail; + + err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); + if (err < 0) + return err; + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_PAUSED: + case SNDRV_PCM_STATE_PREPARED: + break; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } + avail = snd_pcm_mmap_avail(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); + err = sync_ptr(hw, 0); + if (err < 0) + return err; + return frames; + } +} + +static int snd_pcm_hw_resume(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err); + return err; + } + return 0; +} + +static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + snd_pcm_hw_t *hw1 = pcm1->private_data; + snd_pcm_hw_t *hw2 = pcm2->private_data; + if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) { + SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno); + return -errno; + } + return 0; +} + +static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master) +{ + if (master->type != SND_PCM_TYPE_HW) { + SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type); + return -EINVAL; + } + return hw_link(master, pcm); +} + +static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + if (pcm2->type != SND_PCM_TYPE_HW) { + if (pcm2->fast_ops->link_slaves) + return pcm2->fast_ops->link_slaves(pcm2, pcm1); + return -ENOSYS; + } + return hw_link(pcm1, pcm2); + } + +static int snd_pcm_hw_unlink(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_UNLINK) < 0) { + SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno); + return -errno; + } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + int err; + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd; + struct sndrv_xferi xferi; + xferi.buf = (char*) buffer; + xferi.frames = size; + xferi.result = 0; /* make valgrind happy */ + err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi); + err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; +#ifdef DEBUG_RW + fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err); +#endif + if (err < 0) + return snd_pcm_check_error(pcm, err); + return xferi.result; +} + +static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + int err; + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd; + struct sndrv_xfern xfern; + memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ + xfern.bufs = bufs; + xfern.frames = size; + err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern); + err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; +#ifdef DEBUG_RW + fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err); +#endif + if (err < 0) + return snd_pcm_check_error(pcm, err); + return xfern.result; +} + +static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + int err; + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd; + struct sndrv_xferi xferi; + xferi.buf = buffer; + xferi.frames = size; + xferi.result = 0; /* make valgrind happy */ + err = ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi); + err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; +#ifdef DEBUG_RW + fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err); +#endif + if (err < 0) + return snd_pcm_check_error(pcm, err); + return xferi.result; +} + +static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + int err; + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd; + struct sndrv_xfern xfern; + memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ + xfern.bufs = bufs; + xfern.frames = size; + err = ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern); + err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; +#ifdef DEBUG_RW + fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err); +#endif + if (err < 0) + return snd_pcm_check_error(pcm, err); + return xfern.result; +} + +static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + struct sndrv_pcm_sync_ptr sync_ptr; + void *ptr; + int err; + ptr = MAP_FAILED; + if (hw->sync_ptr_ioctl == 0) + ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_status)), + PROT_READ, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + if (ptr == MAP_FAILED || ptr == NULL) { + memset(&sync_ptr, 0, sizeof(sync_ptr)); + sync_ptr.c.control.appl_ptr = 0; + sync_ptr.c.control.avail_min = 1; + err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, &sync_ptr); + if (err < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); + return err; + } + hw->sync_ptr = calloc(1, sizeof(struct sndrv_pcm_sync_ptr)); + if (hw->sync_ptr == NULL) + return -ENOMEM; + hw->mmap_status = &hw->sync_ptr->s.status; + hw->mmap_control = &hw->sync_ptr->c.control; + hw->sync_ptr_ioctl = 1; + } else { + hw->mmap_status = ptr; + } + snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct sndrv_pcm_mmap_status, hw_ptr)); + return 0; +} + +static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + void *ptr; + int err; + if (hw->sync_ptr == NULL) { + ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_control)), + PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (ptr == MAP_FAILED || ptr == NULL) { + err = -errno; + SYSMSG("control mmap failed (%i)", err); + return err; + } + hw->mmap_control = ptr; + } else { + hw->mmap_control->avail_min = 1; + } + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + return 0; +} + +static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (hw->sync_ptr_ioctl) { + free(hw->sync_ptr); + hw->sync_ptr = NULL; + } else { + if (munmap((void*)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) { + err = -errno; + SYSMSG("status munmap failed (%i)", err); + return err; + } + } + return 0; +} + +static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err; + if (hw->sync_ptr_ioctl) { + free(hw->sync_ptr); + hw->sync_ptr = NULL; + } else { + if (munmap(hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) { + err = -errno; + SYSMSG("control munmap failed (%i)", err); + return err; + } + } + return 0; +} + +static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_hw_close(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + int err = 0; + if (close(hw->fd)) { + err = -errno; + SYSMSG("close failed (%i)\n", err); + } + snd_pcm_hw_munmap_status(pcm); + snd_pcm_hw_munmap_control(pcm); + free(hw); + return err; +} + +static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_hw_t *hw = pcm->private_data; + + snd_pcm_mmap_appl_forward(pcm, size); + sync_ptr(hw, 0); +#ifdef DEBUG_MMAP + fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size); +#endif + return size; +} + +static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + snd_pcm_uframes_t avail; + + sync_ptr(hw, 0); + avail = snd_pcm_mmap_avail(pcm); + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_RUNNING: + if (avail >= pcm->stop_threshold) { + /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */ + if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) { + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_XRUN) < 0) + return -errno; + } + /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */ + return -EPIPE; + } + break; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + break; + } + return avail; +} + +static int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_sframes_t avail1; + int ok = 0; + + /* unfortunately, loop is necessary to ensure valid timestamp */ + while (1) { + avail1 = snd_pcm_hw_avail_update(pcm); + if (avail1 < 0) + return avail1; + if (ok && (snd_pcm_uframes_t)avail1 == *avail) + break; + *avail = avail1; + *tstamp = snd_pcm_hw_fast_tstamp(pcm); + ok = 1; + } + return 0; +} + +static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_hw_t *hw = pcm->private_data; + char *name; + int err = snd_card_get_name(hw->card, &name); + if (err < 0) { + SNDERR("cannot get card name"); + return; + } + snd_output_printf(out, "Hardware PCM card %d '%s' device %d subdevice %d\n", + hw->card, name, hw->device, hw->subdevice); + free(name); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + snd_output_printf(out, " appl_ptr : %li\n", hw->mmap_control->appl_ptr); + snd_output_printf(out, " hw_ptr : %li\n", hw->mmap_status->hw_ptr); + } +} + +static const snd_pcm_ops_t snd_pcm_hw_ops = { + .close = snd_pcm_hw_close, + .info = snd_pcm_hw_info, + .hw_refine = snd_pcm_hw_hw_refine, + .hw_params = snd_pcm_hw_hw_params, + .hw_free = snd_pcm_hw_hw_free, + .sw_params = snd_pcm_hw_sw_params, + .channel_info = snd_pcm_hw_channel_info, + .dump = snd_pcm_hw_dump, + .nonblock = snd_pcm_hw_nonblock, + .async = snd_pcm_hw_async, + .mmap = snd_pcm_hw_mmap, + .munmap = snd_pcm_hw_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { + .status = snd_pcm_hw_status, + .state = snd_pcm_hw_state, + .hwsync = snd_pcm_hw_hwsync, + .delay = snd_pcm_hw_delay, + .prepare = snd_pcm_hw_prepare, + .reset = snd_pcm_hw_reset, + .start = snd_pcm_hw_start, + .drop = snd_pcm_hw_drop, + .drain = snd_pcm_hw_drain, + .pause = snd_pcm_hw_pause, + .rewindable = snd_pcm_hw_rewindable, + .rewind = snd_pcm_hw_rewind, + .forwardable = snd_pcm_hw_forwardable, + .forward = snd_pcm_hw_forward, + .resume = snd_pcm_hw_resume, + .link = snd_pcm_hw_link, + .link_slaves = snd_pcm_hw_link_slaves, + .unlink = snd_pcm_hw_unlink, + .writei = snd_pcm_hw_writei, + .writen = snd_pcm_hw_writen, + .readi = snd_pcm_hw_readi, + .readn = snd_pcm_hw_readn, + .avail_update = snd_pcm_hw_avail_update, + .mmap_commit = snd_pcm_hw_mmap_commit, + .htimestamp = snd_pcm_hw_htimestamp, + .poll_descriptors = NULL, + .poll_descriptors_count = NULL, + .poll_revents = NULL, +}; + +static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = { + .status = snd_pcm_hw_status, + .state = snd_pcm_hw_state, + .hwsync = snd_pcm_hw_hwsync, + .delay = snd_pcm_hw_delay, + .prepare = snd_pcm_hw_prepare, + .reset = snd_pcm_hw_reset, + .start = snd_pcm_hw_start, + .drop = snd_pcm_hw_drop, + .drain = snd_pcm_hw_drain, + .pause = snd_pcm_hw_pause, + .rewindable = snd_pcm_hw_rewindable, + .rewind = snd_pcm_hw_rewind, + .forwardable = snd_pcm_hw_forwardable, + .forward = snd_pcm_hw_forward, + .resume = snd_pcm_hw_resume, + .link = snd_pcm_hw_link, + .link_slaves = snd_pcm_hw_link_slaves, + .unlink = snd_pcm_hw_unlink, + .writei = snd_pcm_hw_writei, + .writen = snd_pcm_hw_writen, + .readi = snd_pcm_hw_readi, + .readn = snd_pcm_hw_readn, + .avail_update = snd_pcm_hw_avail_update, + .mmap_commit = snd_pcm_hw_mmap_commit, + .htimestamp = snd_pcm_hw_htimestamp, + .poll_descriptors = snd_pcm_hw_poll_descriptors, + .poll_descriptors_count = snd_pcm_hw_poll_descriptors_count, + .poll_revents = snd_pcm_hw_poll_revents, +}; + +/** + * \brief Creates a new hw PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param fd File descriptor + * \param mmap_emulation Obsoleted parameter + * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + int fd, int mmap_emulation ATTRIBUTE_UNUSED, + int sync_ptr_ioctl) +{ + int ver, mode, monotonic = 0; + long fmode; + snd_pcm_t *pcm = NULL; + snd_pcm_hw_t *hw = NULL; + snd_pcm_info_t info; + int ret; + + assert(pcmp); + + memset(&info, 0, sizeof(info)); + if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) { + ret = -errno; + SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret); + close(fd); + return ret; + + } + + if ((fmode = fcntl(fd, F_GETFL)) < 0) { + ret = -errno; + close(fd); + return ret; + } + mode = 0; + if (fmode & O_NONBLOCK) + mode |= SND_PCM_NONBLOCK; + if (fmode & O_ASYNC) + mode |= SND_PCM_ASYNC; + + if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) { + ret = -errno; + SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret); + close(fd); + return ret; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX)) + return -SND_ERROR_INCOMPATIBLE_VERSION; + +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) { + struct timespec timespec; + if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) { + int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; + if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) { + ret = -errno; + SNDMSG("TTSTAMP failed\n"); + return ret; + } + monotonic = 1; + } + } else +#endif + if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver) { + int on = 1; + if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) { + ret = -errno; + SNDMSG("TSTAMP failed\n"); + return ret; + } + } + + hw = calloc(1, sizeof(snd_pcm_hw_t)); + if (!hw) { + close(fd); + return -ENOMEM; + } + + hw->version = ver; + hw->card = info.card; + hw->device = info.device; + hw->subdevice = info.subdevice; + hw->fd = fd; + hw->sync_ptr_ioctl = sync_ptr_ioctl; + /* no restriction */ + hw->format = SND_PCM_FORMAT_UNKNOWN; + hw->rate = 0; + hw->channels = 0; + + ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode); + if (ret < 0) { + free(hw); + close(fd); + return ret; + } + + pcm->ops = &snd_pcm_hw_ops; + pcm->fast_ops = &snd_pcm_hw_fast_ops; + pcm->private_data = hw; + pcm->poll_fd = fd; + pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; + pcm->monotonic = monotonic; + + ret = snd_pcm_hw_mmap_status(pcm); + if (ret < 0) { + snd_pcm_close(pcm); + return ret; + } + ret = snd_pcm_hw_mmap_control(pcm); + if (ret < 0) { + snd_pcm_close(pcm); + return ret; + } + + *pcmp = pcm; + return 0; +} + +/** + * \brief Creates a new hw PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param card Number of card + * \param device Number of device + * \param subdevice Number of subdevice + * \param stream PCM Stream + * \param mode PCM Mode + * \param mmap_emulation Obsoleted parameter + * \param sync_ptr_ioctl Use SYNC_PTR ioctl rather than mmap for control structures + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, + int card, int device, int subdevice, + snd_pcm_stream_t stream, int mode, + int mmap_emulation ATTRIBUTE_UNUSED, + int sync_ptr_ioctl) +{ + char filename[sizeof(SNDRV_FILE_PCM_STREAM_PLAYBACK) + 20]; + const char *filefmt; + int ret = 0, fd = -1; + int attempt = 0; + snd_pcm_info_t info; + int fmode; + snd_ctl_t *ctl; + + assert(pcmp); + + if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0) + return ret; + + switch (stream) { + case SND_PCM_STREAM_PLAYBACK: + filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK; + break; + case SND_PCM_STREAM_CAPTURE: + filefmt = SNDRV_FILE_PCM_STREAM_CAPTURE; + break; + default: + SNDERR("invalid stream %d", stream); + return -EINVAL; + } + sprintf(filename, filefmt, card, device); + + __again: + if (attempt++ > 3) { + ret = -EBUSY; + goto _err; + } + ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice); + if (ret < 0) + goto _err; + fmode = O_RDWR; + if (mode & SND_PCM_NONBLOCK) + fmode |= O_NONBLOCK; + if (mode & SND_PCM_ASYNC) + fmode |= O_ASYNC; + if (mode & SND_PCM_APPEND) + fmode |= O_APPEND; + fd = snd_open_device(filename, fmode); + if (fd < 0) { + ret = -errno; + SYSMSG("open '%s' failed (%i)", filename, ret); + goto _err; + } + if (subdevice >= 0) { + memset(&info, 0, sizeof(info)); + if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) { + ret = -errno; + SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret); + goto _err; + } + if (info.subdevice != (unsigned int) subdevice) { + close(fd); + goto __again; + } + } + snd_ctl_close(ctl); + return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl); + _err: + snd_ctl_close(ctl); + return ret; +} + +/*! \page pcm_plugins + +\section pcm_plugins_hw Plugin: hw + +This plugin communicates directly with the ALSA kernel driver. It is a raw +communication without any conversions. The emulation of mmap access can be +optionally enabled, but expect worse latency in the case. + +The nonblock option specifies whether the device is opened in a non-blocking +manner. Note that the blocking behavior for read/write access won't be +changed by this option. This influences only on the blocking behavior at +opening the device. If you would like to keep the compatibility with the +older ALSA stuff, turn this option off. + +\code +pcm.name { + type hw # Kernel PCM + card INT/STR # Card name (string) or number (integer) + [device INT] # Device number (default 0) + [subdevice INT] # Subdevice number (default -1: first available) + [sync_ptr_ioctl BOOL] # Use SYNC_PTR ioctl rather than the direct mmap access for control structures + [nonblock BOOL] # Force non-blocking open mode + [format STR] # Restrict only to the given format + [channels INT] # Restrict only to the given channels + [rate INT] # Restrict only to the given rate +} +\endcode + +\subsection pcm_plugins_hw_funcref Function reference + +
    +
  • snd_pcm_hw_open() +
  • _snd_pcm_hw_open() +
+ +*/ + +/** + * \brief Creates a new hw PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with hw PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + long card = -1, device = 0, subdevice = -1; + const char *str; + int err, sync_ptr_ioctl = 0; + int rate = 0, channels = 0; + snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; + snd_config_t *n; + int nonblock = 1; /* non-block per default */ + snd_pcm_hw_t *hw; + + /* look for defaults.pcm.nonblock definition */ + if (snd_config_search(root, "defaults.pcm.nonblock", &n) >= 0) { + err = snd_config_get_bool(n); + if (err >= 0) + nonblock = err; + } + snd_config_for_each(i, next, conf) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + card = snd_card_get_index(str); + if (card < 0) { + SNDERR("Invalid value for %s", id); + return card; + } + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + continue; + } + if (strcmp(id, "subdevice") == 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + continue; + } + if (strcmp(id, "sync_ptr_ioctl") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + continue; + sync_ptr_ioctl = err; + continue; + } + if (strcmp(id, "nonblock") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + continue; + nonblock = err; + continue; + } + if (strcmp(id, "rate") == 0) { + long val; + err = snd_config_get_integer(n, &val); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + rate = val; + continue; + } + if (strcmp(id, "format") == 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("invalid type for %s", id); + return err; + } + format = snd_pcm_format_value(str); + continue; + } + if (strcmp(id, "channels") == 0) { + long val; + err = snd_config_get_integer(n, &val); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + channels = val; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (card < 0) { + SNDERR("card is not defined"); + return -EINVAL; + } + err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream, + mode | (nonblock ? SND_PCM_NONBLOCK : 0), + 0, sync_ptr_ioctl); + if (err < 0) + return err; + if (nonblock && ! (mode & SND_PCM_NONBLOCK)) { + /* revert to blocking mode for read/write access */ + snd_pcm_hw_nonblock(*pcmp, 0); + (*pcmp)->mode = mode; + } else + /* make sure the SND_PCM_NO_xxx flags don't get lost on the + * way */ + (*pcmp)->mode |= mode & (SND_PCM_NO_AUTO_RESAMPLE| + SND_PCM_NO_AUTO_CHANNELS| + SND_PCM_NO_AUTO_FORMAT| + SND_PCM_NO_SOFTVOL); + + hw = (*pcmp)->private_data; + if (format != SND_PCM_FORMAT_UNKNOWN) + hw->format = format; + if (channels > 0) + hw->channels = channels; + if (rate > 0) + hw->rate = rate; + + return 0; +} + +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION); +#endif + +/* + * To be removed helpers, but keep binary compatibility at the time + */ + +#ifndef DOC_HIDDEN +#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5)) +#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5)) +#endif + +static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, + struct sndrv_pcm_hw_params_old *oparams) +{ + unsigned int i; + + memset(params, 0, sizeof(*params)); + params->flags = oparams->flags; + for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) + params->masks[i].bits[0] = oparams->masks[i]; + memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); + params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); + params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); + params->info = oparams->info; + params->msbits = oparams->msbits; + params->rate_num = oparams->rate_num; + params->rate_den = oparams->rate_den; + params->fifo_size = oparams->fifo_size; +} + +static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams, + snd_pcm_hw_params_t *params, + unsigned int *cmask) +{ + unsigned int i, j; + + memset(oparams, 0, sizeof(*oparams)); + oparams->flags = params->flags; + for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) { + oparams->masks[i] = params->masks[i].bits[0]; + for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++) + if (params->masks[i].bits[j]) { + *cmask |= 1 << i; + break; + } + } + memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); + oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); + oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); + oparams->info = params->info; + oparams->msbits = params->msbits; + oparams->rate_num = params->rate_num; + oparams->rate_den = params->rate_den; + oparams->fifo_size = params->fifo_size; +} + +static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params) +{ + struct sndrv_pcm_hw_params_old oparams; + unsigned int cmask = 0; + int res; + + snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask); + res = ioctl(fd, cmd, &oparams); + snd_pcm_hw_convert_from_old_params(params, &oparams); + params->cmask |= cmask; + return res; +} diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c new file mode 100644 index 0000000..3d70ed0 --- /dev/null +++ b/src/pcm/pcm_iec958.c @@ -0,0 +1,679 @@ +/** + * \file pcm/pcm_iec958.c + * \ingroup PCM_Plugins + * \brief PCM IEC958 Subframe Conversion Plugin Interface + * \author Takashi Iwai + * \date 2004 + */ +/* + * PCM - IEC958 Subframe Conversion Plugin + * Copyright (c) 2004 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_iec958 = ""; +#endif + +/* + */ + +#ifndef DOC_HIDDEN + +typedef struct snd_pcm_iec958 snd_pcm_iec958_t; + +typedef void (*iec958_f)(snd_pcm_iec958_t *iec, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames); + +struct snd_pcm_iec958 { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + unsigned int getput_idx; + iec958_f func; + snd_pcm_format_t sformat; + snd_pcm_format_t format; + unsigned int counter; + unsigned char status[24]; + unsigned int byteswap; + unsigned char preamble[3]; /* B/M/W or Z/X/Y */ +}; + +enum { PREAMBLE_Z, PREAMBLE_X, PREAMBLE_Y }; + +#endif /* DOC_HIDDEN */ + +/* + * Determine parity for time slots 4 upto 30 + * to be sure that bit 4 upt 31 will carry + * an even number of ones and zeros. + */ +static unsigned int iec958_parity(unsigned int data) +{ + unsigned int parity; + int bit; + + data >>= 4; /* start from bit 4 */ + parity = 0; + for (bit = 4; bit <= 30; bit++) { + if (data & 1) + parity++; + data >>= 1; + } + return (parity & 1); +} + +/* + * Compose 32bit IEC958 subframe, two sub frames + * build one frame with two channels. + * + * bit 0-3 = preamble + * 4-7 = AUX (=0) + * 8-27 = data (12-27 for 16bit, 8-27 for 20bit, and 24bit without AUX) + * 28 = validity (0 for valid data, else 'in error') + * 29 = user data (0) + * 30 = channel status (24 bytes for 192 frames) + * 31 = parity + */ + +static inline u_int32_t iec958_subframe(snd_pcm_iec958_t *iec, u_int32_t data, int channel) +{ + unsigned int byte = iec->counter >> 3; + unsigned int mask = 1 << (iec->counter - (byte << 3)); + + /* bit 4-27 */ + data >>= 4; + data &= ~0xf; + + /* set IEC status bits (up to 192 bits) */ + if (iec->status[byte] & mask) + data |= 0x40000000; + + if (iec958_parity(data)) /* parity bit 4-30 */ + data |= 0x80000000; + + /* Preamble */ + if (channel) + data |= iec->preamble[PREAMBLE_Y]; /* odd sub frame, 'Y' */ + else if (! iec->counter) + data |= iec->preamble[PREAMBLE_Z]; /* Block start, 'Z' */ + else + data |= iec->preamble[PREAMBLE_X]; /* even sub frame, 'X' */ + + if (iec->byteswap) + data = bswap_32(data); + + return data; +} + +static inline int32_t iec958_to_s32(snd_pcm_iec958_t *iec, u_int32_t data) +{ + if (iec->byteswap) + data = bswap_32(data); + data &= ~0xf; + data <<= 4; + return (int32_t)data; +} + +#ifndef DOC_HIDDEN +static void snd_pcm_iec958_decode(snd_pcm_iec958_t *iec, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames) +{ +#define PUT32_LABELS +#include "plugin_ops.h" +#undef PUT32_LABELS + void *put = put32_labels[iec->getput_idx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { + const u_int32_t *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area) / sizeof(u_int32_t); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + int32_t sample = iec958_to_s32(iec, *src); + goto *put; +#define PUT32_END after +#include "plugin_ops.h" +#undef PUT32_END + after: + src += src_step; + dst += dst_step; + } + } +} + +static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames) +{ +#define GET32_LABELS +#include "plugin_ops.h" +#undef GET32_LABELS + void *get = get32_labels[iec->getput_idx]; + unsigned int channel; + int32_t sample = 0; + int counter = iec->counter; + for (channel = 0; channel < channels; ++channel) { + const char *src; + u_int32_t *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(u_int32_t); + frames1 = frames; + iec->counter = counter; + while (frames1-- > 0) { + goto *get; +#define GET32_END after +#include "plugin_ops.h" +#undef GET32_END + after: + sample = iec958_subframe(iec, sample, channel); + // fprintf(stderr, "%d:%08x\n", frames1, sample); + *dst = sample; + src += src_step; + dst += dst_step; + iec->counter++; + iec->counter %= 192; + } + } +} +#endif /* DOC_HIDDEN */ + +static int snd_pcm_iec958_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + if (iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_LE || + iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_BE) { + snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + } else { + snd_pcm_format_mask_t format_mask = { + { (1U << SND_PCM_FORMAT_IEC958_SUBFRAME_LE) | + (1U << SND_PCM_FORMAT_IEC958_SUBFRAME_BE) } + }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + } + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_iec958_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, iec->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + return 0; +} + +static int snd_pcm_iec958_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_iec958_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_iec958_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_iec958_hw_refine_cprepare, + snd_pcm_iec958_hw_refine_cchange, + snd_pcm_iec958_hw_refine_sprepare, + snd_pcm_iec958_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_iec958_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + snd_pcm_format_t format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_iec958_hw_refine_cchange, + snd_pcm_iec958_hw_refine_sprepare, + snd_pcm_iec958_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); + if (err < 0) + return err; + + iec->format = format; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_LE || + iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_BE) { + iec->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32); + iec->func = snd_pcm_iec958_encode; + iec->byteswap = iec->sformat != SND_PCM_FORMAT_IEC958_SUBFRAME; + } else { + iec->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, iec->sformat); + iec->func = snd_pcm_iec958_decode; + iec->byteswap = format != SND_PCM_FORMAT_IEC958_SUBFRAME; + } + } else { + if (iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_LE || + iec->sformat == SND_PCM_FORMAT_IEC958_SUBFRAME_BE) { + iec->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, format); + iec->func = snd_pcm_iec958_decode; + iec->byteswap = iec->sformat != SND_PCM_FORMAT_IEC958_SUBFRAME; + } else { + iec->getput_idx = snd_pcm_linear_get_index(iec->sformat, SND_PCM_FORMAT_S32); + iec->func = snd_pcm_iec958_encode; + iec->byteswap = format != SND_PCM_FORMAT_IEC958_SUBFRAME; + } + } + /* FIXME: needs to adjust status_bits according to the format + * and sample rate + */ + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_iec958_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + iec->func(iec, slave_areas, slave_offset, + areas, offset, + pcm->channels, size); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_iec958_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + iec->func(iec, areas, offset, + slave_areas, slave_offset, + pcm->channels, size); + *slave_sizep = size; + return size; +} + +static int snd_pcm_iec958_init(snd_pcm_t *pcm) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + iec->counter = 0; + return 0; +} + +static void snd_pcm_iec958_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_iec958_t *iec = pcm->private_data; + snd_output_printf(out, "IEC958 subframe conversion PCM (%s)\n", + snd_pcm_format_name(iec->sformat)); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(iec->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_iec958_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_iec958_hw_refine, + .hw_params = snd_pcm_iec958_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_iec958_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new IEC958 subframe conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \param status_bits The IEC958 status bits + * \param preamble_vals The preamble byte values + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, + snd_pcm_t *slave, int close_slave, + const unsigned char *status_bits, + const unsigned char *preamble_vals) +{ + snd_pcm_t *pcm; + snd_pcm_iec958_t *iec; + int err; + static const unsigned char default_status_bits[] = { + IEC958_AES0_CON_EMPHASIS_NONE, + IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER, + 0, + IEC958_AES3_CON_FS_48000 + }; + + assert(pcmp && slave); + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_LE && + sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_BE) + return -EINVAL; + iec = calloc(1, sizeof(snd_pcm_iec958_t)); + if (!iec) { + return -ENOMEM; + } + snd_pcm_plugin_init(&iec->plug); + iec->sformat = sformat; + iec->plug.read = snd_pcm_iec958_read_areas; + iec->plug.write = snd_pcm_iec958_write_areas; + iec->plug.init = snd_pcm_iec958_init; + iec->plug.undo_read = snd_pcm_plugin_undo_read_generic; + iec->plug.undo_write = snd_pcm_plugin_undo_write_generic; + iec->plug.gen.slave = slave; + iec->plug.gen.close_slave = close_slave; + + if (status_bits) + memcpy(iec->status, status_bits, sizeof(iec->status)); + else + memcpy(iec->status, default_status_bits, sizeof(default_status_bits)); + + memcpy(iec->preamble, preamble_vals, 3); + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_IEC958, name, slave->stream, slave->mode); + if (err < 0) { + free(iec); + return err; + } + pcm->ops = &snd_pcm_iec958_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = iec; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &iec->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &iec->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_iec958 Plugin: IEC958 + +This plugin converts 32bit IEC958 subframe samples to linear, or linear to +32bit IEC958 subframe samples. + +\code +pcm.name { + type iec958 # IEC958 subframe conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + [status status-bytes] # IEC958 status bits (given in byte array) + # IEC958 preamble bits definitions + # B/M/W or Z/X/Y, B = block start, M = even subframe, W = odd subframe + # As default, Z = 0x08, Y = 0x04, X = 0x02 + [preamble.z or preamble.b val] + [preamble.x or preamble.m val] + [preamble.y or preamble.w val] +} +\endcode + +\subsection pcm_plugins_iec958_funcref Function reference + +
    +
  • snd_pcm_iec958_open() +
  • _snd_pcm_iec958_open() +
+ +*/ + +/** + * \brief Creates a new IEC958 subframe conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_config_t *status = NULL, *preamble = NULL; + snd_pcm_format_t sformat; + unsigned char status_bits[24]; + unsigned char preamble_vals[3] = { + 0x08, 0x02, 0x04 /* Z, X, Y */ + }; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "status") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + status = n; + continue; + } + if (strcmp(id, "preamble") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + preamble = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + memset(status_bits, 0, sizeof(status_bits)); + if (status) { + snd_config_iterator_t i, inext; + int bytes = 0; + snd_config_for_each(i, inext, status) { + long val; + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) { + SNDERR("invalid IEC958 status bits"); + return -EINVAL; + } + err = snd_config_get_integer(n, &val); + if (err < 0) { + SNDERR("invalid IEC958 status bits"); + return err; + } + status_bits[bytes] = val; + bytes++; + if (bytes >= (int)sizeof(status_bits)) + break; + } + // fprintf(stderr, "STATUS bits: %02x %02x %02x %02x\n", status_bits[0], status_bits[1], status_bits[2], status_bits[3]); + } + if (preamble) { + snd_config_iterator_t i, inext; + snd_config_for_each(i, inext, preamble) { + long val; + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + int idx; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "b") == 0 || strcmp(id, "z") == 0) + idx = PREAMBLE_Z; + else if (strcmp(id, "m") == 0 || strcmp(id, "x") == 0) + idx = PREAMBLE_X; + else if (strcmp(id, "w") == 0 || strcmp(id, "y") == 0) + idx = PREAMBLE_Y; + else { + SNDERR("invalid IEC958 preamble type %s", id); + return -EINVAL; + } + err = snd_config_get_integer(n, &val); + if (err < 0) { + SNDERR("invalid IEC958 preamble value"); + return err; + } + preamble_vals[idx] = val; + } + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); + if (err < 0) + return err; + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_LE && + sformat != SND_PCM_FORMAT_IEC958_SUBFRAME_BE) { + snd_config_delete(sconf); + SNDERR("invalid slave format"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_iec958_open(pcmp, name, sformat, spcm, 1, + status ? status_bits : NULL, + preamble_vals); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_iec958_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c new file mode 100644 index 0000000..2aa7572 --- /dev/null +++ b/src/pcm/pcm_ioplug.c @@ -0,0 +1,1072 @@ +/** + * \file pcm/pcm_ioplug.c + * \ingroup Plugin_SDK + * \brief I/O Plugin SDK + * \author Takashi Iwai + * \date 2005 + */ +/* + * PCM - External I/O Plugin SDK + * Copyright (c) 2005 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" +#include "pcm_ioplug.h" +#include "pcm_ext_parm.h" +#include "pcm_generic.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_ioplug = ""; +#endif + +#ifndef DOC_HIDDEN + +/* hw_params */ +typedef struct snd_pcm_ioplug_priv { + snd_pcm_ioplug_t *data; + struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS]; + unsigned int last_hw; + snd_pcm_uframes_t avail_max; + snd_htimestamp_t trigger_tstamp; +} ioplug_priv_t; + +/* update the hw pointer */ +static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + snd_pcm_sframes_t hw; + + hw = io->data->callback->pointer(io->data); + if (hw >= 0) { + unsigned int delta; + if ((unsigned int)hw >= io->last_hw) + delta = hw - io->last_hw; + else + delta = pcm->buffer_size + hw - io->last_hw; + io->data->hw_ptr += delta; + io->last_hw = hw; + } else + io->data->state = SNDRV_PCM_STATE_XRUN; +} + +static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info) +{ + memset(info, 0, sizeof(*info)); + info->stream = pcm->stream; + info->card = -1; + if (pcm->name) { + strncpy((char *)info->id, pcm->name, sizeof(info->id)); + strncpy((char *)info->name, pcm->name, sizeof(info->name)); + strncpy((char *)info->subname, pcm->name, sizeof(info->subname)); + } + info->subdevices_count = 1; + return 0; +} + +static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) +{ + return snd_pcm_channel_info_shm(pcm, info, -1); +} + +static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + ioplug_priv_t *io = pcm->private_data; + + memset(status, 0, sizeof(*status)); + snd_pcm_ioplug_hw_ptr_update(pcm); + status->state = io->data->state; + status->trigger_tstamp = io->trigger_tstamp; + status->avail = snd_pcm_mmap_avail(pcm); + status->avail_max = io->avail_max; + return 0; +} + +static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + return io->data->state; +} + +static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_ioplug_hw_ptr_update(pcm); + return 0; +} + +static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->version >= 0x010001 && + io->data->callback->delay) + return io->data->callback->delay(io->data, delayp); + else { + snd_pcm_ioplug_hw_ptr_update(pcm); + *delayp = snd_pcm_mmap_hw_avail(pcm); + } + return 0; +} + +static int snd_pcm_ioplug_reset(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + io->data->appl_ptr = 0; + io->data->hw_ptr = 0; + io->last_hw = 0; + io->avail_max = 0; + return 0; +} + +static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + io->data->state = SND_PCM_STATE_PREPARED; + snd_pcm_ioplug_reset(pcm); + if (io->data->callback->prepare) + return io->data->callback->prepare(io->data); + return 0; +} + +static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = { + [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS, + [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, + [SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS, + [SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE, + [SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES, + [SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES, + [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS, +}; + +/* x = a * b */ +static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b) +{ + snd_interval_t t; + + snd_interval_mul(hw_param_interval(params, a), + hw_param_interval(params, b), &t); + return snd_interval_refine(hw_param_interval(params, x), &t); +} + +/* x = a / b */ +static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b) +{ + snd_interval_t t; + + snd_interval_div(hw_param_interval(params, a), + hw_param_interval(params, b), &t); + return snd_interval_refine(hw_param_interval(params, x), &t); +} + +/* x = a * b / k */ +static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k) +{ + snd_interval_t t; + + snd_interval_muldivk(hw_param_interval(params, a), + hw_param_interval(params, b), k, &t); + return snd_interval_refine(hw_param_interval(params, x), &t); +} + +/* x = a * k / b */ +static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b) +{ + snd_interval_t t; + + snd_interval_mulkdiv(hw_param_interval(params, a), k, + hw_param_interval(params, b), &t); + return snd_interval_refine(hw_param_interval(params, x), &t); +} + +#if 0 +static void dump_parm(snd_pcm_hw_params_t *params) +{ + snd_output_t *log; + snd_output_stdio_attach(&log, stderr, 0); + snd_pcm_hw_params_dump(params, log); + snd_output_close(log); +} +#endif + +/* refine *_TIME and *_SIZE, then update *_BYTES */ +static int refine_time_and_size(snd_pcm_hw_params_t *params, + int time, int size, int bytes) +{ + int err, change1 = 0; + + /* size = time * rate / 1000000 */ + err = rule_muldivk(params, size, time, + SND_PCM_HW_PARAM_RATE, 1000000); + if (err < 0) + return err; + change1 |= err; + + /* bytes = size * framebits / 8 */ + err = rule_muldivk(params, bytes, size, + SND_PCM_HW_PARAM_FRAME_BITS, 8); + if (err < 0) + return err; + change1 |= err; + return change1; +} + +/* refine *_TIME and *_SIZE from *_BYTES */ +static int refine_back_time_and_size(snd_pcm_hw_params_t *params, + int time, int size, int bytes) +{ + int err; + + /* size = bytes * 8 / framebits */ + err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS); + if (err < 0) + return err; + /* time = size * 1000000 / rate */ + err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE); + if (err < 0) + return err; + return 0; +} + + +static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int change = 0, change1, change2, err; + ioplug_priv_t *io = pcm->private_data; + struct snd_ext_parm *p; + unsigned int i; + + /* access, format */ + for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) { + err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]), + io->params, i); + if (err < 0) + return err; + change |= err; + } + /* channels, rate */ + for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) { + err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]), + io->params, i); + if (err < 0) + return err; + change |= err; + } + + if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) | + (1 << SND_PCM_HW_PARAM_FORMAT) | + (1 << SND_PCM_HW_PARAM_SUBFORMAT) | + (1 << SND_PCM_HW_PARAM_CHANNELS) | + (1 << SND_PCM_HW_PARAM_RATE))) { + err = snd_pcm_hw_refine_soft(pcm, params); + if (err < 0) + return err; + change |= err; + } + + change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, + SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_PERIOD_BYTES); + if (change1 < 0) + return change1; + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), + io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); + if (err < 0) + return err; + change1 |= err; + if (change1) { + change |= change1; + err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, + SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_PERIOD_BYTES); + if (err < 0) + return err; + } + + change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME, + SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_BUFFER_BYTES); + if (change1 < 0) + return change1; + change |= change1; + + do { + change2 = 0; + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES), + io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES); + if (err < 0) + return err; + change2 |= err; + /* periods = buffer_bytes / period_bytes */ + err = rule_div(params, SND_PCM_HW_PARAM_PERIODS, + SND_PCM_HW_PARAM_BUFFER_BYTES, + SND_PCM_HW_PARAM_PERIOD_BYTES); + if (err < 0) + return err; + change2 |= err; + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS), + io->params, SND_PCM_IOPLUG_HW_PERIODS); + if (err < 0) + return err; + change2 |= err; + /* buffer_bytes = periods * period_bytes */ + err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES, + SND_PCM_HW_PARAM_PERIOD_BYTES, + SND_PCM_HW_PARAM_PERIODS); + if (err < 0) + return err; + change2 |= err; + change1 |= change2; + } while (change2); + change |= change1; + + if (change1) { + err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME, + SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_BUFFER_BYTES); + if (err < 0) + return err; + } + + /* period_bytes = buffer_bytes / periods */ + err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES, + SND_PCM_HW_PARAM_BUFFER_BYTES, + SND_PCM_HW_PARAM_PERIODS); + if (err < 0) + return err; + if (err) { + /* update period_size and period_time */ + change |= err; + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), + io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); + if (err < 0) + return err; + err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, + SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_PERIOD_BYTES); + if (err < 0) + return err; + } + + params->info = SND_PCM_INFO_BLOCK_TRANSFER; + p = &io->params[SND_PCM_IOPLUG_HW_ACCESS]; + if (p->active) { + for (i = 0; i < p->num_list; i++) + switch (p->list[i]) { + case SND_PCM_ACCESS_MMAP_INTERLEAVED: + case SND_PCM_ACCESS_RW_INTERLEAVED: + params->info |= SND_PCM_INFO_INTERLEAVED; + break; + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: + case SND_PCM_ACCESS_RW_NONINTERLEAVED: + params->info |= SND_PCM_INFO_NONINTERLEAVED; + break; + } + } + if (io->data->callback->pause) + params->info |= SND_PCM_INFO_PAUSE; + if (io->data->callback->resume) + params->info |= SND_PCM_INFO_RESUME; + +#if 0 + fprintf(stderr, "XXX\n"); + dump_parm(params); +#endif + return change; +} + +static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + ioplug_priv_t *io = pcm->private_data; + int err; + + INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access); + INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format); + INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels); + INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0); + INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0); + INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size); + if (io->data->callback->hw_params) { + err = io->data->callback->hw_params(io->data, params); + if (err < 0) + return err; + INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access); + INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format); + INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels); + INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0); + INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0); + INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size); + } + return 0; +} + +static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->hw_free) + return io->data->callback->hw_free(io->data); + return 0; +} + +static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->sw_params) + return io->data->callback->sw_params(io->data, params); + return 0; +} + + +static int snd_pcm_ioplug_start(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + int err; + + if (io->data->state != SND_PCM_STATE_PREPARED) + return -EBADFD; + + err = io->data->callback->start(io->data); + if (err < 0) + return err; + + gettimestamp(&io->trigger_tstamp, pcm->monotonic); + io->data->state = SND_PCM_STATE_RUNNING; + + return 0; +} + +static int snd_pcm_ioplug_drop(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->state == SND_PCM_STATE_OPEN) + return -EBADFD; + + io->data->callback->stop(io->data); + + gettimestamp(&io->trigger_tstamp, pcm->monotonic); + io->data->state = SND_PCM_STATE_SETUP; + + return 0; +} + +static int snd_pcm_ioplug_drain(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->state == SND_PCM_STATE_OPEN) + return -EBADFD; + if (io->data->callback->drain) + io->data->callback->drain(io->data); + return snd_pcm_ioplug_drop(pcm); +} + +static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable) +{ + ioplug_priv_t *io = pcm->private_data; + static const snd_pcm_state_t states[2] = { + SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED + }; + int prev, err; + + prev = !enable; + enable = !prev; + if (io->data->state != states[prev]) + return -EBADFD; + if (io->data->callback->pause) { + err = io->data->callback->pause(io->data, enable); + if (err < 0) + return err; + } + io->data->state = states[enable]; + return 0; +} + +static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_hw_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_mmap_appl_backward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + +static int snd_pcm_ioplug_resume(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->resume) + io->data->callback->resume(io->data); + return 0; +} + +static snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + ioplug_priv_t *io = pcm->private_data; + snd_pcm_sframes_t result; + + if (! size) + return 0; + if (io->data->callback->transfer) + result = io->data->callback->transfer(io->data, areas, offset, size); + else + result = size; + if (result > 0) + snd_pcm_mmap_appl_forward(pcm, result); + return result; +} + +static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + if (pcm->mmap_rw) + return snd_pcm_mmap_writei(pcm, buffer, size); + else { + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_buf(pcm, areas, (void*)buffer); + return snd_pcm_write_areas(pcm, areas, 0, size, + ioplug_priv_transfer_areas); + } +} + +static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + if (pcm->mmap_rw) + return snd_pcm_mmap_writen(pcm, bufs, size); + else { + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_bufs(pcm, areas, bufs); + return snd_pcm_write_areas(pcm, areas, 0, size, + ioplug_priv_transfer_areas); + } +} + +static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + if (pcm->mmap_rw) + return snd_pcm_mmap_readi(pcm, buffer, size); + else { + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_buf(pcm, areas, buffer); + return snd_pcm_read_areas(pcm, areas, 0, size, + ioplug_priv_transfer_areas); + } +} + +static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + if (pcm->mmap_rw) + return snd_pcm_mmap_readn(pcm, bufs, size); + else { + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_bufs(pcm, areas, bufs); + return snd_pcm_read_areas(pcm, areas, 0, size, + ioplug_priv_transfer_areas); + } +} + +static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + if (pcm->stream == SND_PCM_STREAM_PLAYBACK && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t ofs, frames = size; + + snd_pcm_mmap_begin(pcm, &areas, &ofs, &frames); + if (ofs != offset) + return -EIO; + return ioplug_priv_transfer_areas(pcm, areas, offset, frames); + } + + snd_pcm_mmap_appl_forward(pcm, size); + return size; +} + +static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + snd_pcm_uframes_t avail; + + snd_pcm_ioplug_hw_ptr_update(pcm); + if (io->data->state == SNDRV_PCM_STATE_XRUN) + return -EPIPE; + if (pcm->stream == SND_PCM_STREAM_CAPTURE && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { + if (io->data->callback->transfer) { + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t offset, size = UINT_MAX; + snd_pcm_sframes_t result; + + snd_pcm_mmap_begin(pcm, &areas, &offset, &size); + result = io->data->callback->transfer(io->data, areas, offset, size); + if (result < 0) + return result; + } + } + avail = snd_pcm_mmap_avail(pcm); + if (avail > io->avail_max) + io->avail_max = avail; + return (snd_pcm_sframes_t)avail; +} + +static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock) +{ + ioplug_priv_t *io = pcm->private_data; + + io->data->nonblock = nonblock; + return 0; +} + +static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->poll_descriptors_count) + return io->data->callback->poll_descriptors_count(io->data); + else + return 1; +} + +static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->poll_descriptors) + return io->data->callback->poll_descriptors(io->data, pfds, space); + if (pcm->poll_fd < 0) + return -EIO; + if (space >= 1 && pfds) { + pfds->fd = pcm->poll_fd; + pfds->events = pcm->poll_events | POLLERR | POLLNVAL; + } else { + return 0; + } + return 1; +} + +static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->poll_revents) + return io->data->callback->poll_revents(io->data, pfds, nfds, revents); + else + *revents = pfds->revents; + return 0; +} + +static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + int sig ATTRIBUTE_UNUSED, + pid_t pid ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->callback->dump) + io->data->callback->dump(io->data, out); + else { + if (io->data->name) + snd_output_printf(out, "%s\n", io->data->name); + else + snd_output_printf(out, "IO-PCM Plugin\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + } +} + +static void clear_io_params(ioplug_priv_t *io) +{ + int i; + for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++) + snd_ext_parm_clear(&io->params[i]); +} + +static int snd_pcm_ioplug_close(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + clear_io_params(io); + if (io->data->callback->close) + io->data->callback->close(io->data); + free(io); + + return 0; +} + +static const snd_pcm_ops_t snd_pcm_ioplug_ops = { + .close = snd_pcm_ioplug_close, + .nonblock = snd_pcm_ioplug_nonblock, + .async = snd_pcm_ioplug_async, + .info = snd_pcm_ioplug_info, + .hw_refine = snd_pcm_ioplug_hw_refine, + .hw_params = snd_pcm_ioplug_hw_params, + .hw_free = snd_pcm_ioplug_hw_free, + .sw_params = snd_pcm_ioplug_sw_params, + .channel_info = snd_pcm_ioplug_channel_info, + .dump = snd_pcm_ioplug_dump, + .mmap = snd_pcm_ioplug_mmap, + .munmap = snd_pcm_ioplug_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = { + .status = snd_pcm_ioplug_status, + .prepare = snd_pcm_ioplug_prepare, + .reset = snd_pcm_ioplug_reset, + .start = snd_pcm_ioplug_start, + .drop = snd_pcm_ioplug_drop, + .drain = snd_pcm_ioplug_drain, + .pause = snd_pcm_ioplug_pause, + .state = snd_pcm_ioplug_state, + .hwsync = snd_pcm_ioplug_hwsync, + .delay = snd_pcm_ioplug_delay, + .resume = snd_pcm_ioplug_resume, + .link = NULL, + .link_slaves = NULL, + .unlink = NULL, + .rewindable = snd_pcm_ioplug_rewindable, + .rewind = snd_pcm_ioplug_rewind, + .forwardable = snd_pcm_ioplug_forwardable, + .forward = snd_pcm_ioplug_forward, + .writei = snd_pcm_ioplug_writei, + .writen = snd_pcm_ioplug_writen, + .readi = snd_pcm_ioplug_readi, + .readn = snd_pcm_ioplug_readn, + .avail_update = snd_pcm_ioplug_avail_update, + .mmap_commit = snd_pcm_ioplug_mmap_commit, + .htimestamp = snd_pcm_generic_real_htimestamp, + .poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count, + .poll_descriptors = snd_pcm_ioplug_poll_descriptors, + .poll_revents = snd_pcm_ioplug_poll_revents, +}; + +#endif /* !DOC_HIDDEN */ + +/* + * Exported functions + */ + +/*! \page pcm_external_plugins PCM External Plugin SDK + +\section pcm_ioplug External Plugin: I/O Plugin + +The I/O-type plugin is a PCM plugin to work as the input or output terminal point, +i.e. as a user-space PCM driver. + +The new plugin is created via #snd_pcm_ioplug_create() function. +The first argument is a pointer of the pluging information. Some of +this struct must be initialized in prior to call +#snd_pcm_ioplug_create(). Then the function fills other fields in +return. The rest arguments, name, stream and mode, are usually +identical with the values passed from the ALSA plugin constructor. + +The following fields are mandatory: version, name, callback. +Otherfields are optional and should be initialized with zero. + +The constant #SND_PCM_IOPLUG_VERSION must be passed to the version +field for the version check in alsa-lib. A non-NULL ASCII string +has to be passed to the name field. The callback field contains the +table of callback functions for this plugin (defined as +#snd_pcm_ioplug_callback_t). + +flags field specifies the optional bit-flags. poll_fd and poll_events +specify the poll file descriptor and the corresponding poll events +(POLLIN, POLLOUT) for the plugin. If the plugin requires multiple +poll descriptors or poll descriptor(s) dynamically varying, set +poll_descriptors and poll_descriptors_count callbacks to the callback +table. Then the poll_fd and poll_events field are ignored. + +mmap_rw specifies whether the plugin behaves in the pseudo mmap mode. +When this value is set to 1, the plugin creates always a local buffer +and performs read/write calls using this buffer as if it's mmapped. +The address of local buffer can be obtained via +#snd_pcm_ioplug_mmap_areas() function. +When poll_fd, poll_events and mmap_rw fields are changed after +#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to +reflect the changes. + +The driver can set an arbitrary value (pointer) to private_data +field to refer its own data in the callbacks. + +The rest fields are filled by #snd_pcm_ioplug_create(). The pcm field +is the resultant PCM handle. The others are the current status of the +PCM. + +The callback functions in #snd_pcm_ioplug_callback_t define the real +behavior of the driver. +At least, start, stop and pointer callbacks must be given. Other +callbacks are optional. The start and stop callbacks are called when +the PCM stream is started and stopped, repsectively. The pointer +callback returns the current DMA position, which may be called at any +time. + +The transfer callback is called when any data transfer happens. It +receives the area array, offset and the size to transfer. The area +array contains the array of snd_pcm_channel_area_t with the elements +of number of channels. + +When the PCM is closed, close callback is called. If the driver +allocates any internal buffers, they should be released in this +callback. The hw_params and hw_free callbacks are called when +hw_params are set and reset, respectively. Note that they may be +called multiple times according to the application. Similarly, +sw_params callback is called when sw_params is set or changed. + +The prepare, drain, pause and resume callbacks are called when +#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and +#snd_pcm_resume() are called. The poll_descriptors_count and +poll_descriptors callbacks are used to return the multiple or dynamic +poll descriptors as mentioned above. The poll_revents callback is +used to modify poll events. If the driver needs to mangle the native +poll events to proper poll events for PCM, you can do it in this +callback. + +Finally, the dump callback is used to print the status of the plugin. + +The hw_params constraints can be defined via either +#snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list() +functions after calling #snd_pcm_ioplug_create(). +The former defines the minimal and maximal acceptable values for the +given hw_params parameter (SND_PCM_IOPLUG_HW_XXX). +This function can't be used for the format parameter. The latter +function specifies the available parameter values as the list. + +To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function. + +*/ + +/** + * \brief Create an ioplug instance + * \param ioplug the ioplug handle + * \param name name of PCM + * \param stream stream direction + * \param mode PCM open mode + * \return 0 if successful, or a negative error code + * + * Creates the ioplug instance. + * + * The callback is the mandatory field of ioplug handle. At least, start, stop and + * pointer callbacks must be set before calling this function. + * + */ +int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name, + snd_pcm_stream_t stream, int mode) +{ + ioplug_priv_t *io; + int err; + snd_pcm_t *pcm; + + assert(ioplug && ioplug->callback); + assert(ioplug->callback->start && + ioplug->callback->stop && + ioplug->callback->pointer); + + /* We support 1.0.0 to current */ + if (ioplug->version < 0x010000 || + ioplug->version > SND_PCM_IOPLUG_VERSION) { + SNDERR("ioplug: Plugin version mismatch\n"); + return -ENXIO; + } + + io = calloc(1, sizeof(*io)); + if (! io) + return -ENOMEM; + + io->data = ioplug; + ioplug->state = SND_PCM_STATE_OPEN; + ioplug->stream = stream; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode); + if (err < 0) { + free(io); + return err; + } + + ioplug->pcm = pcm; + pcm->ops = &snd_pcm_ioplug_ops; + pcm->fast_ops = &snd_pcm_ioplug_fast_ops; + pcm->private_data = io; + + snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0); + + snd_pcm_ioplug_reinit_status(ioplug); + + return 0; +} + +/** + * \brief Delete the ioplug instance + * \param ioplug the ioplug handle + * \return 0 if successful, or a negative error code + */ +int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug) +{ + return snd_pcm_close(ioplug->pcm); +} + + +/** + * \brief Reset ioplug parameters + * \param ioplug the ioplug handle + * + * Resets the all parameters for the given ioplug handle. + */ +void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug) +{ + ioplug_priv_t *io = ioplug->pcm->private_data; + clear_io_params(io); +} + +/** + * \brief Set parameter as the list + * \param ioplug the ioplug handle + * \param type parameter type + * \param num_list number of available values + * \param list the list of available values + * \return 0 if successful, or a negative error code + * + * Sets the parameter as the list. + * The available values of the given parameter type is restricted to the ones of the given list. + */ +int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list) +{ + ioplug_priv_t *io = ioplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_IOPLUG_HW_PARAMS) { + SNDERR("IOPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (type == SND_PCM_IOPLUG_HW_PERIODS) + io->params[type].integer = 1; + return snd_ext_parm_set_list(&io->params[type], num_list, list); +} + +/** + * \brief Set parameter as the min/max values + * \param ioplug the ioplug handle + * \param type parameter type + * \param min the minimum value + * \param max the maximum value + * \return 0 if successful, or a negative error code + * + * Sets the parameter as the min/max values. + * The available values of the given parameter type is restricted between the given + * minimum and maximum values. + */ +int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max) +{ + ioplug_priv_t *io = ioplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_IOPLUG_HW_PARAMS) { + SNDERR("IOPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) { + SNDERR("IOPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (type == SND_PCM_IOPLUG_HW_PERIODS) + io->params[type].integer = 1; + return snd_ext_parm_set_minmax(&io->params[type], min, max); +} + +/** + * \brief Reinitialize the poll and mmap status + * \param ioplug the ioplug handle + * \return 0 if successful, or a negative error code + * + * Reinitializes the poll and the mmap status of the PCM. + * Call this function to propagate the status change in the ioplug instance to + * its PCM internals. + */ +int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug) +{ + ioplug->pcm->poll_fd = ioplug->poll_fd; + ioplug->pcm->poll_events = ioplug->poll_events; + ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0; + ioplug->pcm->mmap_rw = ioplug->mmap_rw; + return 0; +} + +/** + * \brief Get mmap area of ioplug + * \param ioplug the ioplug handle + * \return the mmap channel areas if available, or NULL + * + * Returns the mmap channel areas if available. When mmap_rw field is not set, + * this function always returns NULL. + */ +const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug) +{ + if (ioplug->mmap_rw) + return snd_pcm_mmap_areas(ioplug->pcm); + return NULL; +} + +/** + * \brief Change the ioplug PCM status + * \param ioplug the ioplug handle + * \param state the PCM status + * \return zero if successful or a negative error code + * + * Changes the PCM status of the ioplug to the given value. + * This function can be used for external plugins to notify the status + * change, e.g. XRUN. + */ +int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state) +{ + ioplug->state = state; + return 0; +} diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c new file mode 100644 index 0000000..c413c10 --- /dev/null +++ b/src/pcm/pcm_ladspa.c @@ -0,0 +1,1803 @@ +/** + * \file pcm/pcm_ladspa.c + * \ingroup PCM_Plugins + * \brief ALSA Plugin <-> LADSPA Plugin Interface + * \author Jaroslav Kysela + * \author Jaroslav Kysela + * \date 2001,2006 + */ +/* + * PCM - LADSPA integration plugin + * Copyright (c) 2001-2006 by Jaroslav Kysela + * Copyright (c) 2005 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * perex@perex.cz 2005/12/13 + * The LADSPA plugin rewrite was sponsored by MediaNet AG + * http://www.medianet.ag + */ + +#include +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "ladspa.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_ladspa = ""; +#endif + +#ifndef DOC_HIDDEN + +#define NO_ASSIGN 0xffffffff + +typedef enum _snd_pcm_ladspa_policy { + SND_PCM_LADSPA_POLICY_NONE, /* use bindings only */ + SND_PCM_LADSPA_POLICY_DUPLICATE /* duplicate bindings for all channels */ +} snd_pcm_ladspa_policy_t; + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + /* Plugin custom fields */ + struct list_head pplugins; + struct list_head cplugins; + unsigned int channels; /* forced input channels, 0 = auto */ + unsigned int allocated; /* count of allocated samples */ + LADSPA_Data *zero[2]; /* zero input or dummy output */ +} snd_pcm_ladspa_t; + +typedef struct { + unsigned int size; + unsigned int *array; +} snd_pcm_ladspa_array_t; + +typedef struct { + snd_pcm_ladspa_array_t channels; + snd_pcm_ladspa_array_t ports; + LADSPA_Data **m_data; + LADSPA_Data **data; +} snd_pcm_ladspa_eps_t; + +typedef struct snd_pcm_ladspa_instance { + struct list_head list; + const LADSPA_Descriptor *desc; + LADSPA_Handle *handle; + unsigned int depth; + snd_pcm_ladspa_eps_t input; + snd_pcm_ladspa_eps_t output; + struct snd_pcm_ladspa_instance *prev; + struct snd_pcm_ladspa_instance *next; +} snd_pcm_ladspa_instance_t; + +typedef struct { + LADSPA_PortDescriptor pdesc; /* port description */ + unsigned int port_bindings_size; /* size of array */ + unsigned int *port_bindings; /* index = channel number, value = LADSPA port */ + unsigned int controls_size; /* size of array */ + unsigned char *controls_initialized; /* initialized by ALSA user */ + LADSPA_Data *controls; /* index = LADSPA control port index */ +} snd_pcm_ladspa_plugin_io_t; + +typedef struct { + struct list_head list; + snd_pcm_ladspa_policy_t policy; + char *filename; + void *dl_handle; + const LADSPA_Descriptor *desc; + snd_pcm_ladspa_plugin_io_t input; + snd_pcm_ladspa_plugin_io_t output; + struct list_head instances; /* one LADSPA plugin might be used multiple times */ +} snd_pcm_ladspa_plugin_t; + +#endif /* DOC_HIDDEN */ + +static unsigned int snd_pcm_ladspa_count_ports(snd_pcm_ladspa_plugin_t *lplug, + LADSPA_PortDescriptor pdesc) +{ + unsigned int res = 0, idx; + for (idx = 0; idx < lplug->desc->PortCount; idx++) { + if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc) + res++; + } + return res; +} + +static int snd_pcm_ladspa_find_port(unsigned int *res, + snd_pcm_ladspa_plugin_t *lplug, + LADSPA_PortDescriptor pdesc, + unsigned int port_idx) +{ + unsigned long idx; + + for (idx = 0; idx < lplug->desc->PortCount; idx++) + if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc) { + if (port_idx == 0) { + *res = idx; + return 0; + } + port_idx--; + } + return -EINVAL; +} + +static int snd_pcm_ladspa_find_sport(unsigned int *res, + snd_pcm_ladspa_plugin_t *lplug, + LADSPA_PortDescriptor pdesc, + const char *port_name) +{ + unsigned long idx; + + for (idx = 0; idx < lplug->desc->PortCount; idx++) + if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc && + !strcmp(lplug->desc->PortNames[idx], port_name)) { + *res = idx; + return 0; + } + return -EINVAL; +} + +static int snd_pcm_ladspa_find_port_idx(unsigned int *res, + snd_pcm_ladspa_plugin_t *lplug, + LADSPA_PortDescriptor pdesc, + unsigned int port) +{ + unsigned long idx; + unsigned int r = 0; + + if (port >= lplug->desc->PortCount) + return -EINVAL; + for (idx = 0; idx < port; idx++) + if ((lplug->desc->PortDescriptors[idx] & pdesc) == pdesc) + r++; + *res = r; + return 0; +} + +static void snd_pcm_ladspa_free_io(snd_pcm_ladspa_plugin_io_t *io) +{ + free(io->controls); + free(io->controls_initialized); +} + +static void snd_pcm_ladspa_free_plugins(struct list_head *plugins) +{ + while (!list_empty(plugins)) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(plugins->next, snd_pcm_ladspa_plugin_t, list); + snd_pcm_ladspa_free_io(&plugin->input); + snd_pcm_ladspa_free_io(&plugin->output); + if (plugin->dl_handle) + dlclose(plugin->dl_handle); + free(plugin->filename); + list_del(&plugin->list); + free(plugin); + } +} + +static void snd_pcm_ladspa_free(snd_pcm_ladspa_t *ladspa) +{ + unsigned int idx; + + snd_pcm_ladspa_free_plugins(&ladspa->pplugins); + snd_pcm_ladspa_free_plugins(&ladspa->cplugins); + for (idx = 0; idx < 2; idx++) { + free(ladspa->zero[idx]); + ladspa->zero[idx] = NULL; + } + ladspa->allocated = 0; +} + +static int snd_pcm_ladspa_close(snd_pcm_t *pcm) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + + snd_pcm_ladspa_free(ladspa); + return snd_pcm_generic_close(pcm); +} + +static int snd_pcm_ladspa_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHMN }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_format(params, SND_PCM_FORMAT_FLOAT); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + if (ladspa->channels > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK) { + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, ladspa->channels, 0); + if (err < 0) + return err; + } + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_ladspa_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAPN }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, SND_PCM_FORMAT_FLOAT); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + if (ladspa->channels > 0 && pcm->stream == SND_PCM_STREAM_CAPTURE) + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, ladspa->channels, 0); + return 0; +} + +static int snd_pcm_ladspa_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_ladspa_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_ladspa_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_ladspa_hw_refine_cprepare, + snd_pcm_ladspa_hw_refine_cchange, + snd_pcm_ladspa_hw_refine_sprepare, + snd_pcm_ladspa_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_ladspa_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + // snd_pcm_ladspa_t *ladspa = pcm->private_data; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_ladspa_hw_refine_cchange, + snd_pcm_ladspa_hw_refine_sprepare, + snd_pcm_ladspa_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + return 0; +} + +static void snd_pcm_ladspa_free_eps(snd_pcm_ladspa_eps_t *eps) +{ + free(eps->channels.array); + free(eps->ports.array); +} + +static void snd_pcm_ladspa_free_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa, int cleanup) +{ + struct list_head *list, *pos, *pos1, *next1; + unsigned int idx; + + list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins; + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each_safe(pos1, next1, &plugin->instances) { + snd_pcm_ladspa_instance_t *instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + if (plugin->desc->deactivate) + plugin->desc->deactivate(instance->handle); + if (cleanup) { + if (plugin->desc->cleanup) + plugin->desc->cleanup(instance->handle); + if (instance->input.m_data) { + for (idx = 0; idx < instance->input.channels.size; idx++) + free(instance->input.m_data[idx]); + free(instance->input.m_data); + } + if (instance->output.m_data) { + for (idx = 0; idx < instance->output.channels.size; idx++) + free(instance->output.m_data[idx]); + free(instance->output.m_data); + } + free(instance->input.data); + free(instance->output.data); + list_del(&(instance->list)); + snd_pcm_ladspa_free_eps(&instance->input); + snd_pcm_ladspa_free_eps(&instance->output); + free(instance); + } else { + if (plugin->desc->activate) + plugin->desc->activate(instance->handle); + } + } + if (cleanup) { + assert(list_empty(&plugin->instances)); + } + } +} + +static int snd_pcm_ladspa_add_to_carray(snd_pcm_ladspa_array_t *array, + unsigned int idx, + unsigned int val) +{ + unsigned int *narray; + unsigned int idx1; + + if (idx >= array->size) { + narray = realloc(array->array, sizeof(unsigned int) * (idx + 1)); + if (narray == NULL) + return -ENOMEM; + for (idx1 = array->size; idx1 < idx; idx1++) + narray[idx1] = NO_ASSIGN; + array->array = narray; + array->size = idx + 1; + array->array[idx] = val; + return 0; + } + if (array->array[idx] == NO_ASSIGN) + array->array[idx] = val; + else + return -EINVAL; + return 0; +} + +static int snd_pcm_ladspa_add_to_array(snd_pcm_ladspa_array_t *array, + unsigned int idx, + unsigned int val) +{ + unsigned int *narray; + unsigned int idx1; + + if (idx >= array->size) { + narray = realloc(array->array, sizeof(unsigned int) * (idx + 1)); + if (narray == NULL) + return -ENOMEM; + for (idx1 = array->size; idx1 < idx; idx1++) + narray[idx1] = NO_ASSIGN; + array->array = narray; + array->size = idx + 1; + } + array->array[idx] = val; + return 0; +} + +static int snd_pcm_ladspa_connect_plugin1(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_plugin_io_t *io, + snd_pcm_ladspa_eps_t *eps) +{ + unsigned int port, channels, idx, idx1; + int err; + + assert(plugin->policy == SND_PCM_LADSPA_POLICY_NONE); + channels = io->port_bindings_size > 0 ? + io->port_bindings_size : + snd_pcm_ladspa_count_ports(plugin, io->pdesc | LADSPA_PORT_AUDIO); + for (idx = idx1 = 0; idx < channels; idx++) { + if (io->port_bindings_size > 0) + port = io->port_bindings[idx]; + else { + err = snd_pcm_ladspa_find_port(&port, plugin, io->pdesc | LADSPA_PORT_AUDIO, idx); + if (err < 0) { + SNDERR("unable to find audio %s port %u plugin '%s'", io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", idx, plugin->desc->Name); + return err; + } + } + if (port == NO_ASSIGN) + continue; + err = snd_pcm_ladspa_add_to_carray(&eps->channels, idx1, idx); + if (err < 0) { + SNDERR("unable to add channel %u for audio %s plugin '%s'", idx, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name); + return err; + } + err = snd_pcm_ladspa_add_to_array(&eps->ports, idx1, port); + if (err < 0) { + SNDERR("unable to add port %u for audio %s plugin '%s'", port, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name); + return err; + } + idx1++; + } + return 0; +} + +static int snd_pcm_ladspa_connect_plugin(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_instance_t *instance) +{ + int err; + + err = snd_pcm_ladspa_connect_plugin1(plugin, &plugin->input, &instance->input); + if (err < 0) + return err; + err = snd_pcm_ladspa_connect_plugin1(plugin, &plugin->output, &instance->output); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_ladspa_connect_plugin_duplicate1(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_plugin_io_t *io, + snd_pcm_ladspa_eps_t *eps, + unsigned int idx) +{ + unsigned int port; + int err; + + assert(plugin->policy == SND_PCM_LADSPA_POLICY_DUPLICATE); + if (io->port_bindings_size > 0) { + port = io->port_bindings[0]; + } else { + err = snd_pcm_ladspa_find_port(&port, plugin, io->pdesc | LADSPA_PORT_AUDIO, 0); + if (err < 0) { + SNDERR("unable to find audio %s port %u plugin '%s'", io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", (unsigned int)0, plugin->desc->Name); + return err; + } + } + err = snd_pcm_ladspa_add_to_carray(&eps->channels, 0, idx); + if (err < 0) { + SNDERR("unable to add channel %u for audio %s plugin '%s'", idx, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name); + return err; + } + err = snd_pcm_ladspa_add_to_array(&eps->ports, 0, port); + if (err < 0) { + SNDERR("unable to add port %u for audio %s plugin '%s'", port, io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name); + return err; + } + return 0; +} + +static int snd_pcm_ladspa_connect_plugin_duplicate(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_plugin_io_t *in_io, + snd_pcm_ladspa_plugin_io_t *out_io, + snd_pcm_ladspa_instance_t *instance, + unsigned int idx) +{ + int err; + + err = snd_pcm_ladspa_connect_plugin_duplicate1(plugin, in_io, &instance->input, idx); + if (err < 0) + return err; + err = snd_pcm_ladspa_connect_plugin_duplicate1(plugin, out_io, &instance->output, idx); + if (err < 0) + return err; + return 0; +} + +static void snd_pcm_ladspa_get_default_cvalue(const LADSPA_Descriptor * desc, unsigned int port, LADSPA_Data *val) +{ + LADSPA_PortRangeHintDescriptor hdesc; + + hdesc = desc->PortRangeHints[port].HintDescriptor; + switch (hdesc & LADSPA_HINT_DEFAULT_MASK) { + case LADSPA_HINT_DEFAULT_MINIMUM: + *val = desc->PortRangeHints[port].LowerBound; + break; + case LADSPA_HINT_DEFAULT_LOW: + if (LADSPA_IS_HINT_LOGARITHMIC(hdesc)) { + *val = exp(log(desc->PortRangeHints[port].LowerBound) + * 0.75 + + log(desc->PortRangeHints[port].UpperBound) + * 0.25); + } else { + *val = (desc->PortRangeHints[port].LowerBound * 0.75) + + (desc->PortRangeHints[port].UpperBound * 0.25); + } + break; + case LADSPA_HINT_DEFAULT_MIDDLE: + if (LADSPA_IS_HINT_LOGARITHMIC(hdesc)) { + *val = sqrt(desc->PortRangeHints[port].LowerBound * + desc->PortRangeHints[port].UpperBound); + } else { + *val = 0.5 * + (desc->PortRangeHints[port].LowerBound + + desc->PortRangeHints[port].UpperBound); + } + break; + case LADSPA_HINT_DEFAULT_HIGH: + if (LADSPA_IS_HINT_LOGARITHMIC(hdesc)) { + *val = exp(log(desc->PortRangeHints[port].LowerBound) + * 0.25 + + log(desc->PortRangeHints[port].UpperBound) + * 0.75); + } else { + *val = (desc->PortRangeHints[port].LowerBound * 0.25) + + (desc->PortRangeHints[port].UpperBound * 0.75); + } + break; + case LADSPA_HINT_DEFAULT_MAXIMUM: + *val = desc->PortRangeHints[port].UpperBound; + break; + case LADSPA_HINT_DEFAULT_0: + *val = 0; + break; + case LADSPA_HINT_DEFAULT_1: + *val = 1; + break; + case LADSPA_HINT_DEFAULT_100: + *val = 100; + break; + case LADSPA_HINT_DEFAULT_440: + *val = 440; + break; + default: + *val = 0; /* reasonable default, if everything fails */ + break; + } +} + +static int snd_pcm_ladspa_connect_controls(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_plugin_io_t *io, + snd_pcm_ladspa_instance_t *instance) +{ + unsigned long idx, midx; + + for (idx = midx = 0; idx < plugin->desc->PortCount; idx++) + if ((plugin->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_CONTROL)) == (io->pdesc | LADSPA_PORT_CONTROL)) { + if (io->controls_size > midx) { + if (!io->controls_initialized[midx]) + snd_pcm_ladspa_get_default_cvalue(plugin->desc, idx, &io->controls[midx]); + plugin->desc->connect_port(instance->handle, idx, &io->controls[midx]); + } else { + return -EINVAL; + } + midx++; + } + return 0; +} + +static int snd_pcm_ladspa_check_connect(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_plugin_io_t *io, + snd_pcm_ladspa_eps_t *eps, + unsigned int depth) +{ + unsigned int idx, midx; + int err = 0; + + for (idx = midx = 0; idx < plugin->desc->PortCount; idx++) + if ((plugin->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_AUDIO)) == (io->pdesc | LADSPA_PORT_AUDIO)) { + if (eps->channels.array[midx] == NO_ASSIGN) { + SNDERR("%s port for plugin %s depth %u is not connected", io->pdesc & LADSPA_PORT_INPUT ? "input" : "output", plugin->desc->Name, depth); + err++; + } + midx++; + } + if (err > 0) { + SNDERR("%i connection errors total", err); + return -EINVAL; + } + return 0; +} + +static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa) +{ + struct list_head *list, *pos; + unsigned int depth, idx, count; + unsigned int in_channel, out_channel; + unsigned int in_channels, out_channels; + unsigned int in_ports, out_ports; + snd_pcm_ladspa_instance_t *instance = NULL; + int err; + + list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins; + in_channels = ladspa->channels > 0 ? ladspa->channels : + (pcm->stream == SND_PCM_STREAM_PLAYBACK ? pcm->channels : ladspa->plug.gen.slave->channels); + depth = 0; + out_channels = 0; + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + if (pos->next == list) /* last entry */ + out_channels = pcm->stream == SND_PCM_STREAM_PLAYBACK ? ladspa->plug.gen.slave->channels : pcm->channels; + in_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO); + out_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO); + count = 1; + if (plugin->policy == SND_PCM_LADSPA_POLICY_DUPLICATE) { + if (in_ports == 1 && out_ports == 1) + count = in_channels; + else + plugin->policy = SND_PCM_LADSPA_POLICY_NONE; + } + in_channel = 0; + out_channel = 0; + for (idx = 0; idx < count; idx++) { + instance = (snd_pcm_ladspa_instance_t *)calloc(1, sizeof(snd_pcm_ladspa_instance_t)); + if (instance == NULL) + return -ENOMEM; + instance->desc = plugin->desc; + instance->handle = plugin->desc->instantiate(plugin->desc, pcm->rate); + instance->depth = depth; + if (instance->handle == NULL) { + SNDERR("Unable to create instance of LADSPA plugin '%s'", plugin->desc->Name); + free(instance); + return -EINVAL; + } + list_add_tail(&instance->list, &plugin->instances); + if (plugin->desc->activate) + plugin->desc->activate(instance->handle); + if (plugin->policy == SND_PCM_LADSPA_POLICY_DUPLICATE) { + err = snd_pcm_ladspa_connect_plugin_duplicate(plugin, &plugin->input, &plugin->output, instance, idx); + if (err < 0) { + SNDERR("Unable to connect duplicate port of plugin '%s' channel %u depth %u", plugin->desc->Name, idx, instance->depth); + return err; + } + } else { + err = snd_pcm_ladspa_connect_plugin(plugin, instance); + if (err < 0) { + SNDERR("Unable to connect plugin '%s' depth %u", plugin->desc->Name, depth); + return err; + } + } + err = snd_pcm_ladspa_connect_controls(plugin, &plugin->input, instance); + assert(err >= 0); + err = snd_pcm_ladspa_connect_controls(plugin, &plugin->output, instance); + assert(err >= 0); + } + err = snd_pcm_ladspa_check_connect(plugin, &plugin->input, &instance->input, depth); + if (err < 0) + return err; + err = snd_pcm_ladspa_check_connect(plugin, &plugin->output, &instance->output, depth); + if (err < 0) + return err; + depth++; + } + return 0; +} + +static LADSPA_Data *snd_pcm_ladspa_allocate_zero(snd_pcm_ladspa_t *ladspa, unsigned int idx) +{ + if (ladspa->zero[idx] == NULL) + ladspa->zero[idx] = calloc(ladspa->allocated, sizeof(LADSPA_Data)); + return ladspa->zero[idx]; +} + +static int snd_pcm_ladspa_allocate_memory(snd_pcm_t *pcm, snd_pcm_ladspa_t *ladspa) +{ + struct list_head *list, *pos, *pos1; + snd_pcm_ladspa_instance_t *instance; + unsigned int channels = 16, nchannels; + unsigned int ichannels, ochannels; + void **pchannels, **npchannels; + unsigned int idx, chn; + + ladspa->allocated = 2048; + if (pcm->buffer_size > ladspa->allocated) + ladspa->allocated = pcm->buffer_size; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + ichannels = pcm->channels; + ochannels = ladspa->plug.gen.slave->channels; + } else { + ichannels = ladspa->plug.gen.slave->channels; + ochannels = pcm->channels; + } + pchannels = calloc(1, sizeof(void *) * channels); + if (pchannels == NULL) + return -ENOMEM; + list = pcm->stream == SND_PCM_STREAM_PLAYBACK ? &ladspa->pplugins : &ladspa->cplugins; + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(pos1, &plugin->instances) { + instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + nchannels = channels; + for (idx = 0; idx < instance->input.channels.size; idx++) { + chn = instance->input.channels.array[idx]; + assert(instance->input.ports.array[idx] != NO_ASSIGN); + if (chn >= nchannels) + nchannels = chn + 1; + } + for (idx = 0; idx < instance->output.channels.size; idx++) { + chn = instance->output.channels.array[idx]; + assert(instance->output.ports.array[idx] != NO_ASSIGN); + if (chn >= nchannels) + nchannels = chn + 1; + } + if (nchannels != channels) { + npchannels = realloc(pchannels, nchannels * sizeof(void *)); + if (npchannels == NULL) { + free(pchannels); + return -ENOMEM; + } + for (idx = channels; idx < nchannels; idx++) + npchannels[idx] = NULL; + pchannels = npchannels; + } + assert(instance->input.data == NULL); + assert(instance->input.m_data == NULL); + assert(instance->output.data == NULL); + assert(instance->output.m_data == NULL); + instance->input.data = calloc(instance->input.channels.size, sizeof(void *)); + instance->input.m_data = calloc(instance->input.channels.size, sizeof(void *)); + instance->output.data = calloc(instance->output.channels.size, sizeof(void *)); + instance->output.m_data = calloc(instance->output.channels.size, sizeof(void *)); + if (instance->input.data == NULL || + instance->input.m_data == NULL || + instance->output.data == NULL || + instance->output.m_data == NULL) + return -ENOMEM; + for (idx = 0; idx < instance->input.channels.size; idx++) { + chn = instance->output.channels.array[idx]; + if (pchannels[chn] == NULL && chn < ichannels) { + instance->input.data[idx] = NULL; + continue; + } + instance->input.data[idx] = pchannels[chn]; + if (instance->input.data[idx] == NULL) { + instance->input.data[idx] = snd_pcm_ladspa_allocate_zero(ladspa, 0); + if (instance->input.data[idx] == NULL) + return -ENOMEM; + } + } + for (idx = 0; idx < instance->output.channels.size; idx++) { + chn = instance->output.channels.array[idx]; + /* FIXME/OPTIMIZE: check if we can remove double alloc */ + /* if LADSPA plugin has no broken inplace */ + instance->output.data[idx] = malloc(sizeof(LADSPA_Data) * ladspa->allocated); + if (instance->output.data[idx] == NULL) + return -ENOMEM; + pchannels[chn] = instance->output.m_data[idx] = instance->output.data[idx]; + } + } + } + /* OPTIMIZE: we have already allocated areas for ALSA output channels */ + /* next loop deallocates the last output LADSPA areas and connects */ + /* them to ALSA areas (NULL) or dummy area ladpsa->free[1] ; */ + /* this algorithm might be optimized to not allocate the last LADSPA outputs */ + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(pos1, &plugin->instances) { + instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + for (idx = 0; idx < instance->output.channels.size; idx++) { + chn = instance->output.channels.array[idx]; + if (instance->output.data[idx] == pchannels[chn]) { + free(instance->output.m_data[idx]); + instance->output.m_data[idx] = NULL; + if (chn < ochannels) { + instance->output.data[idx] = NULL; + } else { + instance->output.data[idx] = snd_pcm_ladspa_allocate_zero(ladspa, 1); + if (instance->output.data[idx] == NULL) + return -ENOMEM; + } + } + } + } + } +#if 0 + printf("zero[0] = %p\n", ladspa->zero[0]); + printf("zero[1] = %p\n", ladspa->zero[1]); + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(pos1, &plugin->instances) { + instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + for (idx = 0; idx < instance->input.channels.size; idx++) + printf("%i:alloc-input%i: data = %p, m_data = %p\n", instance->depth, idx, instance->input.data[idx], instance->input.m_data[idx]); + for (idx = 0; idx < instance->output.channels.size; idx++) + printf("%i:alloc-output%i: data = %p, m_data = %p\n", instance->depth, idx, instance->output.data[idx], instance->output.m_data[idx]); + } + } +#endif + free(pchannels); + return 0; +} + +static int snd_pcm_ladspa_init(snd_pcm_t *pcm) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + int err; + + snd_pcm_ladspa_free_instances(pcm, ladspa, 1); + err = snd_pcm_ladspa_allocate_instances(pcm, ladspa); + if (err < 0) { + snd_pcm_ladspa_free_instances(pcm, ladspa, 1); + return err; + } + err = snd_pcm_ladspa_allocate_memory(pcm, ladspa); + if (err < 0) { + snd_pcm_ladspa_free_instances(pcm, ladspa, 1); + return err; + } + return 0; +} + +static int snd_pcm_ladspa_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + + snd_pcm_ladspa_free_instances(pcm, ladspa, 1); + return snd_pcm_generic_hw_free(pcm); +} + +static snd_pcm_uframes_t +snd_pcm_ladspa_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + snd_pcm_ladspa_instance_t *instance; + struct list_head *pos, *pos1; + LADSPA_Data *data; + unsigned int idx, chn, size1, size2; + + if (size > *slave_sizep) + size = *slave_sizep; + size2 = size; +#if 0 /* no processing - for testing purposes only */ + snd_pcm_areas_copy(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, pcm->format); +#else + while (size > 0) { + size1 = size; + if (size1 > ladspa->allocated) + size1 = ladspa->allocated; + list_for_each(pos, &ladspa->pplugins) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(pos1, &plugin->instances) { + instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + for (idx = 0; idx < instance->input.channels.size; idx++) { + chn = instance->input.channels.array[idx]; + data = instance->input.data[idx]; + if (data == NULL) { + data = (LADSPA_Data *)((char *)areas[chn].addr + (areas[chn].first / 8)); + data += offset; + } + instance->desc->connect_port(instance->handle, instance->input.ports.array[idx], data); + } + for (idx = 0; idx < instance->output.channels.size; idx++) { + chn = instance->output.channels.array[idx]; + data = instance->output.data[idx]; + if (data == NULL) { + data = (LADSPA_Data *)((char *)slave_areas[chn].addr + (areas[chn].first / 8)); + data += slave_offset; + } + instance->desc->connect_port(instance->handle, instance->output.ports.array[idx], data); + } + instance->desc->run(instance->handle, size1); + } + } + offset += size1; + slave_offset += size1; + size -= size1; + } +#endif + *slave_sizep = size2; + return size2; +} + +static snd_pcm_uframes_t +snd_pcm_ladspa_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + snd_pcm_ladspa_instance_t *instance; + struct list_head *pos, *pos1; + LADSPA_Data *data; + unsigned int idx, chn, size1, size2;; + + if (size > *slave_sizep) + size = *slave_sizep; + size2 = size; +#if 0 /* no processing - for testing purposes only */ + snd_pcm_areas_copy(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, pcm->format); +#else + while (size > 0) { + size1 = size; + if (size1 > ladspa->allocated) + size1 = ladspa->allocated; + list_for_each(pos, &ladspa->cplugins) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + list_for_each(pos1, &plugin->instances) { + instance = list_entry(pos1, snd_pcm_ladspa_instance_t, list); + for (idx = 0; idx < instance->input.channels.size; idx++) { + chn = instance->input.channels.array[idx]; + data = instance->input.data[idx]; + if (data == NULL) { + data = (LADSPA_Data *)((char *)slave_areas[chn].addr + (areas[chn].first / 8)); + data += slave_offset; + } + instance->desc->connect_port(instance->handle, instance->input.ports.array[idx], data); + } + for (idx = 0; idx < instance->output.channels.size; idx++) { + chn = instance->output.channels.array[idx]; + data = instance->output.data[idx]; + if (data == NULL) { + data = (LADSPA_Data *)((char *)areas[chn].addr + (areas[chn].first / 8)); + data += offset; + } + instance->desc->connect_port(instance->handle, instance->output.ports.array[idx], data); + } + instance->desc->run(instance->handle, size1); + } + } + offset += size1; + slave_offset += size1; + size -= size1; + } +#endif + *slave_sizep = size2; + return size2; +} + +static void snd_pcm_ladspa_dump_direction(snd_pcm_ladspa_plugin_t *plugin, + snd_pcm_ladspa_plugin_io_t *io, + snd_output_t *out) +{ + unsigned int idx, midx; + + if (io->port_bindings_size == 0) + goto __control; + snd_output_printf(out, " Audio %s port bindings:\n", io->pdesc == LADSPA_PORT_INPUT ? "input" : "output"); + for (idx = 0; idx < io->port_bindings_size; idx++) { + if (io->port_bindings[idx] == NO_ASSIGN) + snd_output_printf(out, " %i -> NONE\n", idx); + else + snd_output_printf(out, " %i -> %i\n", idx, io->port_bindings[idx]); + } + __control: + if (io->controls_size == 0) + return; + snd_output_printf(out, " Control %s port initial values:\n", io->pdesc == LADSPA_PORT_INPUT ? "input" : "output"); + for (idx = midx = 0; idx < plugin->desc->PortCount; idx++) { + if ((plugin->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_CONTROL)) == (io->pdesc | LADSPA_PORT_CONTROL)) { + snd_output_printf(out, " %i \"%s\" = %.8f\n", idx, plugin->desc->PortNames[idx], io->controls[midx]); + midx++; + } + } +} + +static void snd_pcm_ladspa_dump_array(snd_output_t *out, + snd_pcm_ladspa_array_t *array, + snd_pcm_ladspa_plugin_t *plugin) +{ + unsigned int size = array->size; + unsigned int val, idx = 0; + + while (size-- > 0) { + if (idx > 0) { + snd_output_putc(out, ','); + snd_output_putc(out, ' '); + } + val = array->array[idx++]; + if (val == NO_ASSIGN) + snd_output_putc(out, '-'); + else + snd_output_printf(out, "%u", val); + if (plugin && val != NO_ASSIGN) + snd_output_printf(out, " \"%s\"", plugin->desc->PortNames[val]); + } +} + +static void snd_pcm_ladspa_plugins_dump(struct list_head *list, snd_output_t *out) +{ + struct list_head *pos, *pos2; + + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + snd_output_printf(out, " Policy: %s\n", plugin->policy == SND_PCM_LADSPA_POLICY_NONE ? "none" : "duplicate"); + snd_output_printf(out, " Filename: %s\n", plugin->filename); + snd_output_printf(out, " Plugin Name: %s\n", plugin->desc->Name); + snd_output_printf(out, " Plugin Label: %s\n", plugin->desc->Label); + snd_output_printf(out, " Plugin Unique ID: %lu\n", plugin->desc->UniqueID); + snd_output_printf(out, " Instances:\n"); + list_for_each(pos2, &plugin->instances) { + snd_pcm_ladspa_instance_t *in = (snd_pcm_ladspa_instance_t *) pos2; + snd_output_printf(out, " Depth: %i\n", in->depth); + snd_output_printf(out, " InChannels: "); + snd_pcm_ladspa_dump_array(out, &in->input.channels, NULL); + snd_output_printf(out, "\n InPorts: "); + snd_pcm_ladspa_dump_array(out, &in->input.ports, plugin); + snd_output_printf(out, "\n OutChannels: "); + snd_pcm_ladspa_dump_array(out, &in->output.channels, NULL); + snd_output_printf(out, "\n OutPorts: "); + snd_pcm_ladspa_dump_array(out, &in->output.ports, plugin); + snd_output_printf(out, "\n"); + } + snd_pcm_ladspa_dump_direction(plugin, &plugin->input, out); + snd_pcm_ladspa_dump_direction(plugin, &plugin->output, out); + } +} + +static void snd_pcm_ladspa_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_ladspa_t *ladspa = pcm->private_data; + + snd_output_printf(out, "LADSPA PCM\n"); + snd_output_printf(out, " Playback:\n"); + snd_pcm_ladspa_plugins_dump(&ladspa->pplugins, out); + snd_output_printf(out, " Capture:\n"); + snd_pcm_ladspa_plugins_dump(&ladspa->cplugins, out); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(ladspa->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_ladspa_ops = { + .close = snd_pcm_ladspa_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_ladspa_hw_refine, + .hw_params = snd_pcm_ladspa_hw_params, + .hw_free = snd_pcm_ladspa_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_ladspa_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static int snd_pcm_ladspa_check_file(snd_pcm_ladspa_plugin_t * const plugin, + const char *filename, + const char *label, + const unsigned long ladspa_id) +{ + void *handle; + + assert(filename); + handle = dlopen(filename, RTLD_LAZY); + if (handle) { + LADSPA_Descriptor_Function fcn = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor"); + if (fcn) { + long idx; + const LADSPA_Descriptor *d; + for (idx = 0; (d = fcn(idx)) != NULL; idx++) { +/* + * avoid locale problems - see ALSA bug#1553 + */ +#if 0 + if (strcmp(label, d->Label)) + continue; +#else + char *labellocale; + struct lconv *lc; + if (label != NULL) { + lc = localeconv (); + labellocale = malloc (strlen (label) + 1); + if (labellocale == NULL) { + dlclose(handle); + return -ENOMEM; + } + strcpy (labellocale, label); + if (strrchr(labellocale, '.')) + *strrchr (labellocale, '.') = *lc->decimal_point; + if (strcmp(label, d->Label) && strcmp(labellocale, d->Label)) { + free(labellocale); + continue; + } + free (labellocale); + } +#endif + if (ladspa_id > 0 && d->UniqueID != ladspa_id) + continue; + plugin->filename = strdup(filename); + if (plugin->filename == NULL) { + dlclose(handle); + return -ENOMEM; + } + plugin->dl_handle = handle; + plugin->desc = d; + return 1; + } + } + dlclose(handle); + } + return -ENOENT; +} + +static int snd_pcm_ladspa_check_dir(snd_pcm_ladspa_plugin_t * const plugin, + const char *path, + const char *label, + const unsigned long ladspa_id) +{ + DIR *dir; + struct dirent * dirent; + int len = strlen(path), err; + int need_slash; + char *filename; + + if (len < 1) + return 0; + need_slash = path[len - 1] != '/'; + + dir = opendir(path); + if (!dir) + return -ENOENT; + + while (1) { + dirent = readdir(dir); + if (!dirent) { + closedir(dir); + return 0; + } + + filename = malloc(len + strlen(dirent->d_name) + 1 + need_slash); + if (filename == NULL) { + closedir(dir); + return -ENOMEM; + } + strcpy(filename, path); + if (need_slash) + strcat(filename, "/"); + strcat(filename, dirent->d_name); + err = snd_pcm_ladspa_check_file(plugin, filename, label, ladspa_id); + free(filename); + if (err < 0 && err != -ENOENT) { + closedir(dir); + return err; + } + if (err > 0) { + closedir(dir); + return 1; + } + } + /* never reached */ + return 0; +} + +static int snd_pcm_ladspa_look_for_plugin(snd_pcm_ladspa_plugin_t * const plugin, + const char *path, + const char *label, + const long ladspa_id) +{ + const char *c; + size_t l; + int err; + + for (c = path; (l = strcspn(c, ": ")) > 0; ) { + char name[l + 1]; + char *fullpath; + memcpy(name, c, l); + name[l] = 0; + err = snd_user_file(name, &fullpath); + if (err < 0) + return err; + err = snd_pcm_ladspa_check_dir(plugin, fullpath, label, ladspa_id); + free(fullpath); + if (err < 0) + return err; + if (err > 0) + return 0; + c += l; + if (!*c) + break; + c++; + } + return -ENOENT; +} + +static int snd_pcm_ladspa_add_default_controls(snd_pcm_ladspa_plugin_t *lplug, + snd_pcm_ladspa_plugin_io_t *io) +{ + unsigned int count = 0; + LADSPA_Data *array; + unsigned char *initialized; + unsigned long idx; + + for (idx = 0; idx < lplug->desc->PortCount; idx++) + if ((lplug->desc->PortDescriptors[idx] & (io->pdesc | LADSPA_PORT_CONTROL)) == (io->pdesc | LADSPA_PORT_CONTROL)) + count++; + array = (LADSPA_Data *)calloc(count, sizeof(LADSPA_Data)); + if (!array) + return -ENOMEM; + initialized = (unsigned char *)calloc(count, sizeof(unsigned char)); + if (!initialized) { + free(array); + return -ENOMEM; + } + io->controls_size = count; + io->controls_initialized = initialized; + io->controls = array; + + return 0; +} + +static int snd_pcm_ladspa_parse_controls(snd_pcm_ladspa_plugin_t *lplug, + snd_pcm_ladspa_plugin_io_t *io, + snd_config_t *controls) +{ + snd_config_iterator_t i, next; + int err; + + if (snd_config_get_type(controls) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("controls definition must be a compound"); + return -EINVAL; + } + + snd_config_for_each(i, next, controls) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long lval; + unsigned int port, uval; + double dval; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &lval); + if (err >= 0) { + err = snd_pcm_ladspa_find_port(&port, lplug, io->pdesc | LADSPA_PORT_CONTROL, lval); + } else { + err = snd_pcm_ladspa_find_sport(&port, lplug, io->pdesc | LADSPA_PORT_CONTROL, id); + } + if (err < 0) { + SNDERR("Unable to find an control port (%s)", id); + return err; + } + if (snd_config_get_ireal(n, &dval) < 0) { + SNDERR("Control port %s has not an float or integer value", id); + return err; + } + err = snd_pcm_ladspa_find_port_idx(&uval, lplug, io->pdesc | LADSPA_PORT_CONTROL, port); + if (err < 0) { + SNDERR("internal error"); + return err; + } + io->controls_initialized[uval] = 1; + io->controls[uval] = (LADSPA_Data)dval; + } + + return 0; +} + +static int snd_pcm_ladspa_parse_bindings(snd_pcm_ladspa_plugin_t *lplug, + snd_pcm_ladspa_plugin_io_t *io, + snd_config_t *bindings) +{ + unsigned int count = 0; + unsigned int *array; + snd_config_iterator_t i, next; + int err; + + if (snd_config_get_type(bindings) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("bindings definition must be a compound"); + return -EINVAL; + } + snd_config_for_each(i, next, bindings) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long channel; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &channel); + if (err < 0 || channel < 0) { + SNDERR("Invalid channel number: %s", id); + return -EINVAL; + } + if (lplug->policy == SND_PCM_LADSPA_POLICY_DUPLICATE && channel > 0) { + SNDERR("Wrong channel specification for duplicate policy"); + return -EINVAL; + } + if (count < (unsigned int)(channel + 1)) + count = (unsigned int)(channel + 1); + } + if (count > 0) { + array = (unsigned int *)calloc(count, sizeof(unsigned int)); + if (! array) + return -ENOMEM; + memset(array, 0xff, count * sizeof(unsigned int)); + io->port_bindings_size = count; + io->port_bindings = array; + snd_config_for_each(i, next, bindings) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id, *sport; + long channel, port; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &channel); + if (err < 0 || channel < 0) { + assert(0); /* should never happen */ + return -EINVAL; + } + err = snd_config_get_integer(n, &port); + if (err >= 0) { + err = snd_pcm_ladspa_find_port(&array[channel], lplug, io->pdesc | LADSPA_PORT_AUDIO, port); + if (err < 0) { + SNDERR("Unable to find an audio port (%li) for channel %s", port, id); + return err; + } + continue; + } + err = snd_config_get_string(n, &sport); + if (err < 0) { + SNDERR("Invalid LADSPA port field type for %s", id); + return -EINVAL; + } + err = snd_pcm_ladspa_find_sport(&array[channel], lplug, io->pdesc | LADSPA_PORT_AUDIO, sport); + if (err < 0) { + SNDERR("Unable to find an audio port (%s) for channel %s", sport, id); + return err; + } + } + } + + return 0; +} + +static int snd_pcm_ladspa_parse_ioconfig(snd_pcm_ladspa_plugin_t *lplug, + snd_pcm_ladspa_plugin_io_t *io, + snd_config_t *conf) +{ + snd_config_iterator_t i, next; + snd_config_t *bindings = NULL, *controls = NULL; + int err; + + /* always add default controls for both input and output */ + err = snd_pcm_ladspa_add_default_controls(lplug, io); + if (err < 0) { + SNDERR("error adding default controls"); + return err; + } + + if (conf == NULL) { + return 0; + } + + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("input or output definition must be a compound"); + return -EINVAL; + } + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "bindings") == 0) { + bindings = n; + continue; + } + if (strcmp(id, "controls") == 0) { + controls = n; + continue; + } + } + + /* ignore values of parameters for output controls */ + if (controls && !(io->pdesc & LADSPA_PORT_OUTPUT)) { + err = snd_pcm_ladspa_parse_controls(lplug, io, controls); + if (err < 0) + return err; + } + + if (bindings) { + err = snd_pcm_ladspa_parse_bindings(lplug, io, bindings); + if (err < 0) + return err; + } + + + return 0; +} + +static int snd_pcm_ladspa_add_plugin(struct list_head *list, + const char *path, + snd_config_t *plugin, + int reverse) +{ + snd_config_iterator_t i, next; + const char *label = NULL, *filename = NULL; + long ladspa_id = 0; + int err; + snd_pcm_ladspa_plugin_t *lplug; + snd_pcm_ladspa_policy_t policy = SND_PCM_LADSPA_POLICY_DUPLICATE; + snd_config_t *input = NULL, *output = NULL; + + snd_config_for_each(i, next, plugin) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "label") == 0) { + err = snd_config_get_string(n, &label); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "id") == 0) { + err = snd_config_get_integer(n, &ladspa_id); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "filename") == 0) { + err = snd_config_get_string(n, &filename); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "input") == 0) { + input = n; + continue; + } + if (strcmp(id, "output") == 0) { + output = n; + continue; + } + if (strcmp(id, "policy") == 0) { + const char *str; + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("policy field must be a string"); + return err; + } + if (strcmp(str, "none") == 0) + policy = SND_PCM_LADSPA_POLICY_NONE; + else if (strcmp(str, "duplicate") == 0) + policy = SND_PCM_LADSPA_POLICY_DUPLICATE; + else { + SNDERR("unknown policy definition"); + return -EINVAL; + } + continue; + } + } + if (label == NULL && ladspa_id <= 0) { + SNDERR("no plugin label or id"); + return -EINVAL; + } + lplug = (snd_pcm_ladspa_plugin_t *)calloc(1, sizeof(snd_pcm_ladspa_plugin_t)); + if (lplug == NULL) + return -ENOMEM; + lplug->policy = policy; + lplug->input.pdesc = LADSPA_PORT_INPUT; + lplug->output.pdesc = LADSPA_PORT_OUTPUT; + INIT_LIST_HEAD(&lplug->instances); + if (filename) { + err = snd_pcm_ladspa_check_file(lplug, filename, label, ladspa_id); + if (err < 0) { + SNDERR("Unable to load plugin '%s' ID %li, filename '%s'", label, ladspa_id, filename); + free(lplug); + return err; + } + } else { + err = snd_pcm_ladspa_look_for_plugin(lplug, path, label, ladspa_id); + if (err < 0) { + SNDERR("Unable to find or load plugin '%s' ID %li, path '%s'", label, ladspa_id, path); + free(lplug); + return err; + } + } + if (!reverse) { + list_add_tail(&lplug->list, list); + } else { + list_add(&lplug->list, list); + } + err = snd_pcm_ladspa_parse_ioconfig(lplug, &lplug->input, input); + if (err < 0) + return err; + err = snd_pcm_ladspa_parse_ioconfig(lplug, &lplug->output, output); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_ladspa_build_plugins(struct list_head *list, + const char *path, + snd_config_t *plugins, + int reverse) +{ + snd_config_iterator_t i, next; + int idx = 0, hit, err; + + if (plugins == NULL) /* nothing TODO */ + return 0; + if (snd_config_get_type(plugins) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("plugins must be defined inside a compound"); + return -EINVAL; + } + do { + hit = 0; + snd_config_for_each(i, next, plugins) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long i; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not an integer", id); + return err; + } + if (i == idx) { + idx++; + err = snd_pcm_ladspa_add_plugin(list, path, n, reverse); + if (err < 0) + return err; + hit = 1; + } + } + } while (hit); + if (list_empty(list)) { + SNDERR("empty plugin list is not accepted"); + return -EINVAL; + } + return 0; +} + +/** + * \brief Creates a new LADSPA<->ALSA Plugin + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param ladspa_path The path for LADSPA plugins + * \param channels Force input channel count to LADSPA plugin chain, 0 = no force (auto) + * \param ladspa_pplugins The playback configuration + * \param ladspa_cplugins The capture configuration + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, + const char *ladspa_path, + unsigned int channels, + snd_config_t *ladspa_pplugins, + snd_config_t *ladspa_cplugins, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_ladspa_t *ladspa; + int err, reverse = 0; + + assert(pcmp && (ladspa_pplugins || ladspa_cplugins) && slave); + + if (!ladspa_path && !(ladspa_path = getenv("LADSPA_PATH"))) + return -ENOENT; + ladspa = calloc(1, sizeof(snd_pcm_ladspa_t)); + if (!ladspa) + return -ENOMEM; + snd_pcm_plugin_init(&ladspa->plug); + ladspa->plug.init = snd_pcm_ladspa_init; + ladspa->plug.read = snd_pcm_ladspa_read_areas; + ladspa->plug.write = snd_pcm_ladspa_write_areas; + ladspa->plug.undo_read = snd_pcm_plugin_undo_read_generic; + ladspa->plug.undo_write = snd_pcm_plugin_undo_write_generic; + ladspa->plug.gen.slave = slave; + ladspa->plug.gen.close_slave = close_slave; + + INIT_LIST_HEAD(&ladspa->pplugins); + INIT_LIST_HEAD(&ladspa->cplugins); + ladspa->channels = channels; + + if (slave->stream == SND_PCM_STREAM_PLAYBACK) { + err = snd_pcm_ladspa_build_plugins(&ladspa->pplugins, ladspa_path, ladspa_pplugins, reverse); + if (err < 0) { + snd_pcm_ladspa_free(ladspa); + return err; + } + } + if (slave->stream == SND_PCM_STREAM_CAPTURE) { + if (ladspa_cplugins == ladspa_pplugins) + reverse = 1; + err = snd_pcm_ladspa_build_plugins(&ladspa->cplugins, ladspa_path, ladspa_cplugins, reverse); + if (err < 0) { + snd_pcm_ladspa_free(ladspa); + return err; + } + } + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_LADSPA, name, slave->stream, slave->mode); + if (err < 0) { + snd_pcm_ladspa_free(ladspa); + return err; + } + pcm->ops = &snd_pcm_ladspa_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = ladspa; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_ladpsa Plugin: LADSPA <-> ALSA + +This plugin allows to apply a set of LADPSA plugins. +The input and output format is always #SND_PCM_FORMAT_FLOAT (note: this type +can be either little or big-endian depending on architecture). + +The policy duplicate means that there must be only one binding definition for +channel zero. This definition is automatically duplicated for all channels. +If the LADSPA plugin has multiple audio inputs or outputs the policy duplicate +is automatically switched to policy none. + +The plugin serialization works as expected. You can eventually use more +channels (inputs / outputs) inside the LADPSA plugin chain than processed +in the ALSA plugin chain. If ALSA channel does not exist for given LADSPA +input audio port, zero samples are given to this LADSPA port. On the output +side (ALSA next plugin input), the valid channels are checked, too. +If specific ALSA channel does not exist, the LADSPA output port is +connected to a dummy sample area. + +Instances of LADSPA plugins are created dynamically. + +\code +pcm.name { + type ladspa # ALSA<->LADSPA PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + [channels INT] # count input channels (input to LADSPA plugin chain) + [path STR] # Path (directory) with LADSPA plugins + plugins | # Definition for both directions + playback_plugins | # Definition for playback direction + capture_plugins { # Definition for capture direction + N { # Configuration for LADPSA plugin N + [id INT] # LADSPA plugin ID (for example 1043) + [label STR] # LADSPA plugin label (for example 'delay_5s') + [filename STR] # Full filename of .so library with LADSPA plugin code + [policy STR] # Policy can be 'none' or 'duplicate' + input | output { + bindings { + C INT or STR # C - channel, INT - audio port index, STR - audio port name + } + controls { + # valid only in the input block + I INT or REAL # I - control port index, INT or REAL - control value + # or + STR INT or REAL # STR - control port name, INT or REAL - control value + } + } + } + } +} +\endcode + +\subsection pcm_plugins_ladspa_funcref Function reference + +
    +
  • snd_pcm_ladspa_open() +
  • _snd_pcm_ladspa_open() +
+ +*/ + +/** + * \brief Creates a new LADSPA<->ALSA PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with LADSPA<->ALSA PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + const char *path = NULL; + long channels = 0; + snd_config_t *plugins = NULL, *pplugins = NULL, *cplugins = NULL; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "path") == 0) { + snd_config_get_string(n, &path); + continue; + } + if (strcmp(id, "channels") == 0) { + snd_config_get_integer(n, &channels); + if (channels > 1024) + channels = 1024; + if (channels < 0) + channels = 0; + continue; + } + if (strcmp(id, "plugins") == 0) { + plugins = n; + continue; + } + if (strcmp(id, "playback_plugins") == 0) { + pplugins = n; + continue; + } + if (strcmp(id, "capture_plugins") == 0) { + cplugins = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + if (plugins) { + if (pplugins || cplugins) { + SNDERR("'plugins' definition cannot be combined with 'playback_plugins' or 'capture_plugins'"); + return -EINVAL; + } + pplugins = plugins; + cplugins = plugins; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_ladspa_open(pcmp, name, path, channels, pplugins, cplugins, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_ladspa_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c new file mode 100644 index 0000000..62eb398 --- /dev/null +++ b/src/pcm/pcm_lfloat.c @@ -0,0 +1,537 @@ +/** + * \file pcm/pcm_lfloat.c + * \ingroup PCM_Plugins + * \brief PCM Linear<->Float Conversion Plugin Interface + * \author Jaroslav Kysela + * \date 2001 + */ +/* + * PCM - Linear Integer <-> Linear Float conversion + * Copyright (c) 2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef DOC_HIDDEN + +typedef float float_t; +typedef double double_t; + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 91) +#define BUGGY_GCC +#endif + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_lfloat = ""; +#endif + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + unsigned int int32_idx; + unsigned int float32_idx; + snd_pcm_format_t sformat; + void (*func)(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int get32idx, unsigned int put32floatidx); +} snd_pcm_lfloat_t; + +int snd_pcm_lfloat_get_s32_index(snd_pcm_format_t format) +{ + int width, endian; + + switch (format) { + case SND_PCM_FORMAT_FLOAT_LE: + case SND_PCM_FORMAT_FLOAT_BE: + width = 32; + break; + case SND_PCM_FORMAT_FLOAT64_LE: + case SND_PCM_FORMAT_FLOAT64_BE: + width = 64; + break; + default: + return -EINVAL; + } +#ifdef SND_LITTLE_ENDIAN + endian = snd_pcm_format_big_endian(format); +#else + endian = snd_pcm_format_little_endian(format); +#endif + return ((width / 32)-1) * 2 + endian; +} + +int snd_pcm_lfloat_put_s32_index(snd_pcm_format_t format) +{ + return snd_pcm_lfloat_get_s32_index(format); +} + +#endif /* DOC_HIDDEN */ + +#ifndef BUGGY_GCC + +#ifndef DOC_HIDDEN + +void snd_pcm_lfloat_convert_integer_float(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int get32idx, unsigned int put32floatidx) +{ +#define GET32_LABELS +#define PUT32F_LABELS +#include "plugin_ops.h" +#undef PUT32F_LABELS +#undef GET32_LABELS + void *get32 = get32_labels[get32idx]; + void *put32float = put32float_labels[put32floatidx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + int32_t sample = 0; + snd_tmp_float_t tmp_float; + snd_tmp_double_t tmp_double; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + goto *get32; +#define GET32_END sample_loaded +#include "plugin_ops.h" +#undef GET32_END + sample_loaded: + goto *put32float; +#define PUT32F_END sample_put +#include "plugin_ops.h" +#undef PUT32F_END + sample_put: + src += src_step; + dst += dst_step; + } + } +} + +void snd_pcm_lfloat_convert_float_integer(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int put32idx, unsigned int get32floatidx) +{ +#define PUT32_LABELS +#define GET32F_LABELS +#include "plugin_ops.h" +#undef GET32F_LABELS +#undef PUT32_LABELS + void *put32 = put32_labels[put32idx]; + void *get32float = get32float_labels[get32floatidx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + int32_t sample = 0; + snd_tmp_float_t tmp_float; + snd_tmp_double_t tmp_double; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + goto *get32float; +#define GET32F_END sample_loaded +#include "plugin_ops.h" +#undef GET32F_END + sample_loaded: + goto *put32; +#define PUT32_END sample_put +#include "plugin_ops.h" +#undef PUT32_END + sample_put: + src += src_step; + dst += dst_step; + } + } +} + +#endif /* DOC_HIDDEN */ + +static int snd_pcm_lfloat_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_lfloat_t *lfloat = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + snd_pcm_format_mask_t lformat_mask = { SND_PCM_FMTBIT_LINEAR }; + snd_pcm_format_mask_t fformat_mask = { SND_PCM_FMTBIT_FLOAT }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + snd_pcm_format_linear(lfloat->sformat) ? + &fformat_mask : &lformat_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_lfloat_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_lfloat_t *lfloat = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, lfloat->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + return 0; +} + +static int snd_pcm_lfloat_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_lfloat_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_lfloat_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_lfloat_hw_refine_cprepare, + snd_pcm_lfloat_hw_refine_cchange, + snd_pcm_lfloat_hw_refine_sprepare, + snd_pcm_lfloat_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_lfloat_t *lfloat = pcm->private_data; + snd_pcm_t *slave = lfloat->plug.gen.slave; + snd_pcm_format_t src_format, dst_format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_lfloat_hw_refine_cchange, + snd_pcm_lfloat_hw_refine_sprepare, + snd_pcm_lfloat_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &src_format); + dst_format = slave->format; + } else { + src_format = slave->format; + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format); + } + if (snd_pcm_format_linear(src_format)) { + lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32); + lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format); + lfloat->func = snd_pcm_lfloat_convert_integer_float; + } else { + lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format); + lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format); + lfloat->func = snd_pcm_lfloat_convert_float_integer; + } + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_lfloat_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_lfloat_t *lfloat = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + lfloat->func(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, + lfloat->int32_idx, lfloat->float32_idx); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_lfloat_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_lfloat_t *lfloat = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + lfloat->func(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, + lfloat->int32_idx, lfloat->float32_idx); + *slave_sizep = size; + return size; +} + +static void snd_pcm_lfloat_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_lfloat_t *lfloat = pcm->private_data; + snd_output_printf(out, "Linear Integer <-> Linear Float conversion PCM (%s)\n", + snd_pcm_format_name(lfloat->sformat)); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(lfloat->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_lfloat_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_lfloat_hw_refine, + .hw_params = snd_pcm_lfloat_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_lfloat_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new linear conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_lfloat_t *lfloat; + int err; + assert(pcmp && slave); + if (snd_pcm_format_linear(sformat) != 1 && + snd_pcm_format_float(sformat) != 1) + return -EINVAL; + lfloat = calloc(1, sizeof(snd_pcm_lfloat_t)); + if (!lfloat) { + return -ENOMEM; + } + snd_pcm_plugin_init(&lfloat->plug); + lfloat->sformat = sformat; + lfloat->plug.read = snd_pcm_lfloat_read_areas; + lfloat->plug.write = snd_pcm_lfloat_write_areas; + lfloat->plug.undo_read = snd_pcm_plugin_undo_read_generic; + lfloat->plug.undo_write = snd_pcm_plugin_undo_write_generic; + lfloat->plug.gen.slave = slave; + lfloat->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_LINEAR_FLOAT, name, slave->stream, slave->mode); + if (err < 0) { + free(lfloat); + return err; + } + pcm->ops = &snd_pcm_lfloat_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = lfloat; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_lfloat Plugin: linear<->float + +This plugin converts linear to float samples and float to linear samples from master +linear<->float conversion PCM to given slave PCM. The channel count, format and rate must +match for both of them. + +\code +pcm.name { + type lfloat # Linear<->Float conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + format STR # Slave format + } +} +\endcode + +\subsection pcm_plugins_lfloat_funcref Function reference + +
    +
  • snd_pcm_lfloat_open() +
  • _snd_pcm_lfloat_open() +
+ +*/ + +/** + * \brief Creates a new linear<->float conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); + if (err < 0) + return err; + if (snd_pcm_format_linear(sformat) != 1 && + snd_pcm_format_float(sformat) != 1) { + snd_config_delete(sconf); + SNDERR("slave format is not linear integer or linear float"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_lfloat_open(pcmp, name, sformat, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_lfloat_open, SND_PCM_DLSYM_VERSION); +#endif + +#else /* BUGGY_GCC */ + +int snd_pcm_lfloat_open(snd_pcm_t **pcmp ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + snd_pcm_format_t sformat ATTRIBUTE_UNUSED, + snd_pcm_t *slave ATTRIBUTE_UNUSED, + int close_slave ATTRIBUTE_UNUSED) +{ + SNDERR("please, upgrade your GCC to use lfloat plugin"); + return -EINVAL; +} + +int _snd_pcm_lfloat_open(snd_pcm_t **pcmp ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf ATTRIBUTE_UNUSED, + snd_pcm_stream_t stream ATTRIBUTE_UNUSED, + int mode ATTRIBUTE_UNUSED) +{ + SNDERR("please, upgrade your GCC to use lfloat plugin"); + return -EINVAL; +} + +#endif /* BUGGY_GCC */ diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c new file mode 100644 index 0000000..e85dfaa --- /dev/null +++ b/src/pcm/pcm_linear.c @@ -0,0 +1,582 @@ +/** + * \file pcm/pcm_linear.c + * \ingroup PCM_Plugins + * \brief PCM Linear Conversion Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Linear conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_linear = ""; +#endif + +#ifndef DOC_HIDDEN +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + unsigned int use_getput; + unsigned int conv_idx; + unsigned int get_idx, put_idx; + snd_pcm_format_t sformat; +} snd_pcm_linear_t; +#endif + +#ifndef DOC_HIDDEN + +int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, + snd_pcm_format_t dst_format) +{ + int src_endian, dst_endian, sign, src_width, dst_width; + + sign = (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)); +#ifdef SND_LITTLE_ENDIAN + src_endian = snd_pcm_format_big_endian(src_format); + dst_endian = snd_pcm_format_big_endian(dst_format); +#else + src_endian = snd_pcm_format_little_endian(src_format); + dst_endian = snd_pcm_format_little_endian(dst_format); +#endif + + if (src_endian < 0) + src_endian = 0; + if (dst_endian < 0) + dst_endian = 0; + + src_width = snd_pcm_format_width(src_format) / 8 - 1; + dst_width = snd_pcm_format_width(dst_format) / 8 - 1; + + return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; +} + +int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) +{ + int sign, width, pwidth, endian; + sign = (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)); +#ifdef SND_LITTLE_ENDIAN + endian = snd_pcm_format_big_endian(src_format); +#else + endian = snd_pcm_format_little_endian(src_format); +#endif + if (endian < 0) + endian = 0; + pwidth = snd_pcm_format_physical_width(src_format); + width = snd_pcm_format_width(src_format); + if (pwidth == 24) { + switch (width) { + case 24: + width = 0; break; + case 20: + width = 1; break; + case 18: + default: + width = 2; break; + } + return width * 4 + endian * 2 + sign + 16; + } else { + width = width / 8 - 1; + return width * 4 + endian * 2 + sign; + } +} + +int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) +{ + return snd_pcm_linear_get_index(src_format, dst_format); +} + +int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) +{ + int sign, width, pwidth, endian; + sign = (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)); +#ifdef SND_LITTLE_ENDIAN + endian = snd_pcm_format_big_endian(dst_format); +#else + endian = snd_pcm_format_little_endian(dst_format); +#endif + if (endian < 0) + endian = 0; + pwidth = snd_pcm_format_physical_width(dst_format); + width = snd_pcm_format_width(dst_format); + if (pwidth == 24) { + switch (width) { + case 24: + width = 0; break; + case 20: + width = 1; break; + case 18: + default: + width = 2; break; + } + return width * 4 + endian * 2 + sign + 16; + } else { + width = width / 8 - 1; + return width * 4 + endian * 2 + sign; + } +} + +int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) +{ + int sign, width, pwidth, endian; + sign = (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)); +#ifdef SND_LITTLE_ENDIAN + endian = snd_pcm_format_big_endian(dst_format); +#else + endian = snd_pcm_format_little_endian(dst_format); +#endif + if (endian < 0) + endian = 0; + pwidth = snd_pcm_format_physical_width(dst_format); + width = snd_pcm_format_width(dst_format); + if (pwidth == 24) { + switch (width) { + case 24: + width = 0; break; + case 20: + width = 1; break; + case 18: + default: + width = 2; break; + } + return width * 4 + endian * 2 + sign + 16; + } else { + width = width / 8 - 1; + return width * 4 + endian * 2 + sign; + } +} + +void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int convidx) +{ +#define CONV_LABELS +#include "plugin_ops.h" +#undef CONV_LABELS + void *conv = conv_labels[convidx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + goto *conv; +#define CONV_END after +#include "plugin_ops.h" +#undef CONV_END + after: + src += src_step; + dst += dst_step; + } + } +} + +void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int get_idx, unsigned int put_idx) +{ +#define CONV24_LABELS +#include "plugin_ops.h" +#undef CONV24_LABELS + void *get = get32_labels[get_idx]; + void *put = put32_labels[put_idx]; + unsigned int channel; + u_int32_t sample = 0; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + goto *get; +#define CONV24_END after +#include "plugin_ops.h" +#undef CONV24_END + after: + src += src_step; + dst += dst_step; + } + } +} + +#endif /* DOC_HIDDEN */ + +static int snd_pcm_linear_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_linear_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_linear_t *linear = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, linear->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + return 0; +} + +static int snd_pcm_linear_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_linear_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_linear_hw_refine_cprepare, + snd_pcm_linear_hw_refine_cchange, + snd_pcm_linear_hw_refine_sprepare, + snd_pcm_linear_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_linear_t *linear = pcm->private_data; + snd_pcm_format_t format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_linear_hw_refine_cchange, + snd_pcm_linear_hw_refine_sprepare, + snd_pcm_linear_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); + if (err < 0) + return err; + linear->use_getput = (snd_pcm_format_physical_width(format) == 24 || + snd_pcm_format_physical_width(linear->sformat) == 24); + if (linear->use_getput) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + linear->get_idx = snd_pcm_linear_get32_index(format, SND_PCM_FORMAT_S32); + linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, linear->sformat); + } else { + linear->get_idx = snd_pcm_linear_get32_index(linear->sformat, SND_PCM_FORMAT_S32); + linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, format); + } + } else { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + linear->conv_idx = snd_pcm_linear_convert_index(format, + linear->sformat); + else + linear->conv_idx = snd_pcm_linear_convert_index(linear->sformat, + format); + } + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_linear_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_linear_t *linear = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + if (linear->use_getput) + snd_pcm_linear_getput(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, + linear->get_idx, linear->put_idx); + else + snd_pcm_linear_convert(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, linear->conv_idx); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_linear_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_linear_t *linear = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + if (linear->use_getput) + snd_pcm_linear_getput(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, + linear->get_idx, linear->put_idx); + else + snd_pcm_linear_convert(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, linear->conv_idx); + *slave_sizep = size; + return size; +} + +static void snd_pcm_linear_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_linear_t *linear = pcm->private_data; + snd_output_printf(out, "Linear conversion PCM (%s)\n", + snd_pcm_format_name(linear->sformat)); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(linear->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_linear_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_linear_hw_refine, + .hw_params = snd_pcm_linear_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_linear_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + + +/** + * \brief Creates a new linear conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_linear_t *linear; + int err; + assert(pcmp && slave); + if (snd_pcm_format_linear(sformat) != 1) + return -EINVAL; + linear = calloc(1, sizeof(snd_pcm_linear_t)); + if (!linear) { + return -ENOMEM; + } + snd_pcm_plugin_init(&linear->plug); + linear->sformat = sformat; + linear->plug.read = snd_pcm_linear_read_areas; + linear->plug.write = snd_pcm_linear_write_areas; + linear->plug.undo_read = snd_pcm_plugin_undo_read_generic; + linear->plug.undo_write = snd_pcm_plugin_undo_write_generic; + linear->plug.gen.slave = slave; + linear->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_LINEAR, name, slave->stream, slave->mode); + if (err < 0) { + free(linear); + return err; + } + pcm->ops = &snd_pcm_linear_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = linear; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_linear Plugin: linear + +This plugin converts linear samples from master linear conversion PCM to given +slave PCM. The channel count, format and rate must match for both of them. + +\code +pcm.name { + type linear # Linear conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + format STR # Slave format + } +} +\endcode + +\subsection pcm_plugins_linear_funcref Function reference + +
    +
  • snd_pcm_linear_open() +
  • _snd_pcm_linear_open() +
+ +*/ + +/** + * \brief Creates a new linear conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); + if (err < 0) + return err; + if (snd_pcm_format_linear(sformat) != 1) { + snd_config_delete(sconf); + SNDERR("slave format is not linear"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_linear_open(pcmp, name, sformat, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_linear_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h new file mode 100644 index 0000000..2e901d5 --- /dev/null +++ b/src/pcm/pcm_local.h @@ -0,0 +1,972 @@ +/* + * PCM Interface - local header file + * Copyright (c) 2000 by Jaroslav Kysela + * Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#define _snd_mask sndrv_mask +#define _snd_pcm_access_mask _snd_mask +#define _snd_pcm_format_mask _snd_mask +#define _snd_pcm_subformat_mask _snd_mask + +#include "local.h" + +#define SND_INTERVAL_INLINE +#include "interval.h" + +#define SND_MASK_INLINE +#include "mask.h" + +typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t; +#define SND_PCM_HW_PARAM_ACCESS SNDRV_PCM_HW_PARAM_ACCESS +#define SND_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_FIRST_MASK +#define SND_PCM_HW_PARAM_FORMAT SNDRV_PCM_HW_PARAM_FORMAT +#define SND_PCM_HW_PARAM_SUBFORMAT SNDRV_PCM_HW_PARAM_SUBFORMAT +#define SND_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_LAST_MASK +#define SND_PCM_HW_PARAM_SAMPLE_BITS SNDRV_PCM_HW_PARAM_SAMPLE_BITS +#define SND_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_FIRST_INTERVAL +#define SND_PCM_HW_PARAM_FRAME_BITS SNDRV_PCM_HW_PARAM_FRAME_BITS +#define SND_PCM_HW_PARAM_CHANNELS SNDRV_PCM_HW_PARAM_CHANNELS +#define SND_PCM_HW_PARAM_RATE SNDRV_PCM_HW_PARAM_RATE +#define SND_PCM_HW_PARAM_PERIOD_TIME SNDRV_PCM_HW_PARAM_PERIOD_TIME +#define SND_PCM_HW_PARAM_PERIOD_SIZE SNDRV_PCM_HW_PARAM_PERIOD_SIZE +#define SND_PCM_HW_PARAM_PERIOD_BYTES SNDRV_PCM_HW_PARAM_PERIOD_BYTES +#define SND_PCM_HW_PARAM_PERIODS SNDRV_PCM_HW_PARAM_PERIODS +#define SND_PCM_HW_PARAM_BUFFER_TIME SNDRV_PCM_HW_PARAM_BUFFER_TIME +#define SND_PCM_HW_PARAM_BUFFER_SIZE SNDRV_PCM_HW_PARAM_BUFFER_SIZE +#define SND_PCM_HW_PARAM_BUFFER_BYTES SNDRV_PCM_HW_PARAM_BUFFER_BYTES +#define SND_PCM_HW_PARAM_TICK_TIME SNDRV_PCM_HW_PARAM_TICK_TIME +#define SND_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_LAST_INTERVAL +#define SND_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_LAST_MASK +#define SND_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_FIRST_MASK +#define SND_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_LAST_INTERVAL +#define SND_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + +/** device accepts mmaped access */ +#define SND_PCM_INFO_MMAP SNDRV_PCM_INFO_MMAP +/** device accepts mmaped access with sample resolution */ +#define SND_PCM_INFO_MMAP_VALID SNDRV_PCM_INFO_MMAP_VALID +/** device is doing double buffering */ +#define SND_PCM_INFO_DOUBLE SNDRV_PCM_INFO_DOUBLE +/** device transfers samples in batch */ +#define SND_PCM_INFO_BATCH SNDRV_PCM_INFO_BATCH +/** device accepts interleaved samples */ +#define SND_PCM_INFO_INTERLEAVED SNDRV_PCM_INFO_INTERLEAVED +/** device accepts non-interleaved samples */ +#define SND_PCM_INFO_NONINTERLEAVED SNDRV_PCM_INFO_NONINTERLEAVED +/** device accepts complex sample organization */ +#define SND_PCM_INFO_COMPLEX SNDRV_PCM_INFO_COMPLEX +/** device is capable block transfers */ +#define SND_PCM_INFO_BLOCK_TRANSFER SNDRV_PCM_INFO_BLOCK_TRANSFER +/** device can detect DAC/ADC overrange */ +#define SND_PCM_INFO_OVERRANGE SNDRV_PCM_INFO_OVERRANGE +/** device supports resume */ +#define SND_PCM_INFO_RESUME SNDRV_PCM_INFO_RESUME +/** device is capable to pause */ +#define SND_PCM_INFO_PAUSE SNDRV_PCM_INFO_PAUSE +/** device can do only half duplex */ +#define SND_PCM_INFO_HALF_DUPLEX SNDRV_PCM_INFO_HALF_DUPLEX +/** device can do only joint duplex (same parameters) */ +#define SND_PCM_INFO_JOINT_DUPLEX SNDRV_PCM_INFO_JOINT_DUPLEX +/** device can do a kind of synchronized start */ +#define SND_PCM_INFO_SYNC_START SNDRV_PCM_INFO_SYNC_START +/** device can disable period wakeups */ +#define SND_PCM_INFO_NO_PERIOD_WAKEUP SNDRV_PCM_INFO_NO_PERIOD_WAKEUP + +#define SND_PCM_HW_PARAMS_NORESAMPLE SNDRV_PCM_HW_PARAMS_NORESAMPLE +#define SND_PCM_HW_PARAMS_EXPORT_BUFFER SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER +#define SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP + +#define SND_PCM_INFO_MONOTONIC 0x80000000 + +typedef struct _snd_pcm_rbptr { + snd_pcm_t *master; + volatile snd_pcm_uframes_t *ptr; + int fd; + off_t offset; + int link_dst_count; + snd_pcm_t **link_dst; + void *private_data; + void (*changed)(snd_pcm_t *pcm, snd_pcm_t *src); +} snd_pcm_rbptr_t; + +typedef struct _snd_pcm_channel_info { + unsigned int channel; + void *addr; /* base address of channel samples */ + unsigned int first; /* offset to first sample in bits */ + unsigned int step; /* samples distance in bits */ + enum { SND_PCM_AREA_SHM, SND_PCM_AREA_MMAP, SND_PCM_AREA_LOCAL } type; + union { + struct { + struct snd_shm_area *area; + int shmid; + } shm; + struct { + int fd; + off_t offset; + } mmap; + } u; + char reserved[64]; +} snd_pcm_channel_info_t; + +typedef struct { + int (*close)(snd_pcm_t *pcm); + int (*nonblock)(snd_pcm_t *pcm, int nonblock); + int (*async)(snd_pcm_t *pcm, int sig, pid_t pid); + int (*info)(snd_pcm_t *pcm, snd_pcm_info_t *info); + int (*hw_refine)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + int (*hw_params)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + int (*hw_free)(snd_pcm_t *pcm); + int (*sw_params)(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); + int (*channel_info)(snd_pcm_t *pcm, snd_pcm_channel_info_t *info); + void (*dump)(snd_pcm_t *pcm, snd_output_t *out); + int (*mmap)(snd_pcm_t *pcm); + int (*munmap)(snd_pcm_t *pcm); +} snd_pcm_ops_t; + +typedef struct { + int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status); + int (*prepare)(snd_pcm_t *pcm); + int (*reset)(snd_pcm_t *pcm); + int (*start)(snd_pcm_t *pcm); + int (*drop)(snd_pcm_t *pcm); + int (*drain)(snd_pcm_t *pcm); + int (*pause)(snd_pcm_t *pcm, int enable); + snd_pcm_state_t (*state)(snd_pcm_t *pcm); + int (*hwsync)(snd_pcm_t *pcm); + int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); + int (*resume)(snd_pcm_t *pcm); + int (*link)(snd_pcm_t *pcm1, snd_pcm_t *pcm2); + int (*link_slaves)(snd_pcm_t *pcm, snd_pcm_t *master); + int (*unlink)(snd_pcm_t *pcm); + snd_pcm_sframes_t (*rewindable)(snd_pcm_t *pcm); + snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); + snd_pcm_sframes_t (*forwardable)(snd_pcm_t *pcm); + snd_pcm_sframes_t (*forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); + snd_pcm_sframes_t (*writei)(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); + snd_pcm_sframes_t (*writen)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); + snd_pcm_sframes_t (*readi)(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); + snd_pcm_sframes_t (*readn)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); + snd_pcm_sframes_t (*avail_update)(snd_pcm_t *pcm); + snd_pcm_sframes_t (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size); + int (*htimestamp)(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, snd_htimestamp_t *tstamp); + int (*poll_descriptors_count)(snd_pcm_t *pcm); + int (*poll_descriptors)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); + int (*poll_revents)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +} snd_pcm_fast_ops_t; + +struct _snd_pcm { + void *open_func; + char *name; + snd_pcm_type_t type; + snd_pcm_stream_t stream; + int mode; + long minperiodtime; /* in us */ + int poll_fd_count; + int poll_fd; + unsigned short poll_events; + int setup: 1, + monotonic: 1, + compat: 1; + snd_pcm_access_t access; /* access mode */ + snd_pcm_format_t format; /* SND_PCM_FORMAT_* */ + snd_pcm_subformat_t subformat; /* subformat */ + unsigned int channels; /* channels */ + unsigned int rate; /* rate in Hz */ + snd_pcm_uframes_t period_size; + unsigned int period_time; /* period duration */ + snd_interval_t periods; + snd_pcm_tstamp_t tstamp_mode; /* timestamp mode */ + unsigned int period_step; + snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + int period_event; + snd_pcm_uframes_t start_threshold; + snd_pcm_uframes_t stop_threshold; + snd_pcm_uframes_t silence_threshold; /* Silence filling happens when + noise is nearest than this */ + snd_pcm_uframes_t silence_size; /* Silence filling size */ + snd_pcm_uframes_t boundary; /* pointers wrap point */ + unsigned int info; /* Info for returned setup */ + unsigned int msbits; /* used most significant bits */ + unsigned int rate_num; /* rate numerator */ + unsigned int rate_den; /* rate denominator */ + unsigned int hw_flags; /* actual hardware flags */ + snd_pcm_uframes_t fifo_size; /* chip FIFO size in frames */ + snd_pcm_uframes_t buffer_size; + snd_interval_t buffer_time; + unsigned int sample_bits; + unsigned int frame_bits; + snd_pcm_rbptr_t appl; + snd_pcm_rbptr_t hw; + snd_pcm_uframes_t min_align; + unsigned int mmap_rw: 1; /* use always mmapped buffer */ + unsigned int mmap_shadow: 1; /* don't call actual mmap, + * use the mmaped buffer of the slave + */ + unsigned int donot_close: 1; /* don't close this PCM */ + snd_pcm_channel_info_t *mmap_channels; + snd_pcm_channel_area_t *running_areas; + snd_pcm_channel_area_t *stopped_areas; + const snd_pcm_ops_t *ops; + const snd_pcm_fast_ops_t *fast_ops; + snd_pcm_t *op_arg; + snd_pcm_t *fast_op_arg; + void *private_data; + struct list_head async_handlers; +}; + +/* make local functions really local */ +/* Grrr, these cannot be local - a bad aserver uses them! +#define snd_pcm_async \ + snd1_pcm_async +#define snd_pcm_mmap \ + snd1_pcm_mmap +#define snd_pcm_munmap \ + snd1_pcm_munmap +#define snd_pcm_hw_refine \ + snd1_pcm_hw_refine +*/ +#define snd_pcm_new \ + snd1_pcm_new +#define snd_pcm_free \ + snd1_pcm_free +#define snd_pcm_areas_from_buf \ + snd1_pcm_areas_from_buf +#define snd_pcm_areas_from_bufs \ + snd1_pcm_areas_from_bufs +#define snd_pcm_open_named_slave \ + snd1_pcm_open_named_slave +#define snd_pcm_conf_generic_id \ + snd1_pcm_conf_generic_id +#define snd_pcm_hw_open_fd \ + snd1_pcm_hw_open_fd +#define snd_pcm_wait_nocheck \ + snd1_pcm_wait_nocheck +#define snd_pcm_rate_get_default_converter \ + snd1_pcm_rate_get_default_converter +#define snd_pcm_set_hw_ptr \ + snd1_pcm_set_hw_ptr +#define snd_pcm_set_appl_ptr \ + snd1_pcm_set_appl_ptr +#define snd_pcm_link_hw_ptr \ + snd1_pcm_link_hw_ptr +#define snd_pcm_link_appl_ptr \ + snd1_pcm_link_appl_ptr +#define snd_pcm_unlink_hw_ptr \ + snd1_pcm_unlink_hw_ptr +#define snd_pcm_unlink_appl_ptr \ + snd1_pcm_unlink_appl_ptr +#define snd_pcm_mmap_appl_ptr \ + snd1_pcm_mmap_appl_ptr +#define snd_pcm_mmap_appl_backward \ + snd1_pcm_mmap_appl_backward +#define snd_pcm_mmap_appl_forward \ + snd1_pcm_mmap_appl_forward +#define snd_pcm_mmap_hw_backward \ + snd1_pcm_mmap_hw_backward +#define snd_pcm_mmap_hw_forward \ + snd1_pcm_mmap_hw_forward +#define snd_pcm_read_areas \ + snd1_pcm_read_areas +#define snd_pcm_write_areas \ + snd1_pcm_write_areas +#define snd_pcm_read_mmap \ + snd1_pcm_read_mmap +#define snd_pcm_write_mmap \ + snd1_pcm_write_mmap +#define snd_pcm_channel_info_shm \ + snd1_pcm_channel_info_shm +#define snd_pcm_hw_refine_soft \ + snd1_pcm_hw_refine_soft +#define snd_pcm_hw_refine_slave \ + snd1_pcm_hw_refine_slave +#define snd_pcm_hw_params_slave \ + snd1_pcm_hw_params_slave +#define snd_pcm_hw_param_refine_near \ + snd1_pcm_hw_param_refine_near +#define snd_pcm_hw_param_refine_multiple \ + snd1_pcm_hw_param_refine_multiple +#define snd_pcm_hw_param_empty \ + snd1_pcm_hw_param_empty +#define snd_pcm_hw_param_always_eq \ + snd1_pcm_hw_param_always_eq +#define snd_pcm_hw_param_never_eq \ + snd1_pcm_hw_param_never_eq +#define snd_pcm_hw_param_get_mask \ + snd1_pcm_hw_param_get_mask +#define snd_pcm_hw_param_get_interval \ + snd1_pcm_hw_param_get_interval +#define snd_pcm_hw_param_any \ + snd1_pcm_hw_param_any +#define snd_pcm_hw_param_set_integer \ + snd1_pcm_hw_param_set_integer +#define snd_pcm_hw_param_set_first \ + snd1_pcm_hw_param_set_first +#define snd_pcm_hw_param_set_last \ + snd1_pcm_hw_param_set_last +#define snd_pcm_hw_param_set_near \ + snd1_pcm_hw_param_set_near +#define snd_pcm_hw_param_set_min \ + snd1_pcm_hw_param_set_min +#define snd_pcm_hw_param_set_max \ + snd1_pcm_hw_param_set_max +#define snd_pcm_hw_param_set_minmax \ + snd1_pcm_hw_param_set_minmax +#define snd_pcm_hw_param_set \ + snd1_pcm_hw_param_set +#define snd_pcm_hw_param_set_mask \ + snd1_pcm_hw_param_set_mask +#define snd_pcm_hw_param_get \ + snd1_pcm_hw_param_get +#define snd_pcm_hw_param_get_min \ + snd1_pcm_hw_param_get_min +#define snd_pcm_hw_param_get_max \ + snd1_pcm_hw_param_get_max +#define snd_pcm_hw_param_name \ + snd1_pcm_hw_param_name + +int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, + snd_pcm_stream_t stream, int mode); +int snd_pcm_free(snd_pcm_t *pcm); + +void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf); +void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs); + +int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid); +int snd_pcm_mmap(snd_pcm_t *pcm); +int snd_pcm_munmap(snd_pcm_t *pcm); +int snd_pcm_mmap_ready(snd_pcm_t *pcm); +void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset); +void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr, int fd, off_t offset); +void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave); +void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave); +void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave); +void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave); +snd_pcm_sframes_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset); +void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); + +snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); + +typedef snd_pcm_sframes_t (*snd_pcm_xfer_areas_func_t)(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size); + +snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size, + snd_pcm_xfer_areas_func_t func); +snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, snd_pcm_uframes_t size, + snd_pcm_xfer_areas_func_t func); +snd_pcm_sframes_t snd_pcm_read_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t offset, + snd_pcm_uframes_t size); +snd_pcm_sframes_t snd_pcm_write_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t offset, + snd_pcm_uframes_t size); +static inline int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) +{ + return pcm->ops->channel_info(pcm, info); +} +int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid); +int _snd_pcm_poll_descriptor(snd_pcm_t *pcm); +#define _snd_pcm_link_descriptor _snd_pcm_poll_descriptor /* FIXME */ +#define _snd_pcm_async_descriptor _snd_pcm_poll_descriptor /* FIXME */ + +/* handle special error cases */ +static inline int snd_pcm_check_error(snd_pcm_t *pcm, int err) +{ + if (err == -EINTR) { + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + break; + } + } + return err; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t avail; + avail = *pcm->hw.ptr + pcm->buffer_size - *pcm->appl.ptr; + if (avail < 0) + avail += pcm->boundary; + else if ((snd_pcm_uframes_t) avail >= pcm->boundary) + avail -= pcm->boundary; + return avail; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t avail; + avail = *pcm->hw.ptr - *pcm->appl.ptr; + if (avail < 0) + avail += pcm->boundary; + return avail; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_avail(snd_pcm_t *pcm) +{ + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + return snd_pcm_mmap_playback_avail(pcm); + else + return snd_pcm_mmap_capture_avail(pcm); +} + +static inline snd_pcm_sframes_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm) +{ + return pcm->buffer_size - snd_pcm_mmap_playback_avail(pcm); +} + +static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm) +{ + return pcm->buffer_size - snd_pcm_mmap_capture_avail(pcm); +} + +static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t avail; + avail = *pcm->hw.ptr - *pcm->appl.ptr; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + avail += pcm->buffer_size; + if (avail < 0) + avail += pcm->boundary; + return pcm->buffer_size - avail; +} + +static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm) +{ + if (pcm->stopped_areas && + snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING) + return pcm->stopped_areas; + return pcm->running_areas; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_offset(snd_pcm_t *pcm) +{ + assert(pcm); + return *pcm->appl.ptr % pcm->buffer_size; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm) +{ + assert(pcm); + return *pcm->hw.ptr % pcm->buffer_size; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_playback_delay(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_playback_hw_avail(pcm); +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_capture_delay(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_capture_hw_avail(pcm); +} + +static inline snd_pcm_sframes_t snd_pcm_mmap_delay(snd_pcm_t *pcm) +{ + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + return snd_pcm_mmap_playback_delay(pcm); + else + return snd_pcm_mmap_capture_delay(pcm); +} + +static inline void *snd_pcm_channel_area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset) +{ + unsigned int bitofs = area->first + area->step * offset; + assert(bitofs % 8 == 0); + return (char *) area->addr + bitofs / 8; +} + +static inline unsigned int snd_pcm_channel_area_step(const snd_pcm_channel_area_t *area) +{ + assert(area->step % 8 == 0); + return area->step / 8; +} + +static inline snd_pcm_sframes_t _snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + return pcm->fast_ops->writei(pcm->fast_op_arg, buffer, size); +} + +static inline snd_pcm_sframes_t _snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + return pcm->fast_ops->writen(pcm->fast_op_arg, bufs, size); +} + +static inline snd_pcm_sframes_t _snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + return pcm->fast_ops->readi(pcm->fast_op_arg, buffer, size); +} + +static inline snd_pcm_sframes_t _snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + return pcm->fast_ops->readn(pcm->fast_op_arg, bufs, size); +} + +static inline int muldiv(int a, int b, int c, int *r) +{ + int64_t n = (int64_t)a * b; + int64_t v = n / c; + if (v > INT_MAX) { + *r = 0; + return INT_MAX; + } + if (v < INT_MIN) { + *r = 0; + return INT_MIN; + } + *r = n % c; + return v; +} + +static inline int muldiv_down(int a, int b, int c) +{ + int64_t v = (int64_t)a * b / c; + if (v > INT_MAX) { + return INT_MAX; + } + if (v < INT_MIN) { + return INT_MIN; + } + return v; +} + +static inline int muldiv_near(int a, int b, int c) +{ + int r; + int n = muldiv(a, b, c, &r); + if (r >= (c + 1) / 2) + n++; + return n; +} + +int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int _snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_refine_soft(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*srefine)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)); +int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sparams)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)); + + +void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params); +void _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); +int _snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_interval_t *val); +int _snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, const snd_mask_t *mask); +int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); +int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); +int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, int dir); +static inline int _snd_pcm_hw_params_set_format(snd_pcm_hw_params_t *params, + snd_pcm_format_t val) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, + (unsigned long) val, 0); +} + +static inline int _snd_pcm_hw_params_set_subformat(snd_pcm_hw_params_t *params, + snd_pcm_subformat_t val) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT, + (unsigned long) val, 0); +} + +int _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, int dir); +int _snd_pcm_hw_param_set_max(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, int dir); +int _snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int min, int mindir, + unsigned int max, int maxdir); +int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src); +int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, + unsigned int vars, + const snd_pcm_hw_params_t *src); +int snd_pcm_hw_param_refine_near(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src); +int snd_pcm_hw_param_refine_multiple(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src); +int snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); +int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *params1); +int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *params1); +const snd_mask_t *snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); +const snd_interval_t *snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); + +int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var); +int snd_pcm_hw_param_set_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var); +int snd_pcm_hw_param_set_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int *rval, int *dir); +int snd_pcm_hw_param_set_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int *rval, int *dir); +int snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int *val, int *dir); +int snd_pcm_hw_param_set_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, + unsigned int *val, int *dir); +int snd_pcm_hw_param_set_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, unsigned int *val, int *dir); +int snd_pcm_hw_param_set_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, + unsigned int *min, int *mindir, + unsigned int *max, int *maxdir); +int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, unsigned int val, int dir); +int snd_pcm_hw_param_set_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, const snd_mask_t *mask); +int snd_pcm_hw_param_get(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, + unsigned int *val, int *dir); +int snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int *val, int *dir); +int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int *val, int *dir); + +#ifdef INTERNAL +snd_pcm_sframes_t INTERNAL(snd_pcm_forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); + +int INTERNAL(snd_pcm_hw_params_get_access)(const snd_pcm_hw_params_t *params, snd_pcm_access_t *access); +int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); +int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); +int INTERNAL(snd_pcm_hw_params_set_access_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *access); +int INTERNAL(snd_pcm_hw_params_set_access_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *access); +int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); +int snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); + +int INTERNAL(snd_pcm_hw_params_get_format)(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val); +int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); +int INTERNAL(snd_pcm_hw_params_set_format_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); +int INTERNAL(snd_pcm_hw_params_set_format_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); +int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); +void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); + +int INTERNAL(snd_pcm_hw_params_get_subformat)(const snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); +int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat); +int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat); +int INTERNAL(snd_pcm_hw_params_set_subformat_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); +int INTERNAL(snd_pcm_hw_params_set_subformat_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); +int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); +void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); + +int INTERNAL(snd_pcm_hw_params_get_channels)(const snd_pcm_hw_params_t *params, unsigned int *val); +int INTERNAL(snd_pcm_hw_params_get_channels_min)(const snd_pcm_hw_params_t *params, unsigned int *val); +int INTERNAL(snd_pcm_hw_params_get_channels_max)(const snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); +int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max); +int INTERNAL(snd_pcm_hw_params_set_channels_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int INTERNAL(snd_pcm_hw_params_set_channels_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); +int INTERNAL(snd_pcm_hw_params_set_channels_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); + +int INTERNAL(snd_pcm_hw_params_get_rate)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_rate_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_rate_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int INTERNAL(snd_pcm_hw_params_set_rate_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_rate_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_rate_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); + +int INTERNAL(snd_pcm_hw_params_get_period_time)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_period_time_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_period_time_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int INTERNAL(snd_pcm_hw_params_set_period_time_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_period_time_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_period_time_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); + +int INTERNAL(snd_pcm_hw_params_get_period_size)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); +int INTERNAL(snd_pcm_hw_params_get_period_size_min)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); +int INTERNAL(snd_pcm_hw_params_get_period_size_max)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); +int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir); +int INTERNAL(snd_pcm_hw_params_set_period_size_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_period_size_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_period_size_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); +int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +int INTERNAL(snd_pcm_hw_params_get_periods)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_periods_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_periods_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int INTERNAL(snd_pcm_hw_params_set_periods_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_periods_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_periods_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); + +int INTERNAL(snd_pcm_hw_params_get_buffer_time)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_buffer_time_min)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_get_buffer_time_max)(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); +int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); +int INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_buffer_time_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +int INTERNAL(snd_pcm_hw_params_set_buffer_time_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); + +int INTERNAL(snd_pcm_hw_params_get_buffer_size)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int INTERNAL(snd_pcm_hw_params_get_buffer_size_min)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int INTERNAL(snd_pcm_hw_params_get_buffer_size_max)(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max); +int INTERNAL(snd_pcm_hw_params_set_buffer_size_near)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int INTERNAL(snd_pcm_hw_params_set_buffer_size_first)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); +int INTERNAL(snd_pcm_hw_params_set_buffer_size_last)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); + +int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val); +int INTERNAL(snd_pcm_sw_params_get_tstamp_mode)(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val); +int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int INTERNAL(snd_pcm_sw_params_get_avail_min)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int INTERNAL(snd_pcm_sw_params_get_start_threshold)(const snd_pcm_sw_params_t *paramsm, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int INTERNAL(snd_pcm_sw_params_get_stop_threshold)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int INTERNAL(snd_pcm_sw_params_get_silence_threshold)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); +int INTERNAL(snd_pcm_sw_params_get_silence_size)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); +#endif /* INTERNAL */ + +const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param); +void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, snd_output_t *out); +#if 0 +int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy, int order, + snd_pcm_hw_param_t var, + unsigned int best, + unsigned int mul); +int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, int order, + snd_pcm_hw_param_t var, + unsigned int count, + snd_pcm_hw_strategy_simple_choices_list_t *choices); +#endif + +#define SCONF_MANDATORY 1 +#define SCONF_UNCHANGED 2 + +int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf, + snd_config_t **pcm_conf, unsigned int count, ...); + +#define SND_PCM_APPEND (1<<8) + +int snd_pcm_open_named_slave(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, + snd_config_t *conf, snd_pcm_stream_t stream, + int mode, snd_config_t *parent_conf); +static inline int +snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, + snd_config_t *conf, snd_pcm_stream_t stream, + int mode, snd_config_t *parent_conf) +{ + return snd_pcm_open_named_slave(pcmp, NULL, root, conf, stream, + mode, parent_conf); +} +int snd_pcm_conf_generic_id(const char *id); + +int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl); +int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_t *slave, int close_slave); + +int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout); + +const snd_config_t *snd_pcm_rate_get_default_converter(snd_config_t *root); + +#define SND_PCM_HW_PARBIT_ACCESS (1U << SND_PCM_HW_PARAM_ACCESS) +#define SND_PCM_HW_PARBIT_FORMAT (1U << SND_PCM_HW_PARAM_FORMAT) +#define SND_PCM_HW_PARBIT_SUBFORMAT (1U << SND_PCM_HW_PARAM_SUBFORMAT) +#define SND_PCM_HW_PARBIT_CHANNELS (1U << SND_PCM_HW_PARAM_CHANNELS) +#define SND_PCM_HW_PARBIT_RATE (1U << SND_PCM_HW_PARAM_RATE) +#define SND_PCM_HW_PARBIT_PERIOD_TIME (1U << SND_PCM_HW_PARAM_PERIOD_TIME) +#define SND_PCM_HW_PARBIT_PERIOD_SIZE (1U << SND_PCM_HW_PARAM_PERIOD_SIZE) +#define SND_PCM_HW_PARBIT_PERIODS (1U << SND_PCM_HW_PARAM_PERIODS) +#define SND_PCM_HW_PARBIT_BUFFER_TIME (1U << SND_PCM_HW_PARAM_BUFFER_TIME) +#define SND_PCM_HW_PARBIT_BUFFER_SIZE (1U << SND_PCM_HW_PARAM_BUFFER_SIZE) +#define SND_PCM_HW_PARBIT_SAMPLE_BITS (1U << SND_PCM_HW_PARAM_SAMPLE_BITS) +#define SND_PCM_HW_PARBIT_FRAME_BITS (1U << SND_PCM_HW_PARAM_FRAME_BITS) +#define SND_PCM_HW_PARBIT_PERIOD_BYTES (1U << SND_PCM_HW_PARAM_PERIOD_BYTES) +#define SND_PCM_HW_PARBIT_BUFFER_BYTES (1U << SND_PCM_HW_PARAM_BUFFER_BYTES) +#define SND_PCM_HW_PARBIT_TICK_TIME (1U << SND_PCM_HW_PARAM_TICK_TIME) + + +#define SND_PCM_ACCBIT_MMAP { ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \ + (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \ + (1U << SND_PCM_ACCESS_MMAP_COMPLEX)) } +#define SND_PCM_ACCBIT_MMAPI { (1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) } +#define SND_PCM_ACCBIT_MMAPN { (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) } +#define SND_PCM_ACCBIT_MMAPC { (1U << SND_PCM_ACCESS_MMAP_COMPLEX) } + +#define SND_PCM_ACCBIT_SHM { ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \ + (1U << SND_PCM_ACCESS_RW_INTERLEAVED) | \ + (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \ + (1U << SND_PCM_ACCESS_RW_NONINTERLEAVED)) } +#define SND_PCM_ACCBIT_SHMI { ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \ + (1U << SND_PCM_ACCESS_RW_INTERLEAVED)) } +#define SND_PCM_ACCBIT_SHMN { ((1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \ + (1U << SND_PCM_ACCESS_RW_NONINTERLEAVED)) } + +#define SND_PCM_FMTBIT_LINEAR \ + { ((1U << SND_PCM_FORMAT_S8) | \ + (1U << SND_PCM_FORMAT_U8) | \ + (1U << SND_PCM_FORMAT_S16_LE) | \ + (1U << SND_PCM_FORMAT_S16_BE) | \ + (1U << SND_PCM_FORMAT_U16_LE) | \ + (1U << SND_PCM_FORMAT_U16_BE) | \ + (1U << SND_PCM_FORMAT_S24_LE) | \ + (1U << SND_PCM_FORMAT_S24_BE) | \ + (1U << SND_PCM_FORMAT_U24_LE) | \ + (1U << SND_PCM_FORMAT_U24_BE) | \ + (1U << SND_PCM_FORMAT_S32_LE) | \ + (1U << SND_PCM_FORMAT_S32_BE) | \ + (1U << SND_PCM_FORMAT_U32_LE) | \ + (1U << SND_PCM_FORMAT_U32_BE)), \ + ((1U << (SND_PCM_FORMAT_S24_3LE - 32)) | \ + (1U << (SND_PCM_FORMAT_U24_3LE - 32)) | \ + (1U << (SND_PCM_FORMAT_S24_3BE - 32)) | \ + (1U << (SND_PCM_FORMAT_U24_3BE - 32)) | \ + (1U << (SND_PCM_FORMAT_S20_3LE - 32)) | \ + (1U << (SND_PCM_FORMAT_U20_3LE - 32)) | \ + (1U << (SND_PCM_FORMAT_S20_3BE - 32)) | \ + (1U << (SND_PCM_FORMAT_U20_3BE - 32)) | \ + (1U << (SND_PCM_FORMAT_S18_3LE - 32)) | \ + (1U << (SND_PCM_FORMAT_U18_3LE - 32)) | \ + (1U << (SND_PCM_FORMAT_S18_3BE - 32)) | \ + (1U << (SND_PCM_FORMAT_U18_3BE - 32))) } + + +#define SND_PCM_FMTBIT_FLOAT \ + { ((1U << SND_PCM_FORMAT_FLOAT_LE) | \ + (1U << SND_PCM_FORMAT_FLOAT_BE) | \ + (1U << SND_PCM_FORMAT_FLOAT64_LE) | \ + (1U << SND_PCM_FORMAT_FLOAT64_BE)) } + + +typedef union snd_tmp_float { + float f; + int32_t i; +} snd_tmp_float_t; + +typedef union snd_tmp_double { + double d; + int64_t l; +} snd_tmp_double_t; + +/* get the current timestamp */ +static inline void gettimestamp(snd_htimestamp_t *tstamp, int monotonic) +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + if (monotonic) { + clock_gettime(CLOCK_MONOTONIC, tstamp); + } else { +#endif + struct timeval tv; + + gettimeofday(&tv, 0); + tstamp->tv_sec = tv.tv_sec; + tstamp->tv_nsec = tv.tv_usec * 1000L; +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + } +#endif +} diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c new file mode 100644 index 0000000..5acc7bc --- /dev/null +++ b/src/pcm/pcm_meter.c @@ -0,0 +1,1228 @@ +/** + * \file pcm/pcm_meter.c + * \brief Helper functions for #SND_PCM_TYPE_METER PCM scopes + * \author Abramo Bagnara + * \date 2001 + * + * Helper functions for #SND_PCM_TYPE_METER PCM scopes + */ +/* + * PCM - Meter plugin + * Copyright (c) 2001 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include +#include +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" +#include "iatomic.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_meter = ""; +#endif + +#ifndef DOC_HIDDEN +#define FREQUENCY 50 + +struct _snd_pcm_scope { + int enabled; + char *name; + const snd_pcm_scope_ops_t *ops; + void *private_data; + struct list_head list; +}; + +typedef struct _snd_pcm_meter { + snd_pcm_generic_t gen; + snd_pcm_uframes_t rptr; + snd_pcm_uframes_t buf_size; + snd_pcm_channel_area_t *buf_areas; + snd_pcm_uframes_t now; + unsigned char *buf; + struct list_head scopes; + int closed; + int running; + atomic_t reset; + pthread_t thread; + pthread_mutex_t update_mutex; + pthread_mutex_t running_mutex; + pthread_cond_t running_cond; + struct timespec delay; + void *dl_handle; +} snd_pcm_meter_t; + +static void snd_pcm_meter_add_frames(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t ptr, + snd_pcm_uframes_t frames) +{ + snd_pcm_meter_t *meter = pcm->private_data; + while (frames > 0) { + snd_pcm_uframes_t n = frames; + snd_pcm_uframes_t dst_offset = ptr % meter->buf_size; + snd_pcm_uframes_t src_offset = ptr % pcm->buffer_size; + snd_pcm_uframes_t dst_cont = meter->buf_size - dst_offset; + snd_pcm_uframes_t src_cont = pcm->buffer_size - src_offset; + if (n > dst_cont) + n = dst_cont; + if (n > src_cont) + n = src_cont; + snd_pcm_areas_copy(meter->buf_areas, dst_offset, + areas, src_offset, + pcm->channels, n, pcm->format); + frames -= n; + ptr += n; + if (ptr == pcm->boundary) + ptr = 0; + } +} + +static void snd_pcm_meter_update_main(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t frames; + snd_pcm_uframes_t rptr, old_rptr; + const snd_pcm_channel_area_t *areas; + int locked; + locked = (pthread_mutex_trylock(&meter->update_mutex) >= 0); + areas = snd_pcm_mmap_areas(pcm); + rptr = *pcm->hw.ptr; + old_rptr = meter->rptr; + meter->rptr = rptr; + frames = rptr - old_rptr; + if (frames < 0) + frames += pcm->boundary; + if (frames > 0) { + assert((snd_pcm_uframes_t) frames <= pcm->buffer_size); + snd_pcm_meter_add_frames(pcm, areas, old_rptr, + (snd_pcm_uframes_t) frames); + } + if (locked) + pthread_mutex_unlock(&meter->update_mutex); +} + +static int snd_pcm_meter_update_scope(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t frames; + snd_pcm_uframes_t rptr, old_rptr; + const snd_pcm_channel_area_t *areas; + int reset = 0; + /* Wait main thread */ + pthread_mutex_lock(&meter->update_mutex); + areas = snd_pcm_mmap_areas(pcm); + _again: + rptr = *pcm->hw.ptr; + old_rptr = meter->rptr; + rmb(); + if (atomic_read(&meter->reset)) { + reset = 1; + atomic_dec(&meter->reset); + goto _again; + } + meter->rptr = rptr; + frames = rptr - old_rptr; + if (frames < 0) + frames += pcm->boundary; + if (frames > 0) { + assert((snd_pcm_uframes_t) frames <= pcm->buffer_size); + snd_pcm_meter_add_frames(pcm, areas, old_rptr, + (snd_pcm_uframes_t) frames); + } + pthread_mutex_unlock(&meter->update_mutex); + return reset; +} + +static int snd_pcm_scope_remove(snd_pcm_scope_t *scope) +{ + free(scope->name); + scope->ops->close(scope); + list_del(&scope->list); + free(scope); + return 0; +} + +static int snd_pcm_scope_enable(snd_pcm_scope_t *scope) +{ + int err; + assert(!scope->enabled); + err = scope->ops->enable(scope); + scope->enabled = (err >= 0); + return err; +} + +static int snd_pcm_scope_disable(snd_pcm_scope_t *scope) +{ + assert(scope->enabled); + scope->ops->disable(scope); + scope->enabled = 0; + return 0; +} + +static void *snd_pcm_meter_thread(void *data) +{ + snd_pcm_t *pcm = data; + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_t *spcm = meter->gen.slave; + struct list_head *pos; + snd_pcm_scope_t *scope; + int reset; + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_scope_t, list); + snd_pcm_scope_enable(scope); + } + while (!meter->closed) { + snd_pcm_sframes_t now; + snd_pcm_status_t status; + int err; + pthread_mutex_lock(&meter->running_mutex); + err = snd_pcm_status(spcm, &status); + assert(err >= 0); + if (status.state != SND_PCM_STATE_RUNNING && + (status.state != SND_PCM_STATE_DRAINING || + spcm->stream != SND_PCM_STREAM_PLAYBACK)) { + if (meter->running) { + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_scope_t, list); + scope->ops->stop(scope); + } + meter->running = 0; + } + pthread_cond_wait(&meter->running_cond, + &meter->running_mutex); + pthread_mutex_unlock(&meter->running_mutex); + continue; + } + pthread_mutex_unlock(&meter->running_mutex); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + now = status.appl_ptr - status.delay; + if (now < 0) + now += pcm->boundary; + } else { + now = status.appl_ptr + status.delay; + if ((snd_pcm_uframes_t) now >= pcm->boundary) + now -= pcm->boundary; + } + meter->now = now; + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + reset = snd_pcm_meter_update_scope(pcm); + else { + reset = 0; + while (atomic_read(&meter->reset)) { + reset = 1; + atomic_dec(&meter->reset); + } + } + if (reset) { + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + scope->ops->reset(scope); + } + continue; + } + if (!meter->running) { + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + scope->ops->start(scope); + } + meter->running = 1; + } + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + scope->ops->update(scope); + } + nanosleep(&meter->delay, NULL); + } + list_for_each(pos, &meter->scopes) { + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + snd_pcm_scope_disable(scope); + } + return NULL; +} + +static int snd_pcm_meter_close(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + struct list_head *pos, *npos; + int err = 0; + pthread_mutex_destroy(&meter->update_mutex); + pthread_mutex_destroy(&meter->running_mutex); + pthread_cond_destroy(&meter->running_cond); + if (meter->gen.close_slave) + err = snd_pcm_close(meter->gen.slave); + list_for_each_safe(pos, npos, &meter->scopes) { + snd_pcm_scope_t *scope; + scope = list_entry(pos, snd_pcm_scope_t, list); + snd_pcm_scope_remove(scope); + } + if (meter->dl_handle) + snd_dlclose(meter->dl_handle); + free(meter); + return err; +} + +static int snd_pcm_meter_prepare(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err; + atomic_inc(&meter->reset); + err = snd_pcm_prepare(meter->gen.slave); + if (err >= 0) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl.ptr; + else + meter->rptr = *pcm->hw.ptr; + } + return err; +} + +static int snd_pcm_meter_reset(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err = snd_pcm_reset(meter->gen.slave); + if (err >= 0) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl.ptr; + } + return err; +} + +static int snd_pcm_meter_start(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err; + pthread_mutex_lock(&meter->running_mutex); + err = snd_pcm_start(meter->gen.slave); + if (err >= 0) + pthread_cond_signal(&meter->running_cond); + pthread_mutex_unlock(&meter->running_mutex); + return err; +} + +static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t err = snd_pcm_rewind(meter->gen.slave, frames); + if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl.ptr; + return err; +} + +static snd_pcm_sframes_t snd_pcm_meter_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t err = INTERNAL(snd_pcm_forward)(meter->gen.slave, frames); + if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK) + meter->rptr = *pcm->appl.ptr; + return err; +} + +static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_uframes_t old_rptr = *pcm->appl.ptr; + snd_pcm_sframes_t result = snd_pcm_mmap_commit(meter->gen.slave, offset, size); + if (result <= 0) + return result; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result); + meter->rptr = *pcm->appl.ptr; + } + return result; +} + +static snd_pcm_sframes_t snd_pcm_meter_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_pcm_sframes_t result = snd_pcm_avail_update(meter->gen.slave); + if (result <= 0) + return result; + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + snd_pcm_meter_update_main(pcm); + return result; +} + +static int snd_pcm_meter_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_meter_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + return 0; +} + +static int snd_pcm_meter_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_meter_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_meter_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return snd_pcm_hw_refine(meter->gen.slave, params); +} + +static int snd_pcm_meter_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + return _snd_pcm_hw_params(meter->gen.slave, params); +} + +static int snd_pcm_meter_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_meter_hw_refine_cprepare, + snd_pcm_meter_hw_refine_cchange, + snd_pcm_meter_hw_refine_sprepare, + snd_pcm_meter_hw_refine_schange, + snd_pcm_meter_hw_refine_slave); +} + +static int snd_pcm_meter_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_meter_t *meter = pcm->private_data; + unsigned int channel; + snd_pcm_t *slave = meter->gen.slave; + size_t buf_size_bytes; + int err; + err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_meter_hw_refine_cchange, + snd_pcm_meter_hw_refine_sprepare, + snd_pcm_meter_hw_refine_schange, + snd_pcm_meter_hw_params_slave); + if (err < 0) + return err; + /* more than 1 second of buffer */ + meter->buf_size = slave->buffer_size; + while (meter->buf_size < slave->rate) + meter->buf_size *= 2; + buf_size_bytes = snd_pcm_frames_to_bytes(slave, meter->buf_size); + assert(!meter->buf); + meter->buf = malloc(buf_size_bytes); + if (!meter->buf) + return -ENOMEM; + meter->buf_areas = malloc(sizeof(*meter->buf_areas) * slave->channels); + if (!meter->buf_areas) { + free(meter->buf); + return -ENOMEM; + } + for (channel = 0; channel < slave->channels; ++channel) { + snd_pcm_channel_area_t *a = &meter->buf_areas[channel]; + a->addr = meter->buf + buf_size_bytes / slave->channels * channel; + a->first = 0; + a->step = slave->sample_bits; + } + meter->closed = 0; + err = pthread_create(&meter->thread, NULL, snd_pcm_meter_thread, pcm); + assert(err == 0); + return 0; +} + +static int snd_pcm_meter_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter = pcm->private_data; + int err; + meter->closed = 1; + pthread_mutex_lock(&meter->running_mutex); + pthread_cond_signal(&meter->running_cond); + pthread_mutex_unlock(&meter->running_mutex); + err = pthread_join(meter->thread, 0); + assert(err == 0); + free(meter->buf); + free(meter->buf_areas); + meter->buf = NULL; + meter->buf_areas = NULL; + return snd_pcm_hw_free(meter->gen.slave); +} + +static void snd_pcm_meter_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_meter_t *meter = pcm->private_data; + snd_output_printf(out, "Meter PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(meter->gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_meter_ops = { + .close = snd_pcm_meter_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_meter_hw_refine, + .hw_params = snd_pcm_meter_hw_params, + .hw_free = snd_pcm_meter_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_meter_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { + .status = snd_pcm_generic_status, + .state = snd_pcm_generic_state, + .hwsync = snd_pcm_generic_hwsync, + .delay = snd_pcm_generic_delay, + .prepare = snd_pcm_meter_prepare, + .reset = snd_pcm_meter_reset, + .start = snd_pcm_meter_start, + .drop = snd_pcm_generic_drop, + .drain = snd_pcm_generic_drain, + .pause = snd_pcm_generic_pause, + .rewindable = snd_pcm_generic_rewindable, + .rewind = snd_pcm_meter_rewind, + .forwardable = snd_pcm_generic_forwardable, + .forward = snd_pcm_meter_forward, + .resume = snd_pcm_generic_resume, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_mmap_readi, + .readn = snd_pcm_mmap_readn, + .avail_update = snd_pcm_meter_avail_update, + .mmap_commit = snd_pcm_meter_mmap_commit, + .htimestamp = snd_pcm_generic_htimestamp, + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_generic_poll_revents, +}; + +/** + * \brief Creates a new Meter PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param frequency Update frequency + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequency, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_meter_t *meter; + int err; + assert(pcmp); + meter = calloc(1, sizeof(snd_pcm_meter_t)); + if (!meter) + return -ENOMEM; + meter->gen.slave = slave; + meter->gen.close_slave = close_slave; + meter->delay.tv_sec = 0; + meter->delay.tv_nsec = 1000000000 / frequency; + INIT_LIST_HEAD(&meter->scopes); + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_METER, name, slave->stream, slave->mode); + if (err < 0) { + free(meter); + return err; + } + pcm->mmap_rw = 1; + pcm->mmap_shadow = 1; + pcm->ops = &snd_pcm_meter_ops; + pcm->fast_ops = &snd_pcm_meter_fast_ops; + pcm->private_data = meter; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; + + pthread_mutex_init(&meter->update_mutex, NULL); + pthread_mutex_init(&meter->running_mutex, NULL); + pthread_cond_init(&meter->running_cond, NULL); + return 0; +} + + +static int snd_pcm_meter_add_scope_conf(snd_pcm_t *pcm, const char *name, + snd_config_t *root, snd_config_t *conf) +{ + char buf[256]; + snd_config_iterator_t i, next; + const char *id; + const char *lib = NULL, *open_name = NULL, *str = NULL; + snd_config_t *c, *type_conf = NULL; + int (*open_func)(snd_pcm_t *, const char *, + snd_config_t *, snd_config_t *) = NULL; + snd_pcm_meter_t *meter = pcm->private_data; + void *h = NULL; + int err; + + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for scope %s", str); + err = -EINVAL; + goto _err; + } + err = snd_config_search(conf, "type", &c); + if (err < 0) { + SNDERR("type is not defined"); + goto _err; + } + err = snd_config_get_id(c, &id); + if (err < 0) { + SNDERR("unable to get id"); + goto _err; + } + err = snd_config_get_string(c, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + err = snd_config_search_definition(root, "pcm_scope_type", str, &type_conf); + if (err >= 0) { + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + open_name = buf; + snprintf(buf, sizeof(buf), "_snd_pcm_scope_%s_open", str); + } + h = snd_dlopen(lib, RTLD_NOW); + open_func = h ? dlsym(h, open_name) : NULL; + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + if (! err) { + err = open_func(pcm, name, root, conf); + if (err < 0) + snd_dlclose(h); + else + meter->dl_handle = h; + } + return err; +} + +/*! \page pcm_plugins + +\section pcm_plugins_meter Plugin: Meter + +Show meter (visual waveform representation). + +\code +pcm_scope_type.NAME { + [lib STR] # Library file (default libasound.so) + [open STR] # Open function (default _snd_pcm_scope_NAME_open) +} + +pcm_scope.name { + type STR # Scope type + ... +} + +pcm.name { + type meter # Meter PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + } + [frequency INT] # Updates per second + scopes { + ID STR # Scope name (see pcm_scope) + # or + ID { } # Scope definition (see pcm_scope) + } +} +\endcode + +\subsection pcm_plugins_meter_funcref Function reference + +
    +
  • snd_pcm_meter_open() +
  • _snd_pcm_meter_open() +
+ +*/ + +/** + * \brief Creates a new Meter PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Meter PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + long frequency = -1; + snd_config_t *scopes = NULL; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "frequency") == 0) { + err = snd_config_get_integer(n, &frequency); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "scopes") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + scopes = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_meter_open(pcmp, name, frequency > 0 ? (unsigned int) frequency : FREQUENCY, spcm, 1); + if (err < 0) { + snd_pcm_close(spcm); + return err; + } + if (!scopes) + return 0; + snd_config_for_each(i, next, scopes) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id, *str; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_config_get_string(n, &str) >= 0) { + err = snd_config_search_definition(root, "pcm_scope", str, &n); + if (err < 0) { + SNDERR("unknown pcm_scope %s", str); + } else { + err = snd_pcm_meter_add_scope_conf(*pcmp, id, root, n); + snd_config_delete(n); + } + } else + err = snd_pcm_meter_add_scope_conf(*pcmp, id, root, n); + if (err < 0) { + snd_pcm_close(*pcmp); + return err; + } + } + return 0; +} +SND_DLSYM_BUILD_VERSION(_snd_pcm_meter_open, SND_PCM_DLSYM_VERSION); + +#endif + +/** + * \brief Add a scope to a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \param scope Scope handle + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + list_add_tail(&scope->list, &meter->scopes); + return 0; +} + +/** + * \brief Search an installed scope inside a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \param name scope name + * \return pointer to found scope or NULL if none is found + */ +snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name) +{ + snd_pcm_meter_t *meter; + struct list_head *pos; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + list_for_each(pos, &meter->scopes) { + snd_pcm_scope_t *scope; + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->name && strcmp(scope->name, name) == 0) + return scope; + } + return NULL; +} + +/** + * \brief Get meter buffer size from a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \return meter buffer size in frames + */ +snd_pcm_uframes_t snd_pcm_meter_get_bufsize(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->gen.slave->setup); + return meter->buf_size; +} + +/** + * \brief Get meter channels from a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \return meter channels count + */ +unsigned int snd_pcm_meter_get_channels(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->gen.slave->setup); + return meter->gen.slave->channels; +} + +/** + * \brief Get meter rate from a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \return approximate rate + */ +unsigned int snd_pcm_meter_get_rate(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->gen.slave->setup); + return meter->gen.slave->rate; +} + +/** + * \brief Get meter "now" frame pointer from a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \return "now" frame pointer in frames (0 ... boundary - 1) see #snd_pcm_meter_get_boundary + */ +snd_pcm_uframes_t snd_pcm_meter_get_now(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->gen.slave->setup); + return meter->now; +} + +/** + * \brief Get boundary for frame pointers from a #SND_PCM_TYPE_METER PCM + * \param pcm PCM handle + * \return boundary in frames + */ +snd_pcm_uframes_t snd_pcm_meter_get_boundary(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->gen.slave->setup); + return meter->gen.slave->boundary; +} + +/** + * \brief Set name of a #SND_PCM_TYPE_METER PCM scope + * \param scope PCM meter scope + * \param val scope name + */ +void snd_pcm_scope_set_name(snd_pcm_scope_t *scope, const char *val) +{ + scope->name = strdup(val); +} + +/** + * \brief Get name of a #SND_PCM_TYPE_METER PCM scope + * \param scope PCM meter scope + * \return scope name + */ +const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope) +{ + return scope->name; +} + +/** + * \brief Set callbacks for a #SND_PCM_TYPE_METER PCM scope + * \param scope PCM meter scope + * \param val callbacks + */ +void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, const snd_pcm_scope_ops_t *val) +{ + scope->ops = val; +} + +/** + * \brief Get callbacks private value for a #SND_PCM_TYPE_METER PCM scope + * \param scope PCM meter scope + * \return Private data value + */ +void *snd_pcm_scope_get_callback_private(snd_pcm_scope_t *scope) +{ + return scope->private_data; +} + +/** + * \brief Get callbacks private value for a #SND_PCM_TYPE_METER PCM scope + * \param scope PCM meter scope + * \param val Private data value + */ +void snd_pcm_scope_set_callback_private(snd_pcm_scope_t *scope, void *val) +{ + scope->private_data = val; +} + +#ifndef DOC_HIDDEN +typedef struct _snd_pcm_scope_s16 { + snd_pcm_t *pcm; + snd_pcm_adpcm_state_t *adpcm_states; + unsigned int index; + snd_pcm_uframes_t old; + int16_t *buf; + snd_pcm_channel_area_t *buf_areas; +} snd_pcm_scope_s16_t; + +static int s16_enable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + snd_pcm_meter_t *meter = s16->pcm->private_data; + snd_pcm_t *spcm = meter->gen.slave; + snd_pcm_channel_area_t *a; + unsigned int c; + int idx; + if (spcm->format == SND_PCM_FORMAT_S16 && + spcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) { + s16->buf = (int16_t *) meter->buf; + return -EINVAL; + } + switch (spcm->format) { + case SND_PCM_FORMAT_A_LAW: + case SND_PCM_FORMAT_MU_LAW: + case SND_PCM_FORMAT_IMA_ADPCM: + idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, SND_PCM_FORMAT_S16); + break; + case SND_PCM_FORMAT_S8: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + case SND_PCM_FORMAT_S24_LE: + case SND_PCM_FORMAT_S24_BE: + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_U8: + case SND_PCM_FORMAT_U16_LE: + case SND_PCM_FORMAT_U16_BE: + case SND_PCM_FORMAT_U24_LE: + case SND_PCM_FORMAT_U24_BE: + case SND_PCM_FORMAT_U32_LE: + case SND_PCM_FORMAT_U32_BE: + idx = snd_pcm_linear_convert_index(spcm->format, SND_PCM_FORMAT_S16); + break; + default: + return -EINVAL; + } + s16->index = idx; + if (spcm->format == SND_PCM_FORMAT_IMA_ADPCM) { + s16->adpcm_states = calloc(spcm->channels, sizeof(*s16->adpcm_states)); + if (!s16->adpcm_states) + return -ENOMEM; + } + s16->buf = malloc(meter->buf_size * 2 * spcm->channels); + if (!s16->buf) { + free(s16->adpcm_states); + return -ENOMEM; + } + a = calloc(spcm->channels, sizeof(*a)); + if (!a) { + free(s16->buf); + free(s16->adpcm_states); + return -ENOMEM; + } + s16->buf_areas = a; + for (c = 0; c < spcm->channels; c++, a++) { + a->addr = s16->buf + c * meter->buf_size; + a->first = 0; + a->step = 16; + } + return 0; +} + +static void s16_disable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + free(s16->adpcm_states); + s16->adpcm_states = NULL; + free(s16->buf); + s16->buf = NULL; + free(s16->buf_areas); + s16->buf_areas = 0; +} + +static void s16_close(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + free(s16); +} + +static void s16_start(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED) +{ +} + +static void s16_stop(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED) +{ +} + +static void s16_update(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + snd_pcm_meter_t *meter = s16->pcm->private_data; + snd_pcm_t *spcm = meter->gen.slave; + snd_pcm_sframes_t size; + snd_pcm_uframes_t offset; + size = meter->now - s16->old; + if (size < 0) + size += spcm->boundary; + offset = s16->old % meter->buf_size; + while (size > 0) { + snd_pcm_uframes_t frames = size; + snd_pcm_uframes_t cont = meter->buf_size - offset; + if (frames > cont) + frames = cont; + switch (spcm->format) { + case SND_PCM_FORMAT_A_LAW: + snd_pcm_alaw_decode(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index); + break; + case SND_PCM_FORMAT_MU_LAW: + snd_pcm_mulaw_decode(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index); + break; + case SND_PCM_FORMAT_IMA_ADPCM: + snd_pcm_adpcm_decode(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index, + s16->adpcm_states); + break; + default: + snd_pcm_linear_convert(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index); + break; + } + if (frames == cont) + offset = 0; + else + offset += frames; + size -= frames; + } + s16->old = meter->now; +} + +static void s16_reset(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + snd_pcm_meter_t *meter = s16->pcm->private_data; + s16->old = meter->now; +} + +static const snd_pcm_scope_ops_t s16_ops = { + .enable = s16_enable, + .disable = s16_disable, + .close = s16_close, + .start = s16_start, + .stop = s16_stop, + .update = s16_update, + .reset = s16_reset, +}; + +#endif + +/** + * \brief Add a s16 pseudo scope to a #SND_PCM_TYPE_METER PCM + * \param pcm The pcm handle + * \param name Scope name + * \param scopep Pointer to newly created and added scope + * \return 0 on success otherwise a negative error code + * + * s16 pseudo scope convert #SND_PCM_TYPE_METER PCM frames in CPU endian + * 16 bit frames for use with other scopes. Don't forget to insert it before + * and to not insert it more time (see #snd_pcm_meter_search_scope) + */ +int snd_pcm_scope_s16_open(snd_pcm_t *pcm, const char *name, + snd_pcm_scope_t **scopep) +{ + snd_pcm_meter_t *meter; + snd_pcm_scope_t *scope; + snd_pcm_scope_s16_t *s16; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + scope = calloc(1, sizeof(*scope)); + if (!scope) + return -ENOMEM; + s16 = calloc(1, sizeof(*s16)); + if (!s16) { + free(scope); + return -ENOMEM; + } + if (name) + scope->name = strdup(name); + s16->pcm = pcm; + scope->ops = &s16_ops; + scope->private_data = s16; + list_add_tail(&scope->list, &meter->scopes); + *scopep = scope; + return 0; +} + +/** + * \brief Get s16 pseudo scope frames buffer for a channel + * \param scope s16 pseudo scope handle + * \param channel Channel + * \return Pointer to channel buffer + */ +int16_t *snd_pcm_scope_s16_get_channel_buffer(snd_pcm_scope_t *scope, + unsigned int channel) +{ + snd_pcm_scope_s16_t *s16; + snd_pcm_meter_t *meter; + assert(scope->ops == &s16_ops); + s16 = scope->private_data; + meter = s16->pcm->private_data; + assert(meter->gen.slave->setup); + assert(s16->buf_areas); + assert(channel < meter->gen.slave->channels); + return s16->buf_areas[channel].addr; +} + +/** + * \brief allocate an invalid #snd_pcm_scope_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_pcm_scope_malloc(snd_pcm_scope_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_scope_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c new file mode 100644 index 0000000..d52160c --- /dev/null +++ b/src/pcm/pcm_misc.c @@ -0,0 +1,833 @@ +/* + * PCM Interface - misc routines + * Copyright (c) 1998 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include "pcm_local.h" + + +/** + * \brief Return sign info for a PCM sample linear format + * \param format Format + * \return 0 unsigned, 1 signed, a negative error code if format is not linear + */ +int snd_pcm_format_signed(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + return 1; + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + return 0; + default: + return -EINVAL; + } +} + +/** + * \brief Return sign info for a PCM sample linear format + * \param format Format + * \return 0 signed, 1 unsigned, a negative error code if format is not linear + */ +int snd_pcm_format_unsigned(snd_pcm_format_t format) +{ + int val; + + val = snd_pcm_format_signed(format); + if (val < 0) + return val; + return !val; +} + +/** + * \brief Return linear info for a PCM sample format + * \param format Format + * \return 0 non linear, 1 linear + */ +int snd_pcm_format_linear(snd_pcm_format_t format) +{ + return snd_pcm_format_signed(format) >= 0; +} + +/** + * \brief Return float info for a PCM sample format + * \param format Format + * \return 0 non float, 1 float + */ +int snd_pcm_format_float(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return 1; + default: + return 0; + } +} + +/** + * \brief Return endian info for a PCM sample format + * \param format Format + * \return 0 big endian, 1 little endian, a negative error code if endian independent + */ +int snd_pcm_format_little_endian(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U18_3LE: + return 1; + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_BE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U24_3BE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_U18_3BE: + return 0; + default: + return -EINVAL; + } +} + +/** + * \brief Return endian info for a PCM sample format + * \param format Format + * \return 0 little endian, 1 big endian, a negative error code if endian independent + */ +int snd_pcm_format_big_endian(snd_pcm_format_t format) +{ + int val; + + val = snd_pcm_format_little_endian(format); + if (val < 0) + return val; + return !val; +} + +/** + * \brief Return endian info for a PCM sample format + * \param format Format + * \return 0 swapped, 1 CPU endian, a negative error code if endian independent + */ +int snd_pcm_format_cpu_endian(snd_pcm_format_t format) +{ +#ifdef SNDRV_LITTLE_ENDIAN + return snd_pcm_format_little_endian(format); +#else + return snd_pcm_format_big_endian(format); +#endif +} + +/** + * \brief Return nominal bits per a PCM sample + * \param format Sample format + * \return bits per sample, a negative error code if not applicable + */ +int snd_pcm_format_width(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return 8; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + return 16; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + return 18; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + return 20; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + return 24; + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + return 32; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return 64; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return 32; + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return 8; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + return 4; + default: + return -EINVAL; + } +} + +/** + * \brief Return bits needed to store a PCM sample + * \param format Sample format + * \return bits per sample, a negative error code if not applicable + */ +int snd_pcm_format_physical_width(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return 8; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + return 16; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + return 24; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return 32; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return 64; + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return 8; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + return 4; + default: + return -EINVAL; + } +} + +/** + * \brief Return bytes needed to store a quantity of PCM sample + * \param format Sample format + * \param samples Samples count + * \return bytes needed, a negative error code if not integer or unknown + */ +ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return samples; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + return samples * 2; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + return samples * 3; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + return samples * 4; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return samples * 8; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return samples * 4; + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return samples; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + if (samples & 1) + return -EINVAL; + return samples / 2; + default: + assert(0); + return -EINVAL; + } +} + +/** + * \brief Return 64 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 64 bit word + */ +u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) +{ + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + return 0; + case SNDRV_PCM_FORMAT_U8: + return 0x8080808080808080ULL; +#ifdef SNDRV_LITTLE_ENDIAN + case SNDRV_PCM_FORMAT_U16_LE: + return 0x8000800080008000ULL; + case SNDRV_PCM_FORMAT_U24_LE: + return 0x0080000000800000ULL; + case SNDRV_PCM_FORMAT_U32_LE: + return 0x8000000080000000ULL; + case SNDRV_PCM_FORMAT_U16_BE: + return 0x0080008000800080ULL; + case SNDRV_PCM_FORMAT_U24_BE: + return 0x0000800000008000ULL; + case SNDRV_PCM_FORMAT_U32_BE: + return 0x0000008000000080ULL; + case SNDRV_PCM_FORMAT_U24_3LE: + return 0x0000800000800000ULL; + case SNDRV_PCM_FORMAT_U24_3BE: + return 0x0080000080000080ULL; + case SNDRV_PCM_FORMAT_U20_3LE: + return 0x0000080000080000ULL; + case SNDRV_PCM_FORMAT_U20_3BE: + return 0x0008000008000008ULL; + case SNDRV_PCM_FORMAT_U18_3LE: + return 0x0000020000020000ULL; + case SNDRV_PCM_FORMAT_U18_3BE: + return 0x0002000002000002ULL; +#else + case SNDRV_PCM_FORMAT_U16_LE: + return 0x0080008000800080ULL; + case SNDRV_PCM_FORMAT_U24_LE: + return 0x0000800000008000ULL; + case SNDRV_PCM_FORMAT_U32_LE: + return 0x0000008000000080ULL; + case SNDRV_PCM_FORMAT_U16_BE: + return 0x8000800080008000ULL; + case SNDRV_PCM_FORMAT_U24_BE: + return 0x0080000000800000ULL; + case SNDRV_PCM_FORMAT_U32_BE: + return 0x8000000080000000ULL; + case SNDRV_PCM_FORMAT_U24_3LE: + return 0x0080000080000080ULL; + case SNDRV_PCM_FORMAT_U24_3BE: + return 0x0000800000800000ULL; + case SNDRV_PCM_FORMAT_U20_3LE: + return 0x0008000008000008ULL; + case SNDRV_PCM_FORMAT_U20_3BE: + return 0x0000080000080000ULL; + case SNDRV_PCM_FORMAT_U18_3LE: + return 0x0002000002000002ULL; + case SNDRV_PCM_FORMAT_U18_3BE: + return 0x0000020000020000ULL; +#endif + case SNDRV_PCM_FORMAT_FLOAT_LE: + { + union { + float f[2]; + u_int64_t i; + } u; + u.f[0] = u.f[1] = 0.0; +#ifdef SNDRV_LITTLE_ENDIAN + return u.i; +#else + return bswap_64(u.i); +#endif + } + case SNDRV_PCM_FORMAT_FLOAT64_LE: + { + union { + double f; + u_int64_t i; + } u; + u.f = 0.0; +#ifdef SNDRV_LITTLE_ENDIAN + return u.i; +#else + return bswap_64(u.i); +#endif + } + case SNDRV_PCM_FORMAT_FLOAT_BE: + { + union { + float f[2]; + u_int64_t i; + } u; + u.f[0] = u.f[1] = 0.0; +#ifdef SNDRV_LITTLE_ENDIAN + return bswap_64(u.i); +#else + return u.i; +#endif + } + case SNDRV_PCM_FORMAT_FLOAT64_BE: + { + union { + double f; + u_int64_t i; + } u; + u.f = 0.0; +#ifdef SNDRV_LITTLE_ENDIAN + return bswap_64(u.i); +#else + return u.i; +#endif + } + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return 0; + case SNDRV_PCM_FORMAT_MU_LAW: + return 0x7f7f7f7f7f7f7f7fULL; + case SNDRV_PCM_FORMAT_A_LAW: + return 0x5555555555555555ULL; + case SNDRV_PCM_FORMAT_IMA_ADPCM: /* special case */ + case SNDRV_PCM_FORMAT_MPEG: + case SNDRV_PCM_FORMAT_GSM: + case SNDRV_PCM_FORMAT_SPECIAL: + return 0; + default: + assert(0); + return 0; + } + return 0; +} + +/** + * \brief Return 32 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 32 bit word + */ +u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) +{ + assert(snd_pcm_format_physical_width(format) <= 32); + return (u_int32_t)snd_pcm_format_silence_64(format); +} + +/** + * \brief Return 16 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 16 bit word + */ +u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) +{ + assert(snd_pcm_format_physical_width(format) <= 16); + return (u_int16_t)snd_pcm_format_silence_64(format); +} + +/** + * \brief Return 8 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 8 bit word + */ +u_int8_t snd_pcm_format_silence(snd_pcm_format_t format) +{ + assert(snd_pcm_format_physical_width(format) <= 8); + return (u_int8_t)snd_pcm_format_silence_64(format); +} + +/** + * \brief Silence a PCM samples buffer + * \param format Sample format + * \param data Buffer + * \param samples Samples count + * \return 0 if successful or a negative error code + */ +int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) +{ + if (samples == 0) + return 0; + switch (snd_pcm_format_physical_width(format)) { + case 4: { + u_int8_t silence = snd_pcm_format_silence_64(format); + unsigned int samples1; + if (samples % 2 != 0) + return -EINVAL; + samples1 = samples / 2; + memset(data, silence, samples1); + break; + } + case 8: { + u_int8_t silence = snd_pcm_format_silence_64(format); + memset(data, silence, samples); + break; + } + case 16: { + u_int16_t silence = snd_pcm_format_silence_64(format); + u_int16_t *pdata = (u_int16_t *)data; + if (! silence) + memset(data, 0, samples * 2); + else { + while (samples-- > 0) + *pdata++ = silence; + } + break; + } + case 24: { + u_int32_t silence = snd_pcm_format_silence_64(format); + u_int8_t *pdata = (u_int8_t *)data; + if (! silence) + memset(data, 0, samples * 3); + else { + while (samples-- > 0) { +#ifdef SNDRV_LITTLE_ENDIAN + *pdata++ = silence >> 0; + *pdata++ = silence >> 8; + *pdata++ = silence >> 16; +#else + *pdata++ = silence >> 16; + *pdata++ = silence >> 8; + *pdata++ = silence >> 0; +#endif + } + } + break; + } + case 32: { + u_int32_t silence = snd_pcm_format_silence_64(format); + u_int32_t *pdata = (u_int32_t *)data; + if (! silence) + memset(data, 0, samples * 4); + else { + while (samples-- > 0) + *pdata++ = silence; + } + break; + } + case 64: { + u_int64_t silence = snd_pcm_format_silence_64(format); + u_int64_t *pdata = (u_int64_t *)data; + if (! silence) + memset(data, 0, samples * 8); + else { + while (samples-- > 0) + *pdata++ = silence; + } + break; + } + default: + assert(0); + return -EINVAL; + } + return 0; +} + +static const int linear_formats[4][2][2] = { + { { SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8 }, + { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8 } }, + { { SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE }, + { SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE } }, + { { SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE }, + { SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE } }, + { { SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE }, + { SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE } } +}; + +static const int linear24_formats[3][2][2] = { + { { SNDRV_PCM_FORMAT_S24_3LE, SNDRV_PCM_FORMAT_S24_3BE }, + { SNDRV_PCM_FORMAT_U24_3LE, SNDRV_PCM_FORMAT_U24_3BE } }, + { { SNDRV_PCM_FORMAT_S20_3LE, SNDRV_PCM_FORMAT_S20_3BE }, + { SNDRV_PCM_FORMAT_U20_3LE, SNDRV_PCM_FORMAT_U20_3BE } }, + { { SNDRV_PCM_FORMAT_S18_3LE, SNDRV_PCM_FORMAT_S18_3BE }, + { SNDRV_PCM_FORMAT_U18_3LE, SNDRV_PCM_FORMAT_U18_3BE } }, +}; + +/** + * \brief Compose a PCM sample linear format + * \param width Nominal bits per sample + * \param pwidth Physical bit width of the format + * \param unsignd Sign: 0 signed, 1 unsigned + * \param big_endian Endian: 0 little endian, 1 big endian + * \return The matching format type, or #SND_PCM_FORMAT_UNKNOWN if no match + */ +snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian) +{ + if (pwidth == 24) { + switch (width) { + case 24: + width = 0; + break; + case 20: + width = 1; + break; + case 18: + width = 2; + break; + default: + return SND_PCM_FORMAT_UNKNOWN; + } + return linear24_formats[width][!!unsignd][!!big_endian]; + } else { + switch (width) { + case 8: + width = 0; + break; + case 16: + width = 1; + break; + case 24: + width = 2; + break; + case 32: + width = 3; + break; + default: + return SND_PCM_FORMAT_UNKNOWN; + } + return linear_formats[width][!!unsignd][!!big_endian]; + } +} + +/** + * \brief Parse control element id from the config + * \param conf the config tree to parse + * \param ctl_id the pointer to store the resultant control element id + * \param cardp the pointer to store the card index + * \param cchannelsp the pointer to store the number of channels (optional) + * \param hwctlp the pointer to store the h/w control flag (optional) + * \return 0 if successful, or a negative error code + * + * This function parses the given config tree to retrieve the control element id + * and the card index. It's used by softvol. External PCM plugins can use this + * function for creating or assigining their controls. + * + * cchannelsp and hwctlp arguments are optional. Set NULL if not necessary. + */ +int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, + int *cchannelsp, int *hwctlp) +{ + snd_config_iterator_t i, next; + int iface = SND_CTL_ELEM_IFACE_MIXER; + const char *name = NULL; + long index = 0; + long device = -1; + long subdevice = -1; + int err; + + assert(ctl_id && cardp); + + *cardp = -1; + if (cchannelsp) + *cchannelsp = 2; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "card") == 0) { + const char *str; + long v; + if ((err = snd_config_get_integer(n, &v)) < 0) { + if ((err = snd_config_get_string(n, &str)) < 0) { + SNDERR("Invalid field %s", id); + goto _err; + } + *cardp = snd_card_get_index(str); + if (*cardp < 0) { + SNDERR("Cannot get index for %s", str); + err = *cardp; + goto _err; + } + } else + *cardp = v; + continue; + } + if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) { + const char *ptr; + if ((err = snd_config_get_string(n, &ptr)) < 0) { + SNDERR("field %s is not a string", id); + goto _err; + } + if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) { + SNDERR("Invalid value for '%s'", id); + goto _err; + } + iface = err; + continue; + } + if (strcmp(id, "name") == 0) { + if ((err = snd_config_get_string(n, &name)) < 0) { + SNDERR("field %s is not a string", id); + goto _err; + } + continue; + } + if (strcmp(id, "index") == 0) { + if ((err = snd_config_get_integer(n, &index)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + continue; + } + if (strcmp(id, "device") == 0) { + if ((err = snd_config_get_integer(n, &device)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + continue; + } + if (strcmp(id, "subdevice") == 0) { + if ((err = snd_config_get_integer(n, &subdevice)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + continue; + } + if (cchannelsp && strcmp(id, "count") == 0) { + long v; + if ((err = snd_config_get_integer(n, &v)) < 0) { + SNDERR("field %s is not an integer", id); + goto _err; + } + if (v < 1 || v > 2) { + SNDERR("Invalid count %ld", v); + goto _err; + } + *cchannelsp = v; + continue; + } + if (hwctlp && strcmp(id, "hwctl") == 0) { + if ((err = snd_config_get_bool(n)) < 0) { + SNDERR("The field %s must be a boolean type", id); + return err; + } + *hwctlp = err; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (name == NULL) { + SNDERR("Missing control name"); + err = -EINVAL; + goto _err; + } + if (device < 0) + device = 0; + if (subdevice < 0) + subdevice = 0; + + snd_ctl_elem_id_set_interface(ctl_id, iface); + snd_ctl_elem_id_set_name(ctl_id, name); + snd_ctl_elem_id_set_index(ctl_id, index); + snd_ctl_elem_id_set_device(ctl_id, device); + snd_ctl_elem_id_set_subdevice(ctl_id, subdevice); + + return 0; + + _err: + return err; +} diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c new file mode 100644 index 0000000..4621fe6 --- /dev/null +++ b/src/pcm/pcm_mmap.c @@ -0,0 +1,633 @@ +/* + * PCM Interface - mmap + * Copyright (c) 2000 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "pcm_local.h" + +size_t page_size(void) +{ + long s = sysconf(_SC_PAGE_SIZE); + assert(s > 0); + return s; +} + +size_t page_align(size_t size) +{ + size_t r; + long psz = page_size(); + r = size % psz; + if (r) + return size + psz - r; + return size; +} + +size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset) +{ + size_t r; + long psz = page_size(); + assert(offset); + assert(mmap_offset); + *mmap_offset = object_offset; + object_offset %= psz; + *mmap_offset -= object_offset; + object_size += object_offset; + r = object_size % psz; + if (r) + r = object_size + psz - r; + else + r = object_size; + *offset = object_offset; + return r; +} + +void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t appl_ptr = *pcm->appl.ptr; + appl_ptr -= frames; + if (appl_ptr < 0) + appl_ptr += pcm->boundary; + *pcm->appl.ptr = appl_ptr; +} + +void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_uframes_t appl_ptr = *pcm->appl.ptr; + appl_ptr += frames; + if (appl_ptr >= pcm->boundary) + appl_ptr -= pcm->boundary; + *pcm->appl.ptr = appl_ptr; +} + +void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t hw_ptr = *pcm->hw.ptr; + hw_ptr -= frames; + if (hw_ptr < 0) + hw_ptr += pcm->boundary; + *pcm->hw.ptr = hw_ptr; +} + +void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_uframes_t hw_ptr = *pcm->hw.ptr; + hw_ptr += frames; + if (hw_ptr >= pcm->boundary) + hw_ptr -= pcm->boundary; + *pcm->hw.ptr = hw_ptr; +} + +static snd_pcm_sframes_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_uframes_t xfer = 0; + + if (snd_pcm_mmap_playback_avail(pcm) < size) { + SNDMSG("too short avail %ld to size %ld", snd_pcm_mmap_playback_avail(pcm), size); + return -EPIPE; + } + while (size > 0) { + const snd_pcm_channel_area_t *pcm_areas; + snd_pcm_uframes_t pcm_offset; + snd_pcm_uframes_t frames = size; + snd_pcm_sframes_t result; + + snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); + snd_pcm_areas_copy(pcm_areas, pcm_offset, + areas, offset, + pcm->channels, + frames, pcm->format); + result = snd_pcm_mmap_commit(pcm, pcm_offset, frames); + if (result < 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : result; + offset += result; + xfer += result; + size -= result; + } + return (snd_pcm_sframes_t)xfer; +} + +static snd_pcm_sframes_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_uframes_t xfer = 0; + + if (snd_pcm_mmap_capture_avail(pcm) < size) { + SNDMSG("too short avail %ld to size %ld", snd_pcm_mmap_capture_avail(pcm), size); + return -EPIPE; + } + while (size > 0) { + const snd_pcm_channel_area_t *pcm_areas; + snd_pcm_uframes_t pcm_offset; + snd_pcm_uframes_t frames = size; + snd_pcm_sframes_t result; + + snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); + snd_pcm_areas_copy(areas, offset, + pcm_areas, pcm_offset, + pcm->channels, + frames, pcm->format); + result = snd_pcm_mmap_commit(pcm, pcm_offset, frames); + if (result < 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : result; + offset += result; + xfer += result; + size -= result; + } + return (snd_pcm_sframes_t)xfer; +} + +/** + * \brief Write interleaved frames to a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected, then routine waits until + * all requested bytes are played or put to the playback ring buffer. + * The count of bytes can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_buf(pcm, areas, (void*)buffer); + return snd_pcm_write_areas(pcm, areas, 0, size, + snd_pcm_mmap_write_areas); +} + +/** + * \brief Write non interleaved frames to a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected, then routine waits until + * all requested bytes are played or put to the playback ring buffer. + * The count of bytes can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_bufs(pcm, areas, bufs); + return snd_pcm_write_areas(pcm, areas, 0, size, + snd_pcm_mmap_write_areas); +} + +/** + * \brief Read interleaved frames from a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected, then routine waits until + * all requested bytes are filled. The count of bytes can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_buf(pcm, areas, buffer); + return snd_pcm_read_areas(pcm, areas, 0, size, + snd_pcm_mmap_read_areas); +} + +/** + * \brief Read non interleaved frames to a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected, then routine waits until + * all requested bytes are filled. The count of bytes can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_bufs(pcm, areas, bufs); + return snd_pcm_read_areas(pcm, areas, 0, size, + snd_pcm_mmap_read_areas); +} + +int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid) +{ + switch (pcm->access) { + case SND_PCM_ACCESS_MMAP_INTERLEAVED: + case SND_PCM_ACCESS_RW_INTERLEAVED: + info->first = info->channel * pcm->sample_bits; + info->step = pcm->frame_bits; + break; + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: + case SND_PCM_ACCESS_RW_NONINTERLEAVED: + info->first = 0; + info->step = pcm->sample_bits; + break; + default: + SNDMSG("invalid access type %d", pcm->access); + return -EINVAL; + } + info->addr = 0; + if (pcm->hw_flags & SND_PCM_HW_PARAMS_EXPORT_BUFFER) { + info->type = SND_PCM_AREA_SHM; + info->u.shm.shmid = shmid; + info->u.shm.area = NULL; + } else + info->type = SND_PCM_AREA_LOCAL; + return 0; +} + +int snd_pcm_mmap(snd_pcm_t *pcm) +{ + int err; + unsigned int c; + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (CHECK_SANITY(pcm->mmap_channels || pcm->running_areas)) { + SNDMSG("Already mmapped"); + return -EBUSY; + } + err = pcm->ops->mmap(pcm); + if (err < 0) + return err; + if (pcm->mmap_shadow) + return 0; + pcm->mmap_channels = calloc(pcm->channels, sizeof(pcm->mmap_channels[0])); + if (!pcm->mmap_channels) + return -ENOMEM; + pcm->running_areas = calloc(pcm->channels, sizeof(pcm->running_areas[0])); + if (!pcm->running_areas) { + free(pcm->mmap_channels); + pcm->mmap_channels = NULL; + return -ENOMEM; + } + for (c = 0; c < pcm->channels; ++c) { + snd_pcm_channel_info_t *i = &pcm->mmap_channels[c]; + i->channel = c; + err = snd_pcm_channel_info(pcm, i); + if (err < 0) + return err; + } + for (c = 0; c < pcm->channels; ++c) { + snd_pcm_channel_info_t *i = &pcm->mmap_channels[c]; + snd_pcm_channel_area_t *a = &pcm->running_areas[c]; + char *ptr; + size_t size; + unsigned int c1; + if (i->addr) { + a->addr = i->addr; + a->first = i->first; + a->step = i->step; + continue; + } + size = i->first + i->step * (pcm->buffer_size - 1) + pcm->sample_bits; + for (c1 = c + 1; c1 < pcm->channels; ++c1) { + snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; + size_t s; + if (i1->type != i->type) + continue; + switch (i1->type) { + case SND_PCM_AREA_MMAP: + if (i1->u.mmap.fd != i->u.mmap.fd || + i1->u.mmap.offset != i->u.mmap.offset) + continue; + break; + case SND_PCM_AREA_SHM: + if (i1->u.shm.shmid != i->u.shm.shmid) + continue; + break; + case SND_PCM_AREA_LOCAL: + break; + default: + assert(0); + } + s = i1->first + i1->step * (pcm->buffer_size - 1) + pcm->sample_bits; + if (s > size) + size = s; + } + size = (size + 7) / 8; + size = page_align(size); + switch (i->type) { + case SND_PCM_AREA_MMAP: + ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset); + if (ptr == MAP_FAILED) { + SYSERR("mmap failed"); + return -errno; + } + i->addr = ptr; + break; + case SND_PCM_AREA_SHM: + if (i->u.shm.shmid < 0) { + int id; + /* FIXME: safer permission? */ + id = shmget(IPC_PRIVATE, size, 0666); + if (id < 0) { + SYSERR("shmget failed"); + return -errno; + } + i->u.shm.shmid = id; + ptr = shmat(i->u.shm.shmid, 0, 0); + if (ptr == (void *) -1) { + SYSERR("shmat failed"); + return -errno; + } + /* automatically remove segment if not used */ + if (shmctl(id, IPC_RMID, NULL) < 0){ + SYSERR("shmctl mark remove failed"); + return -errno; + } + i->u.shm.area = snd_shm_area_create(id, ptr); + if (i->u.shm.area == NULL) { + SYSERR("snd_shm_area_create failed"); + return -ENOMEM; + } + if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED || + pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) { + unsigned int c1; + for (c1 = c + 1; c1 < pcm->channels; c1++) { + snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; + if (i1->u.shm.shmid < 0) { + i1->u.shm.shmid = id; + i1->u.shm.area = snd_shm_area_share(i->u.shm.area); + } + } + } + } else { + ptr = shmat(i->u.shm.shmid, 0, 0); + if (ptr == (void*) -1) { + SYSERR("shmat failed"); + return -errno; + } + } + i->addr = ptr; + break; + case SND_PCM_AREA_LOCAL: + ptr = malloc(size); + if (ptr == NULL) { + SYSERR("malloc failed"); + return -errno; + } + i->addr = ptr; + break; + default: + assert(0); + } + for (c1 = c + 1; c1 < pcm->channels; ++c1) { + snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; + if (i1->type != i->type) + continue; + switch (i1->type) { + case SND_PCM_AREA_MMAP: + if (i1->u.mmap.fd != i->u.mmap.fd || + i1->u.mmap.offset != i->u.mmap.offset) + continue; + break; + case SND_PCM_AREA_SHM: + if (i1->u.shm.shmid != i->u.shm.shmid) + continue; + /* follow thru */ + case SND_PCM_AREA_LOCAL: + if (pcm->access != SND_PCM_ACCESS_MMAP_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED) + continue; + break; + default: + assert(0); + } + i1->addr = i->addr; + } + a->addr = i->addr; + a->first = i->first; + a->step = i->step; + } + return 0; +} + +int snd_pcm_munmap(snd_pcm_t *pcm) +{ + int err; + unsigned int c; + assert(pcm); + if (CHECK_SANITY(! pcm->mmap_channels)) { + SNDMSG("Not mmapped"); + return -ENXIO; + } + if (pcm->mmap_shadow) + return pcm->ops->munmap(pcm); + for (c = 0; c < pcm->channels; ++c) { + snd_pcm_channel_info_t *i = &pcm->mmap_channels[c]; + unsigned int c1; + size_t size = i->first + i->step * (pcm->buffer_size - 1) + pcm->sample_bits; + if (!i->addr) + continue; + for (c1 = c + 1; c1 < pcm->channels; ++c1) { + snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; + size_t s; + if (i1->addr != i->addr) + continue; + i1->addr = NULL; + s = i1->first + i1->step * (pcm->buffer_size - 1) + pcm->sample_bits; + if (s > size) + size = s; + } + size = (size + 7) / 8; + size = page_align(size); + switch (i->type) { + case SND_PCM_AREA_MMAP: + err = munmap(i->addr, size); + if (err < 0) { + SYSERR("mmap failed"); + return -errno; + } + errno = 0; + break; + case SND_PCM_AREA_SHM: + if (i->u.shm.area) { + snd_shm_area_destroy(i->u.shm.area); + i->u.shm.area = NULL; + if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED || + pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) { + unsigned int c1; + for (c1 = c + 1; c1 < pcm->channels; c1++) { + snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; + if (i1->u.shm.area) { + snd_shm_area_destroy(i1->u.shm.area); + i1->u.shm.area = NULL; + } + } + } + } + break; + case SND_PCM_AREA_LOCAL: + free(i->addr); + break; + default: + assert(0); + } + i->addr = NULL; + } + err = pcm->ops->munmap(pcm); + if (err < 0) + return err; + free(pcm->mmap_channels); + free(pcm->running_areas); + pcm->mmap_channels = NULL; + pcm->running_areas = NULL; + return 0; +} + +snd_pcm_sframes_t snd_pcm_write_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_uframes_t xfer = 0; + snd_pcm_sframes_t err = 0; + if (! size) + return 0; + while (xfer < size) { + snd_pcm_uframes_t frames = size - xfer; + snd_pcm_uframes_t cont = pcm->buffer_size - offset; + if (cont < frames) + frames = cont; + switch (pcm->access) { + case SND_PCM_ACCESS_MMAP_INTERLEAVED: + { + const snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm); + const char *buf = snd_pcm_channel_area_addr(a, offset); + err = _snd_pcm_writei(pcm, buf, frames); + if (err >= 0) + frames = err; + break; + } + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: + { + unsigned int channels = pcm->channels; + unsigned int c; + void *bufs[channels]; + const snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm); + for (c = 0; c < channels; ++c) { + const snd_pcm_channel_area_t *a = &areas[c]; + bufs[c] = snd_pcm_channel_area_addr(a, offset); + } + err = _snd_pcm_writen(pcm, bufs, frames); + if (err >= 0) + frames = err; + break; + } + default: + SNDMSG("invalid access type %d", pcm->access); + return -EINVAL; + } + if (err < 0) + break; + xfer += frames; + offset = (offset + frames) % pcm->buffer_size; + } + if (xfer > 0) + return xfer; + return err; +} + +snd_pcm_sframes_t snd_pcm_read_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_uframes_t xfer = 0; + snd_pcm_sframes_t err = 0; + if (! size) + return 0; + while (xfer < size) { + snd_pcm_uframes_t frames = size - xfer; + snd_pcm_uframes_t cont = pcm->buffer_size - offset; + if (cont < frames) + frames = cont; + switch (pcm->access) { + case SND_PCM_ACCESS_MMAP_INTERLEAVED: + { + const snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm); + char *buf = snd_pcm_channel_area_addr(a, offset); + err = _snd_pcm_readi(pcm, buf, frames); + if (err >= 0) + frames = err; + break; + } + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: + { + snd_pcm_uframes_t channels = pcm->channels; + unsigned int c; + void *bufs[channels]; + const snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm); + for (c = 0; c < channels; ++c) { + const snd_pcm_channel_area_t *a = &areas[c]; + bufs[c] = snd_pcm_channel_area_addr(a, offset); + } + err = _snd_pcm_readn(pcm->fast_op_arg, bufs, frames); + if (err >= 0) + frames = err; + } + default: + SNDMSG("invalid access type %d", pcm->access); + return -EINVAL; + } + if (err < 0) + break; + xfer += frames; + offset = (offset + frames) % pcm->buffer_size; + } + if (xfer > 0) + return xfer; + return err; +} diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c new file mode 100644 index 0000000..f6e7ae9 --- /dev/null +++ b/src/pcm/pcm_mmap_emul.c @@ -0,0 +1,512 @@ +/** + * \file pcm/pcm_mmap_emul.c + * \ingroup PCM_Plugins + * \brief PCM Mmap-Emulation Plugin Interface + * \author Takashi Iwai + * \date 2007 + */ +/* + * PCM - Mmap-Emulation + * Copyright (c) 2007 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" +#include "pcm_generic.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_mmap_emul = ""; +#endif + +#ifndef DOC_HIDDEN +/* + * + */ + +typedef struct { + snd_pcm_generic_t gen; + unsigned int mmap_emul :1; + snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t start_threshold; +} mmap_emul_t; +#endif + +/* + * here goes a really tricky part; hw_refine falls back to ACCESS_RW_* type + * when ACCESS_MMAP_* isn't supported by the hardware. + */ +static int snd_pcm_mmap_emul_hw_refine(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + mmap_emul_t *map = pcm->private_data; + int err = 0; + snd_pcm_access_mask_t oldmask = + *snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); + snd_pcm_access_mask_t mask; + const snd_mask_t *pmask; + + snd_mask_none(&mask); + err = snd_pcm_hw_refine(map->gen.slave, params); + if (err < 0) { + snd_pcm_hw_params_t new = *params; + + /* try to use RW_* */ + if (snd_pcm_access_mask_test(&oldmask, + SND_PCM_ACCESS_MMAP_INTERLEAVED) && + !snd_pcm_access_mask_test(&oldmask, + SND_PCM_ACCESS_RW_INTERLEAVED)) + snd_pcm_access_mask_set(&mask, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (snd_pcm_access_mask_test(&oldmask, + SND_PCM_ACCESS_MMAP_NONINTERLEAVED) && + !snd_pcm_access_mask_test(&oldmask, + SND_PCM_ACCESS_RW_NONINTERLEAVED)) + snd_pcm_access_mask_set(&mask, + SND_PCM_ACCESS_RW_NONINTERLEAVED); + if (snd_pcm_access_mask_empty(&mask)) + return err; + pmask = snd_pcm_hw_param_get_mask(&new, + SND_PCM_HW_PARAM_ACCESS); + *(snd_mask_t *)pmask = mask; + err = snd_pcm_hw_refine(map->gen.slave, &new); + if (err < 0) + return err; + *params = new; + } + + pmask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_INTERLEAVED) || + snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) || + snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_COMPLEX)) + return 0; + if (snd_pcm_access_mask_test(&mask, SND_PCM_ACCESS_RW_INTERLEAVED)) { + if (snd_pcm_access_mask_test(pmask, + SND_PCM_ACCESS_RW_INTERLEAVED)) + snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask, + SND_PCM_ACCESS_MMAP_INTERLEAVED); + snd_pcm_access_mask_reset((snd_pcm_access_mask_t *)pmask, + SND_PCM_ACCESS_RW_INTERLEAVED); + params->cmask |= 1<cmask |= 1<cmask |= 1<cmask |= 1<private_data; + snd_pcm_hw_params_t old = *params; + snd_pcm_access_t access; + snd_pcm_access_mask_t oldmask; + snd_pcm_access_mask_t *pmask; + int err; + + err = _snd_pcm_hw_params(map->gen.slave, params); + if (err >= 0) { + map->mmap_emul = 0; + return err; + } + + *params = old; + pmask = (snd_pcm_access_mask_t *)snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); + oldmask = *pmask; + if (INTERNAL(snd_pcm_hw_params_get_access)(params, &access) < 0) + goto _err; + switch (access) { + case SND_PCM_ACCESS_MMAP_INTERLEAVED: + snd_pcm_access_mask_reset(pmask, + SND_PCM_ACCESS_MMAP_INTERLEAVED); + snd_pcm_access_mask_set(pmask, SND_PCM_ACCESS_RW_INTERLEAVED); + break; + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: + snd_pcm_access_mask_reset(pmask, + SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + snd_pcm_access_mask_set(pmask, + SND_PCM_ACCESS_RW_NONINTERLEAVED); + break; + default: + goto _err; + } + err = _snd_pcm_hw_params(map->gen.slave, params); + if (err < 0) + goto _err; + + /* need to back the access type to relieve apps */ + *pmask = oldmask; + + /* OK, we do fake */ + map->mmap_emul = 1; + map->appl_ptr = 0; + map->hw_ptr = 0; + snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0); + return 0; + + _err: + err = -errno; + return err; +} + +static int snd_pcm_mmap_emul_sw_params(snd_pcm_t *pcm, + snd_pcm_sw_params_t *params) +{ + mmap_emul_t *map = pcm->private_data; + int err; + + map->start_threshold = params->start_threshold; + + /* HACK: don't auto-start in the slave PCM */ + params->start_threshold = pcm->boundary; + err = snd_pcm_generic_sw_params(pcm, params); + if (err < 0) + return err; + /* restore the value for this PCM */ + params->start_threshold = map->start_threshold; + return err; +} + +static int snd_pcm_mmap_emul_prepare(snd_pcm_t *pcm) +{ + mmap_emul_t *map = pcm->private_data; + int err; + + err = snd_pcm_generic_prepare(pcm); + if (err < 0) + return err; + map->hw_ptr = map->appl_ptr = 0; + return err; +} + +static int snd_pcm_mmap_emul_reset(snd_pcm_t *pcm) +{ + mmap_emul_t *map = pcm->private_data; + int err; + + err = snd_pcm_generic_reset(pcm); + if (err < 0) + return err; + map->hw_ptr = map->appl_ptr = 0; + return err; +} + +static snd_pcm_sframes_t +snd_pcm_mmap_emul_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + frames = snd_pcm_generic_rewind(pcm, frames); + if (frames > 0) + snd_pcm_mmap_appl_backward(pcm, frames); + return frames; +} + +static snd_pcm_sframes_t +snd_pcm_mmap_emul_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + frames = snd_pcm_generic_forward(pcm, frames); + if (frames > 0) + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; +} + +/* write out the uncommitted chunk on mmap buffer to the slave PCM */ +static snd_pcm_sframes_t +sync_slave_write(snd_pcm_t *pcm) +{ + mmap_emul_t *map = pcm->private_data; + snd_pcm_t *slave = map->gen.slave; + snd_pcm_uframes_t offset; + snd_pcm_sframes_t size; + + /* HACK: don't start stream automatically at commit in mmap mode */ + pcm->start_threshold = pcm->boundary; + + size = map->appl_ptr - *slave->appl.ptr; + if (size < 0) + size += pcm->boundary; + if (size) { + offset = *slave->appl.ptr % pcm->buffer_size; + size = snd_pcm_write_mmap(pcm, offset, size); + } + pcm->start_threshold = map->start_threshold; /* restore */ + return size; +} + +/* read the available chunk on the slave PCM to mmap buffer */ +static snd_pcm_sframes_t +sync_slave_read(snd_pcm_t *pcm) +{ + mmap_emul_t *map = pcm->private_data; + snd_pcm_t *slave = map->gen.slave; + snd_pcm_uframes_t offset; + snd_pcm_sframes_t size; + + size = *slave->hw.ptr - map->hw_ptr; + if (size < 0) + size += pcm->boundary; + if (!size) + return 0; + offset = map->hw_ptr % pcm->buffer_size; + size = snd_pcm_read_mmap(pcm, offset, size); + if (size > 0) + snd_pcm_mmap_hw_forward(pcm, size); + return 0; +} + +static snd_pcm_sframes_t +snd_pcm_mmap_emul_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + mmap_emul_t *map = pcm->private_data; + snd_pcm_t *slave = map->gen.slave; + + if (!map->mmap_emul) + return snd_pcm_mmap_commit(slave, offset, size); + snd_pcm_mmap_appl_forward(pcm, size); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + sync_slave_write(pcm); + return size; +} + +static snd_pcm_sframes_t snd_pcm_mmap_emul_avail_update(snd_pcm_t *pcm) +{ + mmap_emul_t *map = pcm->private_data; + snd_pcm_t *slave = map->gen.slave; + snd_pcm_sframes_t avail; + + avail = snd_pcm_avail_update(slave); + if (!map->mmap_emul) + return avail; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + map->hw_ptr = *slave->hw.ptr; + else + sync_slave_read(pcm); + return snd_pcm_mmap_avail(pcm); +} + +static void snd_pcm_mmap_emul_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + mmap_emul_t *map = pcm->private_data; + + snd_output_printf(out, "Mmap emulation PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(map->gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_mmap_emul_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_mmap_emul_hw_refine, + .hw_params = snd_pcm_mmap_emul_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_mmap_emul_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_mmap_emul_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = { + .status = snd_pcm_generic_status, + .state = snd_pcm_generic_state, + .hwsync = snd_pcm_generic_hwsync, + .delay = snd_pcm_generic_delay, + .prepare = snd_pcm_mmap_emul_prepare, + .reset = snd_pcm_mmap_emul_reset, + .start = snd_pcm_generic_start, + .drop = snd_pcm_generic_drop, + .drain = snd_pcm_generic_drain, + .pause = snd_pcm_generic_pause, + .rewindable = snd_pcm_generic_rewindable, + .rewind = snd_pcm_mmap_emul_rewind, + .forwardable = snd_pcm_generic_forwardable, + .forward = snd_pcm_mmap_emul_forward, + .resume = snd_pcm_generic_resume, + .link = snd_pcm_generic_link, + .link_slaves = snd_pcm_generic_link_slaves, + .unlink = snd_pcm_generic_unlink, + .writei = snd_pcm_generic_writei, + .writen = snd_pcm_generic_writen, + .readi = snd_pcm_generic_readi, + .readn = snd_pcm_generic_readn, + .avail_update = snd_pcm_mmap_emul_avail_update, + .mmap_commit = snd_pcm_mmap_emul_mmap_commit, + .htimestamp = snd_pcm_generic_htimestamp, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_revents = snd_pcm_generic_poll_revents, +}; + +#ifndef DOC_HIDDEN +int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + mmap_emul_t *map; + int err; + + map = calloc(1, sizeof(*map)); + if (!map) + return -ENOMEM; + map->gen.slave = slave; + map->gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_MMAP_EMUL, name, + slave->stream, slave->mode); + if (err < 0) { + free(map); + return err; + } + pcm->ops = &snd_pcm_mmap_emul_ops; + pcm->fast_ops = &snd_pcm_mmap_emul_fast_ops; + pcm->private_data = map; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} +#endif + +/*! \page pcm_plugins + +\section pcm_plugins_mmap_emul Plugin: mmap_emul + +\code +pcm.name { + type mmap_emul + slave PCM +} +\endcode + +\subsection pcm_plugins_mmap_emul_funcref Function reference + +
    +
  • _snd_pcm_hw_open() +
+ +*/ + +/** + * \brief Creates a new mmap_emul PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with hw PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = __snd_pcm_mmap_emul_open(pcmp, name, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} + +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_mmap_emul_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c new file mode 100644 index 0000000..22e7d96 --- /dev/null +++ b/src/pcm/pcm_mulaw.c @@ -0,0 +1,568 @@ +/** + * \file pcm/pcm_mulaw.c + * \ingroup PCM_Plugins + * \brief PCM Mu-Law Conversion Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Mu-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_mulaw = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef void (*mulaw_f)(const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getputidx); + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + unsigned int getput_idx; + mulaw_f func; + snd_pcm_format_t sformat; +} snd_pcm_mulaw_t; + +#endif + +static inline int val_seg(int val) +{ + int r = 0; + val >>= 7; + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + if (pcm_val < 0) { + pcm_val = 0x84 - pcm_val; + mask = 0x7f; + } else { + pcm_val += 0x84; + mask = 0xff; + } + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + return uval ^ mask; +} + +/* + * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +static int ulaw_to_s16(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & 0x0f) << 3) + 0x84; + t <<= (u_val & 0x70) >> 4; + + return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); +} + +#ifndef DOC_HIDDEN + +void snd_pcm_mulaw_decode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int putidx) +{ +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS + void *put = put16_labels[putidx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { + const unsigned char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + int16_t sample = ulaw_to_s16(*src); + goto *put; +#define PUT16_END after +#include "plugin_ops.h" +#undef PUT16_END + after: + src += src_step; + dst += dst_step; + } + } +} + +void snd_pcm_mulaw_encode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getidx) +{ +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS + void *get = get16_labels[getidx]; + unsigned int channel; + int16_t sample = 0; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { + goto *get; +#define GET16_END after +#include "plugin_ops.h" +#undef GET16_END + after: + *dst = s16_to_ulaw(sample); + src += src_step; + dst += dst_step; + } + } +} + +#endif /* DOC_HIDDEN */ + +static int snd_pcm_mulaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_mulaw_t *mulaw = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) { + snd_pcm_format_mask_t format_mask= { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + } else { + err = _snd_pcm_hw_params_set_format(params, + SND_PCM_FORMAT_MU_LAW); + } + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_mulaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_mulaw_t *mulaw = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_params_set_format(sparams, mulaw->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + return 0; +} + +static int snd_pcm_mulaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_mulaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_mulaw_hw_refine_cprepare, + snd_pcm_mulaw_hw_refine_cchange, + snd_pcm_mulaw_hw_refine_sprepare, + snd_pcm_mulaw_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_mulaw_t *mulaw = pcm->private_data; + snd_pcm_format_t format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_mulaw_hw_refine_cchange, + snd_pcm_mulaw_hw_refine_sprepare, + snd_pcm_mulaw_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &format); + if (err < 0) + return err; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) { + mulaw->getput_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S16); + mulaw->func = snd_pcm_mulaw_encode; + } else { + mulaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, mulaw->sformat); + mulaw->func = snd_pcm_mulaw_decode; + } + } else { + if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) { + mulaw->getput_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, format); + mulaw->func = snd_pcm_mulaw_decode; + } else { + mulaw->getput_idx = snd_pcm_linear_get_index(mulaw->sformat, SND_PCM_FORMAT_S16); + mulaw->func = snd_pcm_mulaw_encode; + } + } + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_mulaw_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_mulaw_t *mulaw = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + mulaw->func(slave_areas, slave_offset, + areas, offset, + pcm->channels, size, + mulaw->getput_idx); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_mulaw_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_mulaw_t *mulaw = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + mulaw->func(areas, offset, + slave_areas, slave_offset, + pcm->channels, size, + mulaw->getput_idx); + *slave_sizep = size; + return size; +} + +static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_mulaw_t *mulaw = pcm->private_data; + snd_output_printf(out, "Mu-Law conversion PCM (%s)\n", + snd_pcm_format_name(mulaw->sformat)); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(mulaw->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_mulaw_ops = { + .close = snd_pcm_generic_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_mulaw_hw_refine, + .hw_params = snd_pcm_mulaw_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_mulaw_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new Mu-Law conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_mulaw_t *mulaw; + int err; + assert(pcmp && slave); + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_MU_LAW) + return -EINVAL; + mulaw = calloc(1, sizeof(snd_pcm_mulaw_t)); + if (!mulaw) { + return -ENOMEM; + } + snd_pcm_plugin_init(&mulaw->plug); + mulaw->sformat = sformat; + mulaw->plug.read = snd_pcm_mulaw_read_areas; + mulaw->plug.write = snd_pcm_mulaw_write_areas; + mulaw->plug.undo_read = snd_pcm_plugin_undo_read_generic; + mulaw->plug.undo_write = snd_pcm_plugin_undo_write_generic; + mulaw->plug.gen.slave = slave; + mulaw->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULAW, name, slave->stream, slave->mode); + if (err < 0) { + free(mulaw); + return err; + } + pcm->ops = &snd_pcm_mulaw_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = mulaw; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_mulaw Plugin: Mu-Law + +This plugin converts Mu-Law samples to linear or linear to Mu-Law samples +from master Mu-Law conversion PCM to given slave PCM. The channel count, +format and rate must match for both of them. + +\code +pcm.name { + type mulaw # Mu-Law conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + format STR # Slave format + } +} +\endcode + +\subsection pcm_plugins_mulaw_funcref Function reference + +
    +
  • snd_pcm_mulaw_open() +
  • _snd_pcm_mulaw_open() +
+ +*/ + +/** + * \brief Creates a new Mu-Law conversion PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with copy PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat); + if (err < 0) + return err; + if (snd_pcm_format_linear(sformat) != 1 && + sformat != SND_PCM_FORMAT_MU_LAW) { + snd_config_delete(sconf); + SNDERR("invalid slave format"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_mulaw_open(pcmp, name, sformat, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_mulaw_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c new file mode 100644 index 0000000..68f2d68 --- /dev/null +++ b/src/pcm/pcm_multi.c @@ -0,0 +1,1214 @@ +/** + * \file pcm/pcm_multi.c + * \ingroup PCM_Plugins + * \brief PCM Multi Streams to One Conversion Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Multi + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include "pcm_local.h" +#include "pcm_generic.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_multi = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef struct { + snd_pcm_t *pcm; + unsigned int channels_count; + int close_slave; + snd_pcm_t *linked; +} snd_pcm_multi_slave_t; + +typedef struct { + int slave_idx; + unsigned int slave_channel; +} snd_pcm_multi_channel_t; + +typedef struct { + unsigned int slaves_count; + unsigned int master_slave; + snd_pcm_multi_slave_t *slaves; + unsigned int channels_count; + snd_pcm_multi_channel_t *channels; +} snd_pcm_multi_t; + +#endif + +static int snd_pcm_multi_close(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + int ret = 0; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_multi_slave_t *slave = &multi->slaves[i]; + if (slave->close_slave) { + int err = snd_pcm_close(slave->pcm); + if (err < 0) + ret = err; + } + } + free(multi->slaves); + free(multi->channels); + free(multi); + return ret; +} + +static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_multi_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; + return snd_pcm_async(slave_0, sig, pid); +} + +static int snd_pcm_multi_poll_descriptors_count(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; + return snd_pcm_poll_descriptors_count(slave_0); +} + +static int snd_pcm_multi_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave; + snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; + int err; + unsigned int i; + + for (i = 0; i < multi->slaves_count; ++i) { + slave = multi->slaves[i].pcm; + if (slave == slave_0) + continue; + err = snd_pcm_poll_descriptors(slave, pfds, space); + if (err < 0) + return err; + } + /* finally overwrite with master's pfds */ + return snd_pcm_poll_descriptors(slave_0, pfds, space); +} + +static int snd_pcm_multi_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm; + return snd_pcm_poll_descriptors_revents(slave_0, pfds, nfds, revents); +} + +static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err, n; + assert(info->subdevice < multi->slaves_count); + n = info->subdevice; + info->subdevice = 0; + err = snd_pcm_info(multi->slaves[n].pcm, info); + if (err < 0) + return err; + info->subdevices_count = multi->slaves_count; + return 0; +} + +static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_access_mask_t access_mask; + int err; + snd_pcm_access_mask_any(&access_mask); + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, + multi->channels_count, 0); + if (err < 0) + return err; + params->info = ~0U; + return 0; +} + +static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, unsigned int slave_idx, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx]; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, + slave->channels_count, 0); + return 0; +} + +static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + unsigned int slave_idx ATTRIBUTE_UNUSED, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) && + !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { + snd_pcm_access_mask_t saccess_mask; + snd_pcm_access_mask_any(&saccess_mask); + snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + unsigned int slave_idx ATTRIBUTE_UNUSED, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + snd_pcm_access_mask_t access_mask; + const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS); + snd_pcm_access_mask_any(&access_mask); + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && + !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX); + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + params->info &= sparams->info; + return 0; +} + +static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm, + unsigned int slave_idx, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[slave_idx].pcm; + return snd_pcm_hw_refine(slave, sparams); +} + +static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int k; + snd_pcm_hw_params_t sparams[multi->slaves_count]; + int err; + unsigned int cmask, changed; + err = snd_pcm_multi_hw_refine_cprepare(pcm, params); + if (err < 0) + return err; + for (k = 0; k < multi->slaves_count; ++k) { + err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]); + if (err < 0) { + SNDERR("Slave PCM #%d not usable", k); + return err; + } + } + do { + cmask = params->cmask; + params->cmask = 0; + for (k = 0; k < multi->slaves_count; ++k) { + err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]); + if (err >= 0) + err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]); + if (err < 0) { + snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); + return err; + } + err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]); + if (err < 0) + return err; + } + err = snd_pcm_hw_refine_soft(pcm, params); + changed = params->cmask; + params->cmask |= cmask; + if (err < 0) + return err; + } while (changed); + return 0; +} + +static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm, + unsigned int slave_idx, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[slave_idx].pcm; + int err = snd_pcm_hw_params(slave, sparams); + if (err < 0) + return err; + err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format); + if (err < 0) + return err; + if (slave->stopped_areas) { + err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format); + if (err < 0) + return err; + } + return 0; +} + +/* reset links to the normal state + * slave #0 = trigger master + * slave #1-(N-1) = trigger slaves, linked is set to #0 + */ +static void reset_links(snd_pcm_multi_t *multi) +{ + unsigned int i; + + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + snd_pcm_unlink(multi->slaves[i].linked); + multi->slaves[0].linked = NULL; + if (! i) + continue; + if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0) + multi->slaves[i].linked = multi->slaves[0].pcm; + } +} + +static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + snd_pcm_hw_params_t sparams[multi->slaves_count]; + int err; + for (i = 0; i < multi->slaves_count; ++i) { + err = snd_pcm_multi_hw_refine_sprepare(pcm, i, &sparams[i]); + assert(err >= 0); + err = snd_pcm_multi_hw_refine_schange(pcm, i, params, &sparams[i]); + assert(err >= 0); + err = snd_pcm_multi_hw_params_slave(pcm, i, &sparams[i]); + if (err < 0) { + snd_pcm_multi_hw_refine_cchange(pcm, i, params, &sparams[i]); + return err; + } + } + reset_links(multi); + return 0; +} + +static int snd_pcm_multi_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + int err = 0; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave = multi->slaves[i].pcm; + int e = snd_pcm_hw_free(slave); + if (e < 0) + err = e; + if (!multi->slaves[i].linked) + continue; + e = snd_pcm_unlink(slave); + if (e < 0) + err = e; + multi->slaves[i].linked = NULL; + } + return err; +} + +static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + int err; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave = multi->slaves[i].pcm; + err = snd_pcm_sw_params(slave, params); + if (err < 0) + return err; + } + return 0; +} + +static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; + return snd_pcm_status(slave, status); +} + +static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; + return snd_pcm_state(slave); +} + +static int snd_pcm_multi_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; + return snd_pcm_hwsync(slave); +} + +static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; + return snd_pcm_delay(slave, delayp); +} + +static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_sframes_t ret = LONG_MAX; + unsigned int i; + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_sframes_t avail; + avail = snd_pcm_avail_update(multi->slaves[i].pcm); + if (avail < 0) + return avail; + if (ret > avail) + ret = avail; + } + return ret; +} + +static int snd_pcm_multi_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm; + return snd_pcm_htimestamp(slave, avail, tstamp); +} + +static int snd_pcm_multi_prepare(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int result = 0, err; + unsigned int i; + for (i = 0; i < multi->slaves_count; ++i) { + /* We call prepare to each slave even if it's linked. + * This is to make sure to sync non-mmaped control/status. + */ + err = snd_pcm_prepare(multi->slaves[i].pcm); + if (err < 0) + result = err; + } + return result; +} + +static int snd_pcm_multi_reset(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int result = 0, err; + unsigned int i; + for (i = 0; i < multi->slaves_count; ++i) { + /* Reset each slave, as well as in prepare */ + err = snd_pcm_reset(multi->slaves[i].pcm); + if (err < 0) + result = err; + } + return result; +} + +/* when the first slave PCM is linked, it means that the whole multi + * plugin instance is linked manually to another PCM. in this case, + * we need to trigger the master. + */ +static int snd_pcm_multi_start(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err = 0; + unsigned int i; + if (multi->slaves[0].linked) + return snd_pcm_start(multi->slaves[0].linked); + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + continue; + err = snd_pcm_start(multi->slaves[i].pcm); + if (err < 0) + return err; + } + return err; +} + +static int snd_pcm_multi_drop(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err = 0; + unsigned int i; + if (multi->slaves[0].linked) + return snd_pcm_drop(multi->slaves[0].linked); + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + continue; + err = snd_pcm_drop(multi->slaves[i].pcm); + if (err < 0) + return err; + } + return err; +} + +static int snd_pcm_multi_drain(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err = 0; + unsigned int i; + if (multi->slaves[0].linked) + return snd_pcm_drain(multi->slaves[0].linked); + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + continue; + err = snd_pcm_drain(multi->slaves[i].pcm); + if (err < 0) + return err; + } + return err; +} + +static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err = 0; + unsigned int i; + if (multi->slaves[0].linked) + return snd_pcm_pause(multi->slaves[0].linked, enable); + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + continue; + err = snd_pcm_pause(multi->slaves[i].pcm, enable); + if (err < 0) + return err; + } + return err; +} + +static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int channel = info->channel; + snd_pcm_multi_channel_t *c = &multi->channels[channel]; + int err; + if (c->slave_idx < 0) + return -ENXIO; + info->channel = c->slave_channel; + err = snd_pcm_channel_info(multi->slaves[c->slave_idx].pcm, info); + info->channel = channel; + return err; +} + +static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + snd_pcm_uframes_t pos[multi->slaves_count]; + memset(pos, 0, sizeof(pos)); + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave_i = multi->slaves[i].pcm; + snd_pcm_sframes_t f = snd_pcm_rewind(slave_i, frames); + if (f < 0) + return f; + pos[i] = f; + frames = f; + } + /* Realign the pointers */ + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave_i = multi->slaves[i].pcm; + snd_pcm_uframes_t f = pos[i] - frames; + snd_pcm_sframes_t result; + if (f > 0) { + result = INTERNAL(snd_pcm_forward)(slave_i, f); + if (result < 0) + return result; + if ((snd_pcm_uframes_t)result != f) + return -EIO; + } + } + return frames; +} + +static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + snd_pcm_uframes_t pos[multi->slaves_count]; + memset(pos, 0, sizeof(pos)); + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave_i = multi->slaves[i].pcm; + snd_pcm_sframes_t f = INTERNAL(snd_pcm_forward)(slave_i, frames); + if (f < 0) + return f; + pos[i] = f; + frames = f; + } + /* Realign the pointers */ + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_t *slave_i = multi->slaves[i].pcm; + snd_pcm_uframes_t f = pos[i] - frames; + snd_pcm_sframes_t result; + if (f > 0) { + result = snd_pcm_rewind(slave_i, f); + if (result < 0) + return result; + if ((snd_pcm_uframes_t)result != f) + return -EIO; + } + } + return frames; +} + +static int snd_pcm_multi_resume(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + int err = 0; + unsigned int i; + if (multi->slaves[0].linked) + return snd_pcm_resume(multi->slaves[0].linked); + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + continue; + err = snd_pcm_resume(multi->slaves[i].pcm); + if (err < 0) + return err; + } + return err; +} + +/* if a multi plugin instance is linked as slaves, every slave PCMs + * including the first one has to be relinked to the given master. + */ +static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + int err; + + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_unlink(multi->slaves[i].pcm); + multi->slaves[i].linked = NULL; + err = snd_pcm_link(master, multi->slaves[i].pcm); + if (err < 0) { + reset_links(multi); + return err; + } + multi->slaves[i].linked = master; + } + return 0; +} + +/* linking to a multi as a master is easy - simply link to the first + * slave element as its own slaves are already linked. + */ +static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) +{ + snd_pcm_multi_t *multi = pcm1->private_data; + if (multi->slaves[0].pcm->fast_ops->link) + return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2); + return -ENOSYS; +} + +static int snd_pcm_multi_unlink(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + + for (i = 0; i < multi->slaves_count; ++i) { + if (multi->slaves[i].linked) + snd_pcm_unlink(multi->slaves[i].linked); + multi->slaves[0].linked = NULL; + } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_t *slave; + unsigned int i; + snd_pcm_sframes_t result; + + for (i = 0; i < multi->slaves_count; ++i) { + slave = multi->slaves[i].pcm; + result = snd_pcm_mmap_commit(slave, offset, size); + if (result < 0) + return result; + if ((snd_pcm_uframes_t)result != size) + return -EIO; + } + return size; +} + +static int snd_pcm_multi_munmap(snd_pcm_t *pcm) +{ + free(pcm->mmap_channels); + free(pcm->running_areas); + pcm->mmap_channels = NULL; + pcm->running_areas = NULL; + return 0; +} + +static int snd_pcm_multi_mmap(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int c; + + pcm->mmap_channels = calloc(pcm->channels, + sizeof(pcm->mmap_channels[0])); + pcm->running_areas = calloc(pcm->channels, + sizeof(pcm->running_areas[0])); + if (!pcm->mmap_channels || !pcm->running_areas) { + snd_pcm_multi_munmap(pcm); + return -ENOMEM; + } + + /* Copy the slave mmapped buffer data */ + for (c = 0; c < pcm->channels; c++) { + snd_pcm_multi_channel_t *chan = &multi->channels[c]; + snd_pcm_t *slave; + if (chan->slave_idx < 0) { + snd_pcm_multi_munmap(pcm); + return -ENXIO; + } + slave = multi->slaves[chan->slave_idx].pcm; + pcm->mmap_channels[c] = + slave->mmap_channels[chan->slave_channel]; + pcm->mmap_channels[c].channel = c; + pcm->running_areas[c] = + slave->running_areas[chan->slave_channel]; + } + return 0; +} + +static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int k; + snd_output_printf(out, "Multi PCM\n"); + snd_output_printf(out, " Channel bindings:\n"); + for (k = 0; k < multi->channels_count; ++k) { + snd_pcm_multi_channel_t *c = &multi->channels[k]; + if (c->slave_idx < 0) + continue; + snd_output_printf(out, " %d: slave %d, channel %d\n", + k, c->slave_idx, c->slave_channel); + } + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + for (k = 0; k < multi->slaves_count; ++k) { + snd_output_printf(out, "Slave #%d: ", k); + snd_pcm_dump(multi->slaves[k].pcm, out); + } +} + +static const snd_pcm_ops_t snd_pcm_multi_ops = { + .close = snd_pcm_multi_close, + .info = snd_pcm_multi_info, + .hw_refine = snd_pcm_multi_hw_refine, + .hw_params = snd_pcm_multi_hw_params, + .hw_free = snd_pcm_multi_hw_free, + .sw_params = snd_pcm_multi_sw_params, + .channel_info = snd_pcm_multi_channel_info, + .dump = snd_pcm_multi_dump, + .nonblock = snd_pcm_multi_nonblock, + .async = snd_pcm_multi_async, + .mmap = snd_pcm_multi_mmap, + .munmap = snd_pcm_multi_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { + .status = snd_pcm_multi_status, + .state = snd_pcm_multi_state, + .hwsync = snd_pcm_multi_hwsync, + .delay = snd_pcm_multi_delay, + .prepare = snd_pcm_multi_prepare, + .reset = snd_pcm_multi_reset, + .start = snd_pcm_multi_start, + .drop = snd_pcm_multi_drop, + .drain = snd_pcm_multi_drain, + .pause = snd_pcm_multi_pause, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_mmap_readi, + .readn = snd_pcm_mmap_readn, + .rewind = snd_pcm_multi_rewind, + .forward = snd_pcm_multi_forward, + .resume = snd_pcm_multi_resume, + .link = snd_pcm_multi_link, + .link_slaves = snd_pcm_multi_link_slaves, + .unlink = snd_pcm_multi_unlink, + .avail_update = snd_pcm_multi_avail_update, + .mmap_commit = snd_pcm_multi_mmap_commit, + .htimestamp = snd_pcm_multi_htimestamp, + .poll_descriptors_count = snd_pcm_multi_poll_descriptors_count, + .poll_descriptors = snd_pcm_multi_poll_descriptors, + .poll_revents = snd_pcm_multi_poll_revents, +}; + +/** + * \brief Creates a new Multi PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param slaves_count Count of slaves + * \param master_slave Master slave number + * \param slaves_pcm Array with slave PCMs + * \param schannels_count Array with slave channel counts + * \param channels_count Count of channels + * \param sidxs Array with channels indexes to slaves + * \param schannels Array with slave channels + * \param close_slaves When set, the slave PCM handle is closed + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, + unsigned int slaves_count, unsigned int master_slave, + snd_pcm_t **slaves_pcm, unsigned int *schannels_count, + unsigned int channels_count, + int *sidxs, unsigned int *schannels, + int close_slaves) +{ + snd_pcm_t *pcm; + snd_pcm_multi_t *multi; + unsigned int i; + snd_pcm_stream_t stream; + char slave_map[64][64] = { { 0 } }; + int err; + + assert(pcmp); + assert(slaves_count > 0 && slaves_pcm && schannels_count); + assert(channels_count > 0 && sidxs && schannels); + assert(master_slave < slaves_count); + + multi = calloc(1, sizeof(snd_pcm_multi_t)); + if (!multi) { + return -ENOMEM; + } + + stream = slaves_pcm[0]->stream; + + multi->slaves_count = slaves_count; + multi->master_slave = master_slave; + multi->slaves = calloc(slaves_count, sizeof(*multi->slaves)); + if (!multi->slaves) { + free(multi); + return -ENOMEM; + } + multi->channels_count = channels_count; + multi->channels = calloc(channels_count, sizeof(*multi->channels)); + if (!multi->channels) { + free(multi->slaves); + free(multi); + return -ENOMEM; + } + for (i = 0; i < slaves_count; ++i) { + snd_pcm_multi_slave_t *slave = &multi->slaves[i]; + assert(slaves_pcm[i]->stream == stream); + slave->pcm = slaves_pcm[i]; + slave->channels_count = schannels_count[i]; + slave->close_slave = close_slaves; + } + for (i = 0; i < channels_count; ++i) { + snd_pcm_multi_channel_t *bind = &multi->channels[i]; + assert(sidxs[i] < (int)slaves_count); + assert(schannels[i] < schannels_count[sidxs[i]]); + bind->slave_idx = sidxs[i]; + bind->slave_channel = schannels[i]; + if (sidxs[i] < 0) + continue; + assert(!slave_map[sidxs[i]][schannels[i]]); + slave_map[sidxs[i]][schannels[i]] = 1; + } + multi->channels_count = channels_count; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULTI, name, stream, + multi->slaves[0].pcm->mode); + if (err < 0) { + free(multi); + return err; + } + pcm->mmap_rw = 1; + pcm->mmap_shadow = 1; /* has own mmap method */ + pcm->ops = &snd_pcm_multi_ops; + pcm->fast_ops = &snd_pcm_multi_fast_ops; + pcm->private_data = multi; + pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd; + pcm->poll_events = multi->slaves[master_slave].pcm->poll_events; + pcm->monotonic = multi->slaves[master_slave].pcm->monotonic; + snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm); + snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm); + *pcmp = pcm; + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_multi Plugin: Multiple streams to One + +This plugin converts multiple streams to one. + +\code +pcm.name { + type multi # Multiple streams conversion PCM + slaves { # Slaves definition + ID STR # Slave PCM name + # or + ID { + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + channels INT # Slave channels + } + } + bindings { # Bindings table + N { + slave STR # Slave key + channel INT # Slave channel + } + } + [master INT] # Define the master slave +} +\endcode + +For example, to bind two PCM streams with two-channel stereo (hw:0,0 and +hw:0,1) as one 4-channel stereo PCM stream, define like this: +\code +pcm.quad { + type multi + + slaves.a.pcm "hw:0,0" + slaves.a.channels 2 + slaves.b.pcm "hw:0,1" + slaves.b.channels 2 + + bindings.0.slave a + bindings.0.channel 0 + bindings.1.slave a + bindings.1.channel 1 + bindings.2.slave b + bindings.2.channel 0 + bindings.3.slave b + bindings.3.channel 1 +} +\endcode +Note that the resultant pcm "quad" is not in the interleaved format +but in the "complex" format. Hence, it's not accessible by applications +which can handle only the interleaved (or the non-interleaved) format. +In such a case, wrap this PCM with \ref pcm_plugins_route "route" or +\ref pcm_plugins_plug "plug" plugin. +\code +pcm.quad2 { + type route + slave.pcm "quad" + ttable.0.0 1 + ttable.1.1 1 + ttable.2.2 1 + ttable.3.3 1 +} +\endcode + +\subsection pcm_plugins_multi_funcref Function reference + +
    +
  • snd_pcm_multi_open() +
  • _snd_pcm_multi_open() +
+ +*/ + +/** + * \brief Creates a new Multi PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Multi PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, inext, j, jnext; + snd_config_t *slaves = NULL; + snd_config_t *bindings = NULL; + int err; + unsigned int idx; + const char **slaves_id = NULL; + snd_config_t **slaves_conf = NULL; + snd_pcm_t **slaves_pcm = NULL; + unsigned int *slaves_channels = NULL; + int *channels_sidx = NULL; + unsigned int *channels_schannel = NULL; + unsigned int slaves_count = 0; + long master_slave = 0; + unsigned int channels_count = 0; + snd_config_for_each(i, inext, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slaves") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + slaves = n; + continue; + } + if (strcmp(id, "bindings") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + bindings = n; + continue; + } + if (strcmp(id, "master") == 0) { + if (snd_config_get_integer(n, &master_slave) < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slaves) { + SNDERR("slaves is not defined"); + return -EINVAL; + } + if (!bindings) { + SNDERR("bindings is not defined"); + return -EINVAL; + } + snd_config_for_each(i, inext, slaves) { + ++slaves_count; + } + if (master_slave < 0 || master_slave >= (long)slaves_count) { + SNDERR("Master slave is out of range (0-%u)\n", slaves_count-1); + return -EINVAL; + } + snd_config_for_each(i, inext, bindings) { + long cchannel; + snd_config_t *m = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(m, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0 || cchannel < 0) { + SNDERR("Invalid channel number: %s", id); + return -EINVAL; + } + if ((unsigned long)cchannel >= channels_count) + channels_count = cchannel + 1; + } + if (channels_count == 0) { + SNDERR("No channels defined"); + return -EINVAL; + } + slaves_id = calloc(slaves_count, sizeof(*slaves_id)); + slaves_conf = calloc(slaves_count, sizeof(*slaves_conf)); + slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm)); + slaves_channels = calloc(slaves_count, sizeof(*slaves_channels)); + channels_sidx = calloc(channels_count, sizeof(*channels_sidx)); + channels_schannel = calloc(channels_count, sizeof(*channels_schannel)); + if (!slaves_id || !slaves_conf || !slaves_pcm || !slaves_channels || + !channels_sidx || !channels_schannel) { + err = -ENOMEM; + goto _free; + } + idx = 0; + for (idx = 0; idx < channels_count; ++idx) + channels_sidx[idx] = -1; + idx = 0; + snd_config_for_each(i, inext, slaves) { + snd_config_t *m = snd_config_iterator_entry(i); + const char *id; + int channels; + if (snd_config_get_id(m, &id) < 0) + continue; + slaves_id[idx] = id; + err = snd_pcm_slave_conf(root, m, &slaves_conf[idx], 1, + SND_PCM_HW_PARAM_CHANNELS, SCONF_MANDATORY, &channels); + if (err < 0) + goto _free; + slaves_channels[idx] = channels; + ++idx; + } + + snd_config_for_each(i, inext, bindings) { + snd_config_t *m = snd_config_iterator_entry(i); + long cchannel = -1; + long schannel = -1; + int slave = -1; + long val; + const char *str; + const char *id; + if (snd_config_get_id(m, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0 || cchannel < 0) { + SNDERR("Invalid channel number: %s", id); + err = -EINVAL; + goto _free; + } + snd_config_for_each(j, jnext, m) { + snd_config_t *n = snd_config_iterator_entry(j); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "slave") == 0) { + char buf[32]; + unsigned int k; + err = snd_config_get_string(n, &str); + if (err < 0) { + err = snd_config_get_integer(n, &val); + if (err < 0) { + SNDERR("Invalid value for %s", id); + goto _free; + } + sprintf(buf, "%ld", val); + str = buf; + } + for (k = 0; k < slaves_count; ++k) { + if (strcmp(slaves_id[k], str) == 0) + slave = k; + } + continue; + } + if (strcmp(id, "channel") == 0) { + err = snd_config_get_integer(n, &schannel); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _free; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _free; + } + if (slave < 0 || (unsigned int)slave >= slaves_count) { + SNDERR("Invalid or missing sidx for channel %s", id); + err = -EINVAL; + goto _free; + } + if (schannel < 0 || + (unsigned int) schannel >= slaves_channels[slave]) { + SNDERR("Invalid or missing schannel for channel %s", id); + err = -EINVAL; + goto _free; + } + channels_sidx[cchannel] = slave; + channels_schannel[cchannel] = schannel; + } + + for (idx = 0; idx < slaves_count; ++idx) { + err = snd_pcm_open_slave(&slaves_pcm[idx], root, + slaves_conf[idx], stream, mode, + conf); + if (err < 0) + goto _free; + snd_config_delete(slaves_conf[idx]); + slaves_conf[idx] = NULL; + } + err = snd_pcm_multi_open(pcmp, name, slaves_count, master_slave, + slaves_pcm, slaves_channels, + channels_count, + channels_sidx, channels_schannel, + 1); +_free: + if (err < 0) { + for (idx = 0; idx < slaves_count; ++idx) { + if (slaves_pcm[idx]) + snd_pcm_close(slaves_pcm[idx]); + } + } + if (slaves_conf) { + for (idx = 0; idx < slaves_count; ++idx) { + if (slaves_conf[idx]) + snd_config_delete(slaves_conf[idx]); + } + free(slaves_conf); + } + free(slaves_pcm); + free(slaves_channels); + free(channels_sidx); + free(channels_schannel); + free(slaves_id); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_multi_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c new file mode 100644 index 0000000..692254a --- /dev/null +++ b/src/pcm/pcm_null.c @@ -0,0 +1,432 @@ +/** + * \file pcm/pcm_null.c + * \ingroup PCM_Plugins + * \brief PCM Null Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Null plugin + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_null = ""; +#endif + +#ifndef DOC_HIDDEN +typedef struct { + snd_htimestamp_t trigger_tstamp; + snd_pcm_state_t state; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t hw_ptr; + int poll_fd; +} snd_pcm_null_t; +#endif + +static int snd_pcm_null_close(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + close(null->poll_fd); + free(null); + return 0; +} + +static int snd_pcm_null_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_null_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +static int snd_pcm_null_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + memset(info, 0, sizeof(*info)); + info->stream = pcm->stream; + info->card = -1; + if (pcm->name) { + strncpy((char *)info->id, pcm->name, sizeof(info->id)); + strncpy((char *)info->name, pcm->name, sizeof(info->name)); + strncpy((char *)info->subname, pcm->name, sizeof(info->subname)); + } + info->subdevices_count = 1; + return 0; +} + +static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_null_t *null = pcm->private_data; + memset(status, 0, sizeof(*status)); + status->state = null->state; + status->trigger_tstamp = null->trigger_tstamp; + gettimestamp(&status->tstamp, pcm->monotonic); + status->avail = pcm->buffer_size; + status->avail_max = status->avail; + return 0; +} + +static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + return null->state; +} + +static int snd_pcm_null_hwsync(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp) +{ + *delayp = 0; + return 0; +} + +static int snd_pcm_null_prepare(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + null->state = SND_PCM_STATE_PREPARED; + *pcm->appl.ptr = 0; + *pcm->hw.ptr = 0; + return 0; +} + +static int snd_pcm_null_reset(snd_pcm_t *pcm) +{ + *pcm->appl.ptr = 0; + *pcm->hw.ptr = 0; + return 0; +} + +static int snd_pcm_null_start(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + assert(null->state == SND_PCM_STATE_PREPARED); + null->state = SND_PCM_STATE_RUNNING; + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + *pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size; + else + *pcm->hw.ptr = *pcm->appl.ptr; + return 0; +} + +static int snd_pcm_null_drop(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + assert(null->state != SND_PCM_STATE_OPEN); + null->state = SND_PCM_STATE_SETUP; + return 0; +} + +static int snd_pcm_null_drain(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + assert(null->state != SND_PCM_STATE_OPEN); + null->state = SND_PCM_STATE_SETUP; + return 0; +} + +static int snd_pcm_null_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_null_t *null = pcm->private_data; + if (enable) { + if (null->state != SND_PCM_STATE_RUNNING) + return -EBADFD; + null->state = SND_PCM_STATE_PAUSED; + } else { + if (null->state != SND_PCM_STATE_PAUSED) + return -EBADFD; + null->state = SND_PCM_STATE_RUNNING; + } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_null_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_null_t *null = pcm->private_data; + switch (null->state) { + case SND_PCM_STATE_RUNNING: + snd_pcm_mmap_hw_backward(pcm, frames); + /* Fall through */ + case SND_PCM_STATE_PREPARED: + snd_pcm_mmap_appl_backward(pcm, frames); + return frames; + default: + return -EBADFD; + } +} + +static snd_pcm_sframes_t snd_pcm_null_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_null_t *null = pcm->private_data; + switch (null->state) { + case SND_PCM_STATE_RUNNING: + snd_pcm_mmap_hw_forward(pcm, frames); + /* Fall through */ + case SND_PCM_STATE_PREPARED: + snd_pcm_mmap_appl_forward(pcm, frames); + return frames; + default: + return -EBADFD; + } +} + +static int snd_pcm_null_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static snd_pcm_sframes_t snd_pcm_null_xfer_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_mmap_appl_forward(pcm, size); + snd_pcm_mmap_hw_forward(pcm, size); + return size; +} + +static snd_pcm_sframes_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) +{ + return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); +} + +static snd_pcm_sframes_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) +{ + return snd_pcm_write_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); +} + +static snd_pcm_sframes_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) +{ + return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); +} + +static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) +{ + return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas); +} + +static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + return snd_pcm_null_forward(pcm, size); +} + +static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) +{ + return pcm->buffer_size; +} + +static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err = snd_pcm_hw_refine_soft(pcm, params); + params->info = SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID | + SND_PCM_INFO_RESUME | SND_PCM_INFO_PAUSE; + params->fifo_size = 0; + return err; +} + +static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_null_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) +{ + return 0; +} + +static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_output_printf(out, "Null PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } +} + +static const snd_pcm_ops_t snd_pcm_null_ops = { + .close = snd_pcm_null_close, + .info = snd_pcm_null_info, + .hw_refine = snd_pcm_null_hw_refine, + .hw_params = snd_pcm_null_hw_params, + .hw_free = snd_pcm_null_hw_free, + .sw_params = snd_pcm_null_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_null_dump, + .nonblock = snd_pcm_null_nonblock, + .async = snd_pcm_null_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { + .status = snd_pcm_null_status, + .state = snd_pcm_null_state, + .hwsync = snd_pcm_null_hwsync, + .delay = snd_pcm_null_delay, + .prepare = snd_pcm_null_prepare, + .reset = snd_pcm_null_reset, + .start = snd_pcm_null_start, + .drop = snd_pcm_null_drop, + .drain = snd_pcm_null_drain, + .pause = snd_pcm_null_pause, + .rewind = snd_pcm_null_rewind, + .forward = snd_pcm_null_forward, + .resume = snd_pcm_null_resume, + .writei = snd_pcm_null_writei, + .writen = snd_pcm_null_writen, + .readi = snd_pcm_null_readi, + .readn = snd_pcm_null_readn, + .avail_update = snd_pcm_null_avail_update, + .mmap_commit = snd_pcm_null_mmap_commit, + .htimestamp = snd_pcm_generic_real_htimestamp, +}; + +/** + * \brief Creates a new null PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm; + snd_pcm_null_t *null; + int fd; + int err; + assert(pcmp); + if (stream == SND_PCM_STREAM_PLAYBACK) { + fd = open("/dev/null", O_WRONLY); + if (fd < 0) { + SYSERR("Cannot open /dev/null"); + return -errno; + } + } else { + fd = open("/dev/full", O_RDONLY); + if (fd < 0) { + SYSERR("Cannot open /dev/full"); + return -errno; + } + } + null = calloc(1, sizeof(snd_pcm_null_t)); + if (!null) { + close(fd); + return -ENOMEM; + } + null->poll_fd = fd; + null->state = SND_PCM_STATE_OPEN; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_NULL, name, stream, mode); + if (err < 0) { + close(fd); + free(null); + return err; + } + pcm->ops = &snd_pcm_null_ops; + pcm->fast_ops = &snd_pcm_null_fast_ops; + pcm->private_data = null; + pcm->poll_fd = fd; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; + snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_null Plugin: Null + +This plugin discards contents of a PCM stream or creates a stream with zero +samples. + +Note: This implementation uses devices /dev/null (playback, must be writable) +and /dev/full (capture, must be readable). + +\code +pcm.name { + type null # Null PCM +} +\endcode + +\subsection pcm_plugins_null_funcref Function reference + +
    +
  • snd_pcm_null_open() +
  • _snd_pcm_null_open() +
+ +*/ + +/** + * \brief Creates a new Null PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Null PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + SNDERR("Unknown field %s", id); + return -EINVAL; + } + return snd_pcm_null_open(pcmp, name, stream, mode); +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_null_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c new file mode 100644 index 0000000..b085d42 --- /dev/null +++ b/src/pcm/pcm_params.c @@ -0,0 +1,2372 @@ +/* + * PCM - Params functions + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" + +#ifndef NDEBUG +/* + * dump hw_params when $LIBASOUND_DEBUG is set to >= 1 + */ +static void dump_hw_params(snd_pcm_hw_params_t *params, const char *type, + snd_pcm_hw_param_t var, unsigned int val, int err) +{ + const char *verbose = getenv("LIBASOUND_DEBUG"); + snd_output_t *out; + + if (! verbose || ! *verbose || atoi(verbose) < 1) + return; + if (snd_output_stdio_attach(&out, stderr, 0) < 0) + return; + fprintf(stderr, "ALSA ERROR hw_params: %s (%s)\n", + type, snd_pcm_hw_param_name(var)); + fprintf(stderr, " value = "); + switch (var) { + case SND_PCM_HW_PARAM_ACCESS: + fprintf(stderr, "%s", snd_pcm_access_name(val)); + break; + case SND_PCM_HW_PARAM_FORMAT: + fprintf(stderr, "%s", snd_pcm_format_name(val)); + break; + case SND_PCM_HW_PARAM_SUBFORMAT: + fprintf(stderr, "%s", snd_pcm_subformat_name(val)); + break; + default: + fprintf(stderr, "%u", val); + } + fprintf(stderr, " : %s\n", snd_strerror(err)); + snd_pcm_hw_params_dump(params, out); + snd_output_close(out); +} +#else +static inline void dump_hw_params(snd_pcm_hw_params_t *params, const char *type, + snd_pcm_hw_param_t var, unsigned int val, int err) +{ +} +#endif + +static inline int hw_is_mask(snd_pcm_hw_param_t var) +{ +#if SND_PCM_HW_PARAM_FIRST_MASK == 0 + return var <= SND_PCM_HW_PARAM_LAST_MASK; +#else + return var >= SND_PCM_HW_PARAM_FIRST_MASK && + var <= SND_PCM_HW_PARAM_LAST_MASK; +#endif +} + +static inline int hw_is_interval(snd_pcm_hw_param_t var) +{ + return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL && + var <= SND_PCM_HW_PARAM_LAST_INTERVAL; +} + +#define hw_param_mask(params,var) \ + &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK]) + +#define hw_param_interval(params,var) \ + &((params)->intervals[(var) - SND_PCM_HW_PARAM_FIRST_INTERVAL]) + +#define hw_param_mask_c hw_param_mask +#define hw_param_interval_c hw_param_interval + +static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) +{ + if (hw_is_mask(var)) { + snd_mask_any(hw_param_mask(params, var)); + params->cmask |= 1 << var; + params->rmask |= 1 << var; + return; + } + if (hw_is_interval(var)) { + snd_interval_any(hw_param_interval(params, var)); + params->cmask |= 1 << var; + params->rmask |= 1 << var; + return; + } + assert(0); +} + +int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + _snd_pcm_hw_param_any(params, var); + return snd_pcm_hw_refine(pcm, params); +} + +void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) +{ + unsigned int k; + memset(params, 0, sizeof(*params)); + for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) + _snd_pcm_hw_param_any(params, k); + for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) + _snd_pcm_hw_param_any(params, k); + params->rmask = ~0U; + params->cmask = 0; + params->info = ~0U; +} + +/* Return the value for field PAR if it's fixed in configuration space + defined by PARAMS. Return -EINVAL otherwise +*/ +int snd_pcm_hw_param_get(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, + unsigned int *val, int *dir) +{ + if (hw_is_mask(var)) { + const snd_mask_t *mask = hw_param_mask_c(params, var); + if (snd_mask_empty(mask) || !snd_mask_single(mask)) + return -EINVAL; + if (dir) + *dir = 0; + if (val) + *val = snd_mask_value(mask); + return 0; + } else if (hw_is_interval(var)) { + const snd_interval_t *i = hw_param_interval_c(params, var); + if (snd_interval_empty(i) || !snd_interval_single(i)) + return -EINVAL; + if (dir) + *dir = i->openmin; + if (val) + *val = snd_interval_value(i); + return 0; + } + assert(0); + return -EINVAL; +} + +/* Return the minimum value for field PAR. */ +int snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, + unsigned int *val, int *dir) +{ + if (hw_is_mask(var)) { + const snd_mask_t *m = hw_param_mask_c(params, var); + assert(!snd_mask_empty(m)); + if (dir) + *dir = 0; + if (val) + *val = snd_mask_min(m); + return 0; + } else if (hw_is_interval(var)) { + const snd_interval_t *i = hw_param_interval_c(params, var); + assert(!snd_interval_empty(i)); + if (dir) + *dir = i->openmin; + if (val) + *val = snd_interval_min(i); + return 0; + } + assert(0); + return 0; +} + +/* Return the maximum value for field PAR. */ +int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, + unsigned int *val, int *dir) +{ + if (hw_is_mask(var)) { + const snd_mask_t *m = hw_param_mask_c(params, var); + assert(!snd_mask_empty(m)); + if (dir) + *dir = 0; + if (val) + *val = snd_mask_max(m); + return 0; + } else if (hw_is_interval(var)) { + const snd_interval_t *i = hw_param_interval_c(params, var); + assert(!snd_interval_empty(i)); + if (dir) + *dir = - (int) i->openmax; + if (val) + *val = snd_interval_max(i); + return 0; + } + assert(0); + return 0; +} + +/* Return the mask for field PAR. + This function can be called only for SND_PCM_HW_PARAM_ACCESS, + SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */ +const snd_mask_t *snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + assert(hw_is_mask(var)); + return hw_param_mask_c(params, var); +} + +/* Return the interval for field PAR. + This function cannot be called for SND_PCM_HW_PARAM_ACCESS, + SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */ +const snd_interval_t *snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + assert(hw_is_interval(var)); + return hw_param_interval_c(params, var); +} + +/* --- Refinement functions --- */ + +int _snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_interval_t *val) +{ + int changed; + assert(hw_is_interval(var)); + changed = snd_interval_refine(hw_param_interval(params, var), val); + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +void _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + if (hw_is_mask(var)) { + snd_mask_none(hw_param_mask(params, var)); + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } else if (hw_is_interval(var)) { + snd_interval_none(hw_param_interval(params, var)); + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } else { + assert(0); + } +} + +static int _snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + int changed; + assert(hw_is_interval(var)); + changed = snd_interval_setinteger(hw_param_interval(params, var)); + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* Inside configuration space defined by PARAMS remove from PAR all + non integer values. Reduce configuration space accordingly. + Return -EINVAL if the configuration space is empty +*/ +int snd_pcm_hw_param_set_integer(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var) +{ + snd_pcm_hw_params_t save; + int err; + switch (mode) { + case SND_CHANGE: + break; + case SND_TRY: + save = *params; + break; + case SND_TEST: + save = *params; + params = &save; + break; + default: + assert(0); + return -EINVAL; + } + err = _snd_pcm_hw_param_set_integer(params, var); + if (err < 0) + goto _fail; + if (params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + goto _fail; + } + return 0; + _fail: + if (mode == SND_TRY) + *params = save; + return err; +} + +static int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + int changed; + if (hw_is_mask(var)) + changed = snd_mask_refine_first(hw_param_mask(params, var)); + else if (hw_is_interval(var)) + changed = snd_interval_refine_first(hw_param_interval(params, var)); + else { + assert(0); + return -EINVAL; + } + if (changed > 0) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + + +/* Inside configuration space defined by PARAMS remove from PAR all + values > minimum. Reduce configuration space accordingly. + Return the minimum. +*/ +int snd_pcm_hw_param_set_first(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int *rval, int *dir) +{ + int err; + + err = _snd_pcm_hw_param_set_first(params, var); + if (err < 0) + return err; + if (params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + } + return snd_pcm_hw_param_get(params, var, rval, dir); +} + +static int _snd_pcm_hw_param_set_last(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + int changed; + if (hw_is_mask(var)) + changed = snd_mask_refine_last(hw_param_mask(params, var)); + else if (hw_is_interval(var)) + changed = snd_interval_refine_last(hw_param_interval(params, var)); + else { + assert(0); + return -EINVAL; + } + if (changed > 0) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + + +/* Inside configuration space defined by PARAMS remove from PAR all + values < maximum. Reduce configuration space accordingly. + Return the maximum. +*/ +int snd_pcm_hw_param_set_last(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int *rval, int *dir) +{ + int err; + + err = _snd_pcm_hw_param_set_last(params, var); + if (err < 0) + return err; + if (params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + } + return snd_pcm_hw_param_get(params, var, rval, dir); +} + +int _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, int dir) +{ + int changed; + int openmin = 0; + if (dir) { + if (dir > 0) { + openmin = 1; + } else if (dir < 0) { + if (val > 0) { + openmin = 1; + val--; + } + } + } + if (hw_is_mask(var)) + changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!openmin); + else if (hw_is_interval(var)) + changed = snd_interval_refine_min(hw_param_interval(params, var), val, openmin); + else { + assert(0); + return -EINVAL; + } + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* Inside configuration space defined by PARAMS remove from PAR all + values < VAL. Reduce configuration space accordingly. + Return new minimum or -EINVAL if the configuration space is empty +*/ +int snd_pcm_hw_param_set_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, unsigned int *val, int *dir) +{ + snd_pcm_hw_params_t save; + int err; + switch (mode) { + case SND_CHANGE: + break; + case SND_TRY: + save = *params; + break; + case SND_TEST: + save = *params; + params = &save; + break; + default: + assert(0); + return -EINVAL; + } + err = _snd_pcm_hw_param_set_min(params, var, *val, dir ? *dir : 0); + if (err < 0) + goto _fail; + if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + goto _fail; + if (snd_pcm_hw_param_empty(params, var)) { + err = -ENOENT; + goto _fail; + } + } + return snd_pcm_hw_param_get_min(params, var, val, dir); + _fail: + if (mode == SND_TRY) + *params = save; + if (err < 0 && mode == SND_TRY) + dump_hw_params(params, "set_min", var, *val, err); + return err; +} + +int _snd_pcm_hw_param_set_max(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, int dir) +{ + int changed; + int openmax = 0; + if (dir) { + if (dir < 0) { + openmax = 1; + } else if (dir > 0) { + openmax = 1; + val++; + } + } + if (hw_is_mask(var)) { + if (val == 0 && openmax) { + snd_mask_none(hw_param_mask(params, var)); + changed = -EINVAL; + } else + changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!openmax); + } else if (hw_is_interval(var)) + changed = snd_interval_refine_max(hw_param_interval(params, var), val, openmax); + else { + assert(0); + return -EINVAL; + } + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* Inside configuration space defined by PARAMS remove from PAR all + values >= VAL + 1. Reduce configuration space accordingly. + Return new maximum or -EINVAL if the configuration space is empty +*/ +int snd_pcm_hw_param_set_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, unsigned int *val, int *dir) +{ + snd_pcm_hw_params_t save; + int err; + switch (mode) { + case SND_CHANGE: + break; + case SND_TRY: + save = *params; + break; + case SND_TEST: + save = *params; + params = &save; + break; + default: + assert(0); + return -EINVAL; + } + err = _snd_pcm_hw_param_set_max(params, var, *val, dir ? *dir : 0); + if (err < 0) + goto _fail; + if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + goto _fail; + if (snd_pcm_hw_param_empty(params, var)) { + err = -ENOENT; + goto _fail; + } + } + return snd_pcm_hw_param_get_max(params, var, val, dir); + _fail: + if (mode == SND_TRY) + *params = save; + if (err < 0 && mode == SND_TRY) + dump_hw_params(params, "set_max", var, *val, err); + return err; +} + +int _snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int min, int mindir, + unsigned int max, int maxdir) +{ + int changed, c1, c2; + int openmin = 0, openmax = 0; + if (mindir) { + if (mindir > 0) { + openmin = 1; + } else if (mindir < 0) { + if (min > 0) { + openmin = 1; + min--; + } + } + } + if (maxdir) { + if (maxdir < 0) { + openmax = 1; + } else if (maxdir > 0) { + openmax = 1; + max++; + } + } + if (hw_is_mask(var)) { + snd_mask_t *mask = hw_param_mask(params, var); + if (max == 0 && openmax) { + snd_mask_none(mask); + changed = -EINVAL; + } else { + c1 = snd_mask_refine_min(mask, min + !!openmin); + if (c1 < 0) + changed = c1; + else { + c2 = snd_mask_refine_max(mask, max - !!openmax); + if (c2 < 0) + changed = c2; + else + changed = (c1 || c2); + } + } + } + else if (hw_is_interval(var)) { + snd_interval_t *i = hw_param_interval(params, var); + c1 = snd_interval_refine_min(i, min, openmin); + if (c1 < 0) + changed = c1; + else { + c2 = snd_interval_refine_max(i, max, openmax); + if (c2 < 0) + changed = c2; + else + changed = (c1 || c2); + } + } else { + assert(0); + return -EINVAL; + } + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* Inside configuration space defined by PARAMS remove from PAR all + values < MIN and all values > MAX. Reduce configuration space accordingly. + Return 0 or -EINVAL if the configuration space is empty +*/ +int snd_pcm_hw_param_set_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, + unsigned int *min, int *mindir, + unsigned int *max, int *maxdir) +{ + snd_pcm_hw_params_t save; + int err; + switch (mode) { + case SND_CHANGE: + break; + case SND_TRY: + save = *params; + break; + case SND_TEST: + save = *params; + params = &save; + break; + default: + assert(0); + return -EINVAL; + } + err = _snd_pcm_hw_param_set_minmax(params, var, + *min, mindir ? *mindir : 0, + *max, maxdir ? *maxdir : 0); + if (err < 0) + goto _fail; + if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + goto _fail; + } + err = snd_pcm_hw_param_get_min(params, var, min, mindir); + if (err < 0) + return err; + return snd_pcm_hw_param_get_max(params, var, max, maxdir); + _fail: + if (mode == SND_TRY) + *params = save; + if (err < 0) + dump_hw_params(params, "set_minmax", var, *min, err); + return err; +} + +int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, int dir) +{ + int changed; + if (hw_is_mask(var)) { + snd_mask_t *m = hw_param_mask(params, var); + if (val == 0 && dir < 0) { + changed = -EINVAL; + snd_mask_none(m); + } else { + if (dir > 0) + val++; + else if (dir < 0) + val--; + changed = snd_mask_refine_set(hw_param_mask(params, var), val); + } + } else if (hw_is_interval(var)) { + snd_interval_t *i = hw_param_interval(params, var); + if (val == 0 && dir < 0) { + changed = -EINVAL; + snd_interval_none(i); + } else if (dir == 0) + changed = snd_interval_refine_set(i, val); + else { + snd_interval_t t; + t.openmin = 1; + t.openmax = 1; + t.empty = 0; + t.integer = 0; + if (dir < 0) { + t.min = val - 1; + t.max = val; + } else { + t.min = val; + t.max = val+1; + } + changed = snd_interval_refine(i, &t); + } + } else { + assert(0); + return -EINVAL; + } + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* Inside configuration space defined by PARAMS remove from PAR all + values != VAL. Reduce configuration space accordingly. + Return -EINVAL if the configuration space is empty +*/ +int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, unsigned int val, int dir) +{ + snd_pcm_hw_params_t save; + int err; + switch (mode) { + case SND_CHANGE: + break; + case SND_TRY: + save = *params; + break; + case SND_TEST: + save = *params; + params = &save; + break; + default: + assert(0); + return -EINVAL; + } + err = _snd_pcm_hw_param_set(params, var, val, dir); + if (err < 0) + goto _fail; + if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + goto _fail; + } + return 0; + _fail: + if (mode == SND_TRY) + *params = save; + if (err < 0 && mode == SND_TRY) + dump_hw_params(params, "set", var, val, err); + return err; +} + +int _snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, const snd_mask_t *val) +{ + int changed; + assert(hw_is_mask(var)); + changed = snd_mask_refine(hw_param_mask(params, var), val); + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* Inside configuration space defined by PARAMS remove from PAR all values + not contained in MASK. Reduce configuration space accordingly. + This function can be called only for SND_PCM_HW_PARAM_ACCESS, + SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. + Return 0 on success or -EINVAL + if the configuration space is empty +*/ +int snd_pcm_hw_param_set_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_set_mode_t mode, + snd_pcm_hw_param_t var, const snd_mask_t *val) +{ + snd_pcm_hw_params_t save; + int err; + switch (mode) { + case SND_CHANGE: + break; + case SND_TRY: + save = *params; + break; + case SND_TEST: + save = *params; + params = &save; + break; + default: + assert(0); + return -EINVAL; + } + err = _snd_pcm_hw_param_set_mask(params, var, val); + if (err < 0) + goto _fail; + if (mode != SND_TEST && params->rmask) { + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + goto _fail; + } + return 0; + _fail: + if (mode == SND_TRY) + *params = save; + return err; +} + +/* Inside configuration space defined by PARAMS set PAR to the available value + nearest to VAL. Reduce configuration space accordingly. + This function cannot be called for SND_PCM_HW_PARAM_ACCESS, + SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. + Return the value found. + */ +int snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int *val, int *dir) +{ + snd_pcm_hw_params_t save; + int err; + unsigned int best = *val, saved_min; + int last = 0; + unsigned int min, max; + int mindir, maxdir; + int valdir = dir ? *dir : 0; + snd_interval_t *i; + /* FIXME */ + if (best > INT_MAX) + best = INT_MAX; + min = max = best; + mindir = maxdir = valdir; + if (maxdir > 0) + maxdir = 0; + else if (maxdir == 0) + maxdir = -1; + else { + maxdir = 1; + max--; + } + save = *params; + saved_min = min; + err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir); + + i = hw_param_interval(params, var); + if (!snd_interval_empty(i) && snd_interval_single(i)) { + err = snd_pcm_hw_param_get_min(params, var, val, dir); + if (err < 0) + dump_hw_params(params, "set_near", var, *val, err); + return err; + } + + if (err >= 0) { + snd_pcm_hw_params_t params1; + if (min == saved_min && mindir == valdir) + goto _end; + params1 = save; + err = snd_pcm_hw_param_set_max(pcm, ¶ms1, SND_CHANGE, var, &max, &maxdir); + if (err < 0) + goto _end; + if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { + *params = params1; + last = 1; + } + } else { + *params = save; + err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir); + if (err < 0) { + dump_hw_params(params, "set_near", var, *val, err); + return err; + } + last = 1; + } + _end: + if (last) + err = snd_pcm_hw_param_set_last(pcm, params, var, val, dir); + else + err = snd_pcm_hw_param_set_first(pcm, params, var, val, dir); + if (err < 0) + dump_hw_params(params, "set_near", var, *val, err); + return err; +} + +#if 0 +/* Inside configuration space defined by PARAMS set PAR to the available value + nearest to BEST after VAL (on equal difference values less than BEST are + returned first). + Reduce configuration space accordingly. + This function cannot be called for SND_PCM_HW_PARAM_ACCESS, + SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. + Return the value found. + */ +int snd_pcm_hw_param_set_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int best, int bestdir, + unsigned int val, int *dir) +{ + snd_pcm_hw_params_t save; + int v, err; + int last = 0; + int min, max; + int mindir, maxdir; + int diff, diffdir; + int valdir = dir ? *dir : 0; + /* FIXME */ + if (best > INT_MAX) + best = INT_MAX; + boundary_sub(val, valdir, best, bestdir, &diff, &diffdir); + if (diff < 0 || (diff == 0 && diffdir < 0)) { + min = best - diff; + mindir = bestdir - diffdir; + max = val; + maxdir = bestdir - 1; + } else { + min = val; + mindir = bestdir + 1; + max = best + diff; + maxdir = bestdir + diffdir + 1; + } + min += mindir / 2; + mindir %= 2; + max += maxdir / 2; + maxdir %= 2; + save = *params; + if (min >= 0 && + (err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir)) >= 0) { + snd_pcm_hw_params_t params1; + if (max < 0) + goto _end; + params1 = save; + err = snd_pcm_hw_param_set_max(pcm, ¶ms1, SND_CHANGE, var, &max, &maxdir); + if (err < 0) + goto _end; + if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) { + *params = params1; + last = 1; + } + } else { + if (max < 0) + return -EINVAL; + *params = save; + err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir); + if (err < 0) + return max; + last = 1; + } + _end: + if (last) + v = snd_pcm_hw_param_set_last(pcm, params, var, dir); + else + v = snd_pcm_hw_param_set_first(pcm, params, var, dir); + assert(v >= 0); + return v; +} +#endif + +static int snd_pcm_hw_param_set_near_minmax(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + unsigned int min, int *mindir, + unsigned int max, int *maxdir) +{ + snd_pcm_hw_params_t tmp; + int err; + if (!boundary_lt(min, *mindir, max, *maxdir)) + return snd_pcm_hw_param_set_near(pcm, params, var, &min, mindir); + tmp = *params; + err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &min, mindir); + if (err < 0) + return err; + if (boundary_lt(min, *mindir, max, *maxdir)) { + tmp = *params; + err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &max, maxdir); + } else { + max = min; + *maxdir = *mindir; + } + err = snd_pcm_hw_param_set_minmax(pcm, params, SND_CHANGE, var, &min, mindir, + &max, maxdir); + if (err < 0) + return err; + return 0; +} + +int snd_pcm_hw_param_refine_near(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src) +{ + unsigned int min, max; + int mindir, maxdir, err; + + if ((err = snd_pcm_hw_param_get_min(src, var, &min, &mindir)) < 0) + return err; + if ((err = snd_pcm_hw_param_get_max(src, var, &max, &maxdir)) < 0) + return err; + if ((err = snd_pcm_hw_param_set_near_minmax(pcm, params, var, + min, &mindir, max, &maxdir)) < 0) + return err; + return 0; +} + +int snd_pcm_hw_param_refine_multiple(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src) +{ + const snd_interval_t *it = hw_param_interval_c(src, var); + const snd_interval_t *st = hw_param_interval_c(params, var); + if (snd_interval_single(it)) { + unsigned int best = snd_interval_min(it), cur, prev; + cur = best; + for (;;) { + if (st->max < cur || (st->max == cur && st->openmax)) + break; + if (it->min <= cur && ! (it->min == cur && st->openmin)) { + if (! snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0)) + return 0; /* ok */ + } + prev = cur; + cur += best; + if (cur <= prev) + break; + } + } + return snd_pcm_hw_param_refine_near(pcm, params, var, src); +} + +/* ---- end of refinement functions ---- */ + +int snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + if (hw_is_mask(var)) + return snd_mask_empty(hw_param_mask_c(params, var)); + if (hw_is_interval(var)) + return snd_interval_empty(hw_param_interval_c(params, var)); + assert(0); + return -EINVAL; +} + +int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *params1) +{ + if (hw_is_mask(var)) + return snd_mask_always_eq(hw_param_mask_c(params, var), + hw_param_mask_c(params1, var)); + if (hw_is_interval(var)) + return snd_interval_always_eq(hw_param_interval_c(params, var), + hw_param_interval_c(params1, var)); + assert(0); + return -EINVAL; +} + +int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *params1) +{ + if (hw_is_mask(var)) + return snd_mask_never_eq(hw_param_mask_c(params, var), + hw_param_mask_c(params1, var)); + if (hw_is_interval(var)) + return snd_interval_never_eq(hw_param_interval_c(params, var), + hw_param_interval_c(params1, var)); + assert(0); + return -EINVAL; +} + +#if 0 +#define CHOOSE_DEBUG +#endif + +/* Choose one configuration from configuration space defined by PARAMS + The configuration chosen is that obtained fixing in this order: + first access + first format + first subformat + min channels + min rate + min period time + max buffer size + min tick time +*/ +static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int err; +#ifdef CHOOSE_DEBUG + snd_output_t *log; + snd_output_stdio_attach(&log, stderr, 0); + snd_output_printf(log, "CHOOSE called:\n"); + snd_pcm_hw_params_dump(params, log); +#endif + + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, NULL, 0); + if (err < 0) + return err; + if (pcm->minperiodtime > 0) { + unsigned int min, max; + int dir = 1; + err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir); + if (err >= 0) + err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_TIME, &max, &dir); + if (err >= 0 && (long)min < pcm->minperiodtime && + (long)max > pcm->minperiodtime) { + min = pcm->minperiodtime; dir = 1; + snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir); + } + } + if (pcm->compat) { + /* old mode */ + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0); + if (err < 0) + return err; + } else { + /* determine buffer size first */ + err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0); + if (err < 0) + return err; + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0); + if (err < 0) + return err; + } + err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0); + if (err < 0) + return err; +#ifdef CHOOSE_DEBUG + snd_output_printf(log, "choose done\n"); + snd_pcm_hw_params_dump(params, log); + snd_output_close(log); +#endif + return 0; +} + +#if 0 +static unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + if (hw_is_mask(var)) { + const snd_mask_t *mask = hw_param_mask_c(params, var); + return snd_mask_count(mask); + } + if (hw_is_interval(var)) { + const snd_interval_t *i = hw_param_interval_c(params, var); + return snd_interval_max(i) - snd_interval_min(i) + 1; + } + assert(0); + return 0; +} +#endif + +int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src) +{ + int changed = 0; + if (hw_is_mask(var)) { + snd_mask_t *d = hw_param_mask(params, var); + const snd_mask_t *s = hw_param_mask_c(src, var); + changed = snd_mask_refine(d, s); + } else if (hw_is_interval(var)) { + snd_interval_t *d = hw_param_interval(params, var); + const snd_interval_t *s = hw_param_interval_c(src, var); + changed = snd_interval_refine(d, s); + } else + return 0; /* NOP / reserved */ + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +#if 0 +static void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var, + const snd_pcm_hw_params_t *src) +{ + if (hw_is_mask(var)) { + snd_mask_t *d = hw_param_mask(params, var); + const snd_mask_t *s = hw_param_mask_c(src, var); + snd_mask_copy(d, s); + params->cmask |= 1 << var; + params->rmask |= 1 << var; + return; + } + if (hw_is_interval(var)) { + snd_interval_t *d = hw_param_interval(params, var); + const snd_interval_t *s = hw_param_interval_c(src, var); + snd_interval_copy(d, s); + params->cmask |= 1 << var; + params->rmask |= 1 << var; + return; + } + assert(0); +} +#endif + +void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, snd_output_t *out) +{ + if (hw_is_mask(var)) { + const snd_mask_t *mask = hw_param_mask_c(params, var); + if (snd_mask_empty(mask)) + snd_output_puts(out, " NONE"); + else if (snd_mask_full(mask)) + snd_output_puts(out, " ALL"); + else { + unsigned int k; + for (k = 0; k <= SND_MASK_MAX; ++k) { + if (snd_mask_test(mask, k)) { + const char *s; + switch (var) { + case SND_PCM_HW_PARAM_ACCESS: + s = snd_pcm_access_name(k); + break; + case SND_PCM_HW_PARAM_FORMAT: + s = snd_pcm_format_name(k); + break; + case SND_PCM_HW_PARAM_SUBFORMAT: + s = snd_pcm_subformat_name(k); + break; + default: + assert(0); + s = NULL; + } + if (s) { + snd_output_putc(out, ' '); + snd_output_puts(out, s); + } + } + } + } + return; + } + if (hw_is_interval(var)) { + snd_interval_print(hw_param_interval_c(params, var), out); + return; + } + assert(0); +} + +#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v + +static const char *const snd_pcm_hw_param_names[] = { + HW_PARAM(ACCESS), + HW_PARAM(FORMAT), + HW_PARAM(SUBFORMAT), + HW_PARAM(SAMPLE_BITS), + HW_PARAM(FRAME_BITS), + HW_PARAM(CHANNELS), + HW_PARAM(RATE), + HW_PARAM(PERIOD_TIME), + HW_PARAM(PERIOD_SIZE), + HW_PARAM(PERIOD_BYTES), + HW_PARAM(PERIODS), + HW_PARAM(BUFFER_TIME), + HW_PARAM(BUFFER_SIZE), + HW_PARAM(BUFFER_BYTES), + HW_PARAM(TICK_TIME), +}; + +const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param) +{ + assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL); + return snd_pcm_hw_param_names[param]; +} + +#if 0 +/* Strategies */ + +struct _snd_pcm_hw_strategy { + unsigned int badness_min, badness_max; + int (*choose_param)(const snd_pcm_hw_params_t *params, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_t *strategy); + int (*next_value)(snd_pcm_hw_params_t *params, + unsigned int param, + int value, int *dir, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_t *strategy); + int (*min_badness)(const snd_pcm_hw_params_t *params, + unsigned int max_badness, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_t *strategy); + void *private_data; + void (*free)(snd_pcm_hw_strategy_t *strategy); +}; + +/* Independent badness */ +typedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t; + +struct _snd_pcm_hw_strategy_simple { + int valid; + unsigned int order; + int (*next_value)(snd_pcm_hw_params_t *params, + unsigned int param, + int value, int *dir, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_simple_t *par); + unsigned int (*min_badness)(const snd_pcm_hw_params_t *params, + unsigned int param, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_simple_t *par); + void *private_data; + void (*free)(snd_pcm_hw_strategy_simple_t *strategy); +}; + +typedef struct _snd_pcm_hw_strategy_simple_near { + int best; + unsigned int mul; +} snd_pcm_hw_strategy_simple_near_t; + +typedef struct _snd_pcm_hw_strategy_simple_choices { + unsigned int count; + /* choices need to be sorted on ascending badness */ + snd_pcm_hw_strategy_simple_choices_list_t *choices; +} snd_pcm_hw_strategy_simple_choices_t; + +int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + const snd_pcm_hw_strategy_t *strategy, + unsigned int badness_min, + unsigned int badness_max) +{ + snd_pcm_hw_params_t best_params; + int var; + int value, dir; + unsigned int best_badness; + int badness = strategy->min_badness(params, badness_max, pcm, strategy); + snd_pcm_hw_params_t params1; +#if 0 + printf("\nBadness: %d\n", badness); + snd_pcm_hw_params_dump(params, stdout); +#endif + if (badness < 0) + return badness; + if ((unsigned int)badness > badness_min) + badness_min = badness_min; + var = strategy->choose_param(params, pcm, strategy); + if (var < 0) + return badness; + best_badness = UINT_MAX; + value = -1; + while (1) { + params1 = *params; + value = strategy->next_value(¶ms1, var, value, &dir, pcm, strategy); + if (value < 0) + break; + badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, strategy, badness_min, badness_max); + if (badness >= 0) { + if ((unsigned int) badness <= badness_min) { + *params = params1; + return badness; + } + best_badness = badness; + best_params = params1; + badness_max = badness - 1; + } + } + if (best_badness == UINT_MAX) { + return -EINVAL; + } + *params = best_params; + return best_badness; +} + +void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy) +{ + snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; + int k; + for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) { + if (pars[k].valid && pars[k].free) + pars[k].free(&pars[k]); + } + free(pars); +} + +int snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params, + snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_hw_strategy_t *strategy) +{ + snd_pcm_hw_param_t var; + int best_var = -1; + const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; + unsigned int min_choices = UINT_MAX; + unsigned int min_order = UINT_MAX; + for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) { + const snd_pcm_hw_strategy_simple_t *p = &pars[var]; + unsigned int choices; + if (!p->valid) + continue; + choices = snd_pcm_hw_param_count(params, var); + if (choices == 1) + continue; + assert(choices != 0); + if (p->order < min_order || + (p->order == min_order && + choices < min_choices)) { + min_order = p->order; + min_choices = choices; + best_var = var; + } + } + return best_var; +} + +int snd_pcm_hw_strategy_simple_next_value(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + int value, int *dir, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_t *strategy) +{ + const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; + assert(pars[var].valid); + return pars[var].next_value(params, var, value, dir, pcm, &pars[var]); +} + + +int snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params, + unsigned int max_badness, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_t *strategy) +{ + snd_pcm_hw_param_t var; + unsigned int badness = 0; + const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data; + for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) { + unsigned int b; + if (!pars[var].valid) + continue; + b = pars[var].min_badness(params, var, pcm, &pars[var]); + if (b > max_badness || max_badness - b < badness) + return -E2BIG; + badness += b; + } + return badness; +} + + +void snd_pcm_hw_strategy_simple_near_free(snd_pcm_hw_strategy_simple_t *par) +{ + snd_pcm_hw_strategy_simple_near_t *p = par->private_data; + free(p); +} + +unsigned int snd_pcm_hw_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_simple_t *par) +{ + const snd_pcm_hw_strategy_simple_near_t *p = par->private_data; + snd_pcm_hw_params_t params1 = *params; + int value = snd_pcm_hw_param_set_near(pcm, ¶ms1, var, p->best, 0); + int diff; + assert(value >= 0); + diff = p->best - value; + if (diff < 0) + diff = -diff; + return diff * p->mul; +} + +int snd_pcm_hw_strategy_simple_near_next_value(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + int value, int *dir, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_simple_t *par) +{ + const snd_pcm_hw_strategy_simple_near_t *p = par->private_data; + if (value < 0) { + *dir = 0; + return snd_pcm_hw_param_set_near(pcm, params, var, p->best, dir); + } else + return snd_pcm_hw_param_set_next(pcm, params, var, p->best, 0, value, dir); +} + +void snd_pcm_hw_strategy_simple_choices_free(snd_pcm_hw_strategy_simple_t *par) +{ + snd_pcm_hw_strategy_simple_choices_t *p = par->private_data; +// free(p->choices); + free(p); +} + +unsigned int snd_pcm_hw_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_simple_t *par) +{ + const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data; + unsigned int k; + for (k = 0; k < p->count; ++k) { + if (snd_pcm_hw_param_set(pcm, (snd_pcm_hw_params_t *) params, SND_TEST, var, p->choices[k].value, 0)) + return p->choices[k].badness; + } + assert(0); + return UINT_MAX; +} + +int snd_pcm_hw_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + int value, int *dir, + snd_pcm_t *pcm, + const snd_pcm_hw_strategy_simple_t *par) +{ + const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data; + unsigned int k = 0; + if (value >= 0) { + for (; k < p->count; ++k) { + if (p->choices[k].value == (unsigned int) value) { + k++; + break; + } + } + } + for (; k < p->count; ++k) { + unsigned int v = p->choices[k].value; + int err = snd_pcm_hw_param_set(pcm, params, SND_TRY, var, v, 0); + if (err < 0) + continue; + *dir = 0; + return v; + } + return -1; +} + +void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy) +{ + if (strategy->free) + strategy->free(strategy); + free(strategy); +} + +int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp, + unsigned int badness_min, + unsigned int badness_max) +{ + snd_pcm_hw_strategy_simple_t *data; + snd_pcm_hw_strategy_t *s; + assert(strategyp); + data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data)); + if (!data) + return -ENOMEM; + s = calloc(1, sizeof(*s)); + if (!s) { + free(data); + return -ENOMEM; + } + s->choose_param = snd_pcm_hw_strategy_simple_choose_param; + s->next_value = snd_pcm_hw_strategy_simple_next_value; + s->min_badness = snd_pcm_hw_strategy_simple_min_badness; + s->badness_min = badness_min; + s->badness_max = badness_max; + s->private_data = data; + s->free = snd_pcm_hw_strategy_simple_free; + *strategyp = s; + return 0; +} + +int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy, + int order, + snd_pcm_hw_param_t var, + unsigned int best, + unsigned int mul) +{ + snd_pcm_hw_strategy_simple_t *s = strategy->private_data; + snd_pcm_hw_strategy_simple_near_t *data; + assert(strategy); + assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL); + assert(!s->valid); + data = calloc(1, sizeof(*data)); + if (!data) + return -ENOMEM; + data->best = best; + data->mul = mul; + s += var; + s->order = order; + s->valid = 1; + s->next_value = snd_pcm_hw_strategy_simple_near_next_value; + s->min_badness = snd_pcm_hw_strategy_simple_near_min_badness; + s->private_data = data; + s->free = snd_pcm_hw_strategy_simple_near_free; + return 0; +} + +int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, + int order, + snd_pcm_hw_param_t var, + unsigned int count, + snd_pcm_hw_strategy_simple_choices_list_t *choices) +{ + snd_pcm_hw_strategy_simple_t *s = strategy->private_data; + snd_pcm_hw_strategy_simple_choices_t *data; + assert(strategy); + assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL); + assert(!s->valid); + data = calloc(1, sizeof(*data)); + if (!data) + return -ENOMEM; + data->count = count; + data->choices = choices; + s += var; + s->valid = 1; + s->order = order; + s->next_value = snd_pcm_hw_strategy_simple_choices_next_value; + s->min_badness = snd_pcm_hw_strategy_simple_choices_min_badness; + s->private_data = data; + s->free = snd_pcm_hw_strategy_simple_choices_free; + return 0; +} + +int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm, + snd_pcm_hw_params_t *fail, + snd_pcm_hw_params_t *success, + unsigned int depth, + snd_output_t *out) +{ + snd_pcm_hw_param_t var; + snd_pcm_hw_params_t i; + if (depth < 1) + return -ENOENT; + for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) { + int err; + i = *success; + _snd_pcm_hw_param_copy(&i, var, fail); + err = snd_pcm_hw_refine(pcm, &i); + if (err == 0 && + snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0) + continue; + snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(var)); + snd_pcm_hw_param_dump(fail, var, out); + snd_output_putc(out, '\n'); + return 0; + } + return -ENOENT; +} + +int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm, + snd_pcm_hw_params_t *fail, + snd_pcm_hw_params_t *success, + unsigned int depth, + snd_output_t *out) +{ + snd_pcm_hw_params_t i, any; + int err; + snd_pcm_hw_param_t var; + int done = 0; + assert(pcm && fail); + for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) { + if (!snd_pcm_hw_param_empty(fail, var)) + continue; + snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var)); + done = 1; + } + if (done) + return 0; + i = *fail; + err = snd_pcm_hw_refine(pcm, &i); + if (err == 0) { + snd_output_printf(out, "Configuration is virtually correct\n"); + return 0; + } + if (!success) { + snd_pcm_hw_params_any(pcm, &any); + success = &any; + } + return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out); +} + +#endif + +typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t; + +typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule); + +struct _snd_pcm_hw_rule { + int var; + snd_pcm_hw_rule_func_t func; + int deps[4]; + void *private_data; +}; + +static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule) +{ + snd_interval_t t; + snd_interval_mul(hw_param_interval_c(params, rule->deps[0]), + hw_param_interval_c(params, rule->deps[1]), &t); + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + +static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule) +{ + snd_interval_t t; + snd_interval_div(hw_param_interval_c(params, rule->deps[0]), + hw_param_interval_c(params, rule->deps[1]), &t); + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + +static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule) +{ + snd_interval_t t; + snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]), + hw_param_interval_c(params, rule->deps[1]), + (unsigned long) rule->private_data, &t); + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + +static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule) +{ + snd_interval_t t; + snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]), + (unsigned long) rule->private_data, + hw_param_interval_c(params, rule->deps[1]), &t); + return snd_interval_refine(hw_param_interval(params, rule->var), &t); +} + +static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule) +{ + int changed = 0; + snd_pcm_format_t k; + snd_mask_t *mask = hw_param_mask(params, rule->var); + snd_interval_t *i = hw_param_interval(params, rule->deps[0]); + for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) { + int bits; + if (!snd_pcm_format_mask_test(mask, k)) + continue; + bits = snd_pcm_format_physical_width(k); + if (bits < 0) + continue; + if (!snd_interval_test(i, (unsigned int) bits)) { + snd_pcm_format_mask_reset(mask, k); + if (snd_mask_empty(mask)) + return -EINVAL; + changed = 1; + } + } + return changed; +} + + +static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params, + const snd_pcm_hw_rule_t *rule) +{ + unsigned int min, max; + snd_pcm_format_t k; + snd_interval_t *i = hw_param_interval(params, rule->var); + snd_mask_t *mask = hw_param_mask(params, rule->deps[0]); + int c, changed = 0; + min = UINT_MAX; + max = 0; + for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) { + int bits; + if (!snd_pcm_format_mask_test(mask, k)) + continue; + bits = snd_pcm_format_physical_width(k); + if (bits < 0) + continue; + if (min > (unsigned)bits) + min = bits; + if (max < (unsigned)bits) + max = bits; + } + c = snd_interval_refine_min(i, min, 0); + if (c < 0) + return c; + if (c) + changed = 1; + c = snd_interval_refine_max(i, max, 0); + if (c < 0) + return c; + if (c) + changed = 1; + return changed; +} + +static const snd_pcm_hw_rule_t refine_rules[] = { + { + .var = SND_PCM_HW_PARAM_FORMAT, + .func = snd_pcm_hw_rule_format, + .deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_SAMPLE_BITS, + .func = snd_pcm_hw_rule_sample_bits, + .deps = { SND_PCM_HW_PARAM_FORMAT, + SND_PCM_HW_PARAM_SAMPLE_BITS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_SAMPLE_BITS, + .func = snd_pcm_hw_rule_div, + .deps = { SND_PCM_HW_PARAM_FRAME_BITS, + SND_PCM_HW_PARAM_CHANNELS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_FRAME_BITS, + .func = snd_pcm_hw_rule_mul, + .deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, + SND_PCM_HW_PARAM_CHANNELS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_FRAME_BITS, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_PERIOD_BYTES, + SND_PCM_HW_PARAM_PERIOD_SIZE, -1 }, + .private_data = (void*) 8, + }, + { + .var = SND_PCM_HW_PARAM_FRAME_BITS, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_BUFFER_BYTES, + SND_PCM_HW_PARAM_BUFFER_SIZE, -1 }, + .private_data = (void*) 8, + }, + { + .var = SND_PCM_HW_PARAM_CHANNELS, + .func = snd_pcm_hw_rule_div, + .deps = { SND_PCM_HW_PARAM_FRAME_BITS, + SND_PCM_HW_PARAM_SAMPLE_BITS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_RATE, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_PERIOD_TIME, -1 }, + .private_data = (void*) 1000000, + }, + { + .var = SND_PCM_HW_PARAM_RATE, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_BUFFER_TIME, -1 }, + .private_data = (void*) 1000000, + }, + { + .var = SND_PCM_HW_PARAM_PERIODS, + .func = snd_pcm_hw_rule_div, + .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_PERIOD_SIZE, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_PERIOD_SIZE, + .func = snd_pcm_hw_rule_div, + .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_PERIODS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_PERIOD_SIZE, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_PERIOD_BYTES, + SND_PCM_HW_PARAM_FRAME_BITS, -1 }, + .private_data = (void*) 8, + }, + { + .var = SND_PCM_HW_PARAM_PERIOD_SIZE, + .func = snd_pcm_hw_rule_muldivk, + .deps = { SND_PCM_HW_PARAM_PERIOD_TIME, + SND_PCM_HW_PARAM_RATE, -1 }, + .private_data = (void*) 1000000, + }, + { + .var = SND_PCM_HW_PARAM_BUFFER_SIZE, + .func = snd_pcm_hw_rule_mul, + .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_PERIODS, -1 }, + .private_data = 0, + }, + { + .var = SND_PCM_HW_PARAM_BUFFER_SIZE, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_BUFFER_BYTES, + SND_PCM_HW_PARAM_FRAME_BITS, -1 }, + .private_data = (void*) 8, + }, + { + .var = SND_PCM_HW_PARAM_BUFFER_SIZE, + .func = snd_pcm_hw_rule_muldivk, + .deps = { SND_PCM_HW_PARAM_BUFFER_TIME, + SND_PCM_HW_PARAM_RATE, -1 }, + .private_data = (void*) 1000000, + }, + { + .var = SND_PCM_HW_PARAM_PERIOD_BYTES, + .func = snd_pcm_hw_rule_muldivk, + .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_FRAME_BITS, -1 }, + .private_data = (void*) 8, + }, + { + .var = SND_PCM_HW_PARAM_BUFFER_BYTES, + .func = snd_pcm_hw_rule_muldivk, + .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_FRAME_BITS, -1 }, + .private_data = (void*) 8, + }, + { + .var = SND_PCM_HW_PARAM_PERIOD_TIME, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_PERIOD_SIZE, + SND_PCM_HW_PARAM_RATE, -1 }, + .private_data = (void*) 1000000, + }, + { + .var = SND_PCM_HW_PARAM_BUFFER_TIME, + .func = snd_pcm_hw_rule_mulkdiv, + .deps = { SND_PCM_HW_PARAM_BUFFER_SIZE, + SND_PCM_HW_PARAM_RATE, -1 }, + .private_data = (void*) 1000000, + }, +}; + +#define RULES (sizeof(refine_rules) / sizeof(refine_rules[0])) + +static const snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = { + [SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = { + .bits = { 0x1f }, + }, + [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = { + .bits = { 0x81ffffff, 0xfff}, + }, + [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = { + .bits = { 0x1 }, + }, +}; + +static const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = { + [SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, + }, + [SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, + }, + [SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, + }, + [SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, + [SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 0, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, + [SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 0, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, + [SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 0, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, + [SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 0, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, + [SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, + [SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, + }, + [SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 1, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 1, .empty = 0, + }, + [SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = { + .min = 0, .max = UINT_MAX, + .openmin = 0, .openmax = 0, .integer = 0, .empty = 0, + }, +}; + +#if 0 +#define RULES_DEBUG +#endif + +int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + unsigned int k; + snd_interval_t *i; + unsigned int rstamps[RULES]; + unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1]; + unsigned int stamp = 2; + int changed, again; +#ifdef RULES_DEBUG + snd_output_t *log; + snd_output_stdio_attach(&log, stderr, 0); + snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name); + snd_pcm_hw_params_dump(params, log); +#endif + + for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) { + if (!(params->rmask & (1 << k))) + continue; + changed = snd_mask_refine(hw_param_mask(params, k), + &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]); + if (changed) + params->cmask |= 1 << k; + if (changed < 0) + goto _err; + } + + for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) { + if (!(params->rmask & (1 << k))) + continue; + changed = snd_interval_refine(hw_param_interval(params, k), + &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]); + if (changed) + params->cmask |= 1 << k; + if (changed < 0) + goto _err; + } + + for (k = 0; k < RULES; k++) + rstamps[k] = 0; + for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) + vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; + do { + again = 0; + for (k = 0; k < RULES; k++) { + const snd_pcm_hw_rule_t *r = &refine_rules[k]; + unsigned int d; + int doit = 0; + for (d = 0; r->deps[d] >= 0; d++) { + if (vstamps[r->deps[d]] > rstamps[k]) { + doit = 1; + break; + } + } + if (!doit) + continue; +#ifdef RULES_DEBUG + snd_output_printf(log, "Rule %d (%p): ", k, r->func); + if (r->var >= 0) { + snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var)); + snd_pcm_hw_param_dump(params, r->var, log); + snd_output_puts(log, " -> "); + } +#endif + changed = r->func(params, r); +#ifdef RULES_DEBUG + if (r->var >= 0) + snd_pcm_hw_param_dump(params, r->var, log); + for (d = 0; r->deps[d] >= 0; d++) { + snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d])); + snd_pcm_hw_param_dump(params, r->deps[d], log); + } + snd_output_putc(log, '\n'); +#endif + rstamps[k] = stamp; + if (changed && r->var >= 0) { + params->cmask |= 1 << r->var; + vstamps[r->var] = stamp; + again = 1; + } + if (changed < 0) + goto _err; + stamp++; + } + } while (again); + if (!params->msbits) { + i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS); + if (snd_interval_single(i)) + params->msbits = snd_interval_value(i); + } + + if (!params->rate_den) { + i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE); + if (snd_interval_single(i)) { + params->rate_num = snd_interval_value(i); + params->rate_den = 1; + } + } + params->rmask = 0; + return 0; + _err: +#ifdef RULES_DEBUG + snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed); + snd_pcm_hw_params_dump(params, log); + snd_output_close(log); +#endif + return changed; +} + +int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, + unsigned int vars, + const snd_pcm_hw_params_t *src) +{ + int changed, err = 0; + unsigned int k; + for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) { + if (!(vars & (1 << k))) + continue; + changed = _snd_pcm_hw_param_refine(params, k, src); + if (changed < 0) + err = changed; + } + params->info &= src->info; + params->flags = src->flags; /* propagate all flags to slave */ + return err; +} + +int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*srefine)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)) + +{ +#ifdef RULES_DEBUG + snd_output_t *log; +#endif + snd_pcm_hw_params_t sparams; + int err; + unsigned int cmask, changed; +#ifdef RULES_DEBUG + snd_output_stdio_attach(&log, stderr, 0); +#endif + err = cprepare(pcm, params); + if (err < 0) + return err; + err = sprepare(pcm, &sparams); + if (err < 0) { + SNDERR("Slave PCM not usable"); + return err; + } +#ifdef RULES_DEBUG + snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name); +#endif + do { + cmask = params->cmask; + params->cmask = 0; +#ifdef RULES_DEBUG + snd_output_printf(log, "schange '%s' (client)\n", pcm->name); + snd_pcm_hw_params_dump(params, log); + snd_output_printf(log, "schange '%s' (slave)\n", pcm->name); + snd_pcm_hw_params_dump(&sparams, log); +#endif + err = schange(pcm, params, &sparams); + if (err >= 0) { +#ifdef RULES_DEBUG + snd_output_printf(log, "srefine '%s' (client)\n", pcm->name); + snd_pcm_hw_params_dump(params, log); + snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name); + snd_pcm_hw_params_dump(&sparams, log); +#endif + err = srefine(pcm, &sparams); + if (err < 0) { +#ifdef RULES_DEBUG + snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err); + snd_pcm_hw_params_dump(params, log); + snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err); + snd_pcm_hw_params_dump(&sparams, log); +#endif + cchange(pcm, params, &sparams); + return err; + } + } else { +#ifdef RULES_DEBUG + snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err); + snd_pcm_hw_params_dump(params, log); + snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err); + snd_pcm_hw_params_dump(&sparams, log); +#endif + cchange(pcm, params, &sparams); + return err; + } +#ifdef RULES_DEBUG + snd_output_printf(log, "cchange '%s'\n", pcm->name); +#endif + err = cchange(pcm, params, &sparams); + if (err < 0) + return err; +#ifdef RULES_DEBUG + snd_output_printf(log, "refine_soft '%s'\n", pcm->name); +#endif + err = snd_pcm_hw_refine_soft(pcm, params); + changed = params->cmask; + params->cmask |= cmask; + if (err < 0) + return err; +#ifdef RULES_DEBUG + snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name); +#endif + } while (changed); +#ifdef RULES_DEBUG + snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name); + snd_output_close(log); +#endif + return 0; +} + +int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + int (*cchange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sprepare)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params), + int (*schange)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams), + int (*sparams)(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams)) + +{ + snd_pcm_hw_params_t slave_params; + int err; + err = sprepare(pcm, &slave_params); + assert(err >= 0); + err = schange(pcm, params, &slave_params); + assert(err >= 0); + err = sparams(pcm, &slave_params); + if (err < 0) + cchange(pcm, params, &slave_params); + return err; +} + +static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) +{ + assert(pcm && params); + assert(pcm->setup); + params->tstamp_mode = SND_PCM_TSTAMP_NONE; + params->period_step = 1; + params->sleep_min = 0; + params->avail_min = pcm->period_size; + params->xfer_align = 1; + params->start_threshold = 1; + params->stop_threshold = pcm->buffer_size; + params->silence_threshold = 0; + params->silence_size = 0; + params->boundary = pcm->buffer_size; + while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size) + params->boundary *= 2; + return 0; +} + +#if 0 +#define REFINE_DEBUG +#endif + +int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int res; +#ifdef REFINE_DEBUG + snd_output_t *log; + snd_output_stdio_attach(&log, stderr, 0); +#endif + assert(pcm && params); +#ifdef REFINE_DEBUG + snd_output_printf(log, "REFINE called:\n"); + snd_pcm_hw_params_dump(params, log); +#endif + res = pcm->ops->hw_refine(pcm->op_arg, params); +#ifdef REFINE_DEBUG + snd_output_printf(log, "refine done - result = %i\n", res); + snd_pcm_hw_params_dump(params, log); + snd_output_close(log); +#endif + return res; +} + +/* Install one of the configurations present in configuration + space defined by PARAMS. + The configuration chosen is that obtained fixing in this order: + first access + first format + first subformat + min channels + min rate + min period_size + max periods + Return 0 on success otherwise a negative error code +*/ +int _snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_sw_params_t sw; + int fb, min_align; + err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + snd_pcm_hw_params_choose(pcm, params); + if (pcm->setup) { + err = snd_pcm_hw_free(pcm); + if (err < 0) + return err; + } + err = pcm->ops->hw_params(pcm->op_arg, params); + if (err < 0) + return err; + + pcm->setup = 1; + INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access); + INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format); + INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat); + INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels); + INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0); + INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0); + INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0); + INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size); + pcm->sample_bits = snd_pcm_format_physical_width(pcm->format); + pcm->frame_bits = pcm->sample_bits * pcm->channels; + fb = pcm->frame_bits; + min_align = 1; + while (fb % 8) { + fb *= 2; + min_align *= 2; + } + pcm->min_align = min_align; + + pcm->hw_flags = params->flags; + pcm->info = params->info; + pcm->msbits = params->msbits; + pcm->rate_num = params->rate_num; + pcm->rate_den = params->rate_den; + pcm->fifo_size = params->fifo_size; + + /* Default sw params */ + memset(&sw, 0, sizeof(sw)); + snd_pcm_sw_params_default(pcm, &sw); + err = snd_pcm_sw_params(pcm, &sw); + assert(err >= 0); + + if (pcm->mmap_rw || + pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED || + pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED || + pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) { + err = snd_pcm_mmap(pcm); + } + if (err < 0) + return err; + return 0; +} + diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c new file mode 100644 index 0000000..e9d2923 --- /dev/null +++ b/src/pcm/pcm_plug.c @@ -0,0 +1,1323 @@ +/* + * \file pcm/pcm_plug.c + * \ingroup PCM_Plugins + * \brief PCM Route & Volume Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Plug + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_plug = ""; +#endif + +#ifndef DOC_HIDDEN + +enum snd_pcm_plug_route_policy { + PLUG_ROUTE_POLICY_NONE, + PLUG_ROUTE_POLICY_DEFAULT, + PLUG_ROUTE_POLICY_COPY, + PLUG_ROUTE_POLICY_AVERAGE, + PLUG_ROUTE_POLICY_DUP, +}; + +typedef struct { + snd_pcm_generic_t gen; + snd_pcm_t *req_slave; + snd_pcm_format_t sformat; + int schannels; + int srate; + const snd_config_t *rate_converter; + enum snd_pcm_plug_route_policy route_policy; + snd_pcm_route_ttable_entry_t *ttable; + int ttable_ok, ttable_last; + unsigned int tt_ssize, tt_cused, tt_sused; +} snd_pcm_plug_t; + +#endif + +static int snd_pcm_plug_close(snd_pcm_t *pcm) +{ + snd_pcm_plug_t *plug = pcm->private_data; + int err, result = 0; + free(plug->ttable); + assert(plug->gen.slave == plug->req_slave); + if (plug->gen.close_slave) { + snd_pcm_unlink_hw_ptr(pcm, plug->req_slave); + snd_pcm_unlink_appl_ptr(pcm, plug->req_slave); + err = snd_pcm_close(plug->req_slave); + if (err < 0) + result = err; + } + free(plug); + return result; +} + +static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info) +{ + snd_pcm_plug_t *plug = pcm->private_data; + snd_pcm_t *slave = plug->req_slave; + int err; + + if ((err = snd_pcm_info(slave, info)) < 0) + return err; + return 0; +} + +static const snd_pcm_format_t linear_preferred_formats[] = { +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_U16_LE, + SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_U16_BE, +#else + SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_U16_BE, + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_U16_LE, +#endif +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_U32_LE, + SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_U32_BE, +#else + SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_U32_BE, + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_U32_LE, +#endif + SND_PCM_FORMAT_S8, + SND_PCM_FORMAT_U8, +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT64_LE, + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_FLOAT64_BE, +#else + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_FLOAT64_BE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT64_LE, +#endif +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_U24_LE, + SND_PCM_FORMAT_S24_BE, + SND_PCM_FORMAT_U24_BE, +#else + SND_PCM_FORMAT_S24_BE, + SND_PCM_FORMAT_U24_BE, + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_U24_LE, +#endif +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_U24_3LE, + SND_PCM_FORMAT_S24_3BE, + SND_PCM_FORMAT_U24_3BE, +#else + SND_PCM_FORMAT_S24_3BE, + SND_PCM_FORMAT_U24_3BE, + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_U24_3LE, +#endif +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_S20_3LE, + SND_PCM_FORMAT_U20_3LE, + SND_PCM_FORMAT_S20_3BE, + SND_PCM_FORMAT_U20_3BE, +#else + SND_PCM_FORMAT_S20_3BE, + SND_PCM_FORMAT_U20_3BE, + SND_PCM_FORMAT_S20_3LE, + SND_PCM_FORMAT_U20_3LE, +#endif +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_S18_3LE, + SND_PCM_FORMAT_U18_3LE, + SND_PCM_FORMAT_S18_3BE, + SND_PCM_FORMAT_U18_3BE, +#else + SND_PCM_FORMAT_S18_3BE, + SND_PCM_FORMAT_U18_3BE, + SND_PCM_FORMAT_S18_3LE, + SND_PCM_FORMAT_U18_3LE, +#endif +}; + +#if defined(BUILD_PCM_PLUGIN_MULAW) || \ + defined(BUILD_PCM_PLUGIN_ALAW) || \ + defined(BUILD_PCM_PLUGIN_ADPCM) +#define BUILD_PCM_NONLINEAR +#endif + +#ifdef BUILD_PCM_NONLINEAR +static const snd_pcm_format_t nonlinear_preferred_formats[] = { +#ifdef BUILD_PCM_PLUGIN_MULAW + SND_PCM_FORMAT_MU_LAW, +#endif +#ifdef BUILD_PCM_PLUGIN_ALAW + SND_PCM_FORMAT_A_LAW, +#endif +#ifdef BUILD_PCM_PLUGIN_ADPCM + SND_PCM_FORMAT_IMA_ADPCM, +#endif +}; +#endif + +#ifdef BUILD_PCM_PLUGIN_LFLOAT +static const snd_pcm_format_t float_preferred_formats[] = { +#ifdef SND_LITTLE_ENDIAN + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT64_LE, + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_FLOAT64_BE, +#else + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_FLOAT64_BE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT64_LE, +#endif +}; +#endif + +static const char linear_format_widths[32] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 1, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 1, +}; + +static int check_linear_format(const snd_pcm_format_mask_t *format_mask, int wid, int sgn, int ed) +{ + int e, s; + if (! linear_format_widths[wid - 1]) + return SND_PCM_FORMAT_UNKNOWN; + for (e = 0; e < 2; e++) { + for (s = 0; s < 2; s++) { + int pw = ((wid + 7) / 8) * 8; + for (; pw <= 32; pw += 8) { + snd_pcm_format_t f; + f = snd_pcm_build_linear_format(wid, pw, sgn, ed); + if (f != SND_PCM_FORMAT_UNKNOWN && + snd_pcm_format_mask_test(format_mask, f)) + return f; + } + sgn = !sgn; + } + ed = !ed; + } + return SND_PCM_FORMAT_UNKNOWN; +} + +static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const snd_pcm_format_mask_t *format_mask) +{ + int w, w1, u, e; + snd_pcm_format_t f; + snd_pcm_format_mask_t lin = { SND_PCM_FMTBIT_LINEAR }; + snd_pcm_format_mask_t fl = { +#ifdef BUILD_PCM_PLUGIN_LFLOAT + SND_PCM_FMTBIT_FLOAT +#else + { 0 } +#endif + }; + if (snd_pcm_format_mask_test(format_mask, format)) + return format; + if (!snd_pcm_format_mask_test(&lin, format) && + !snd_pcm_format_mask_test(&fl, format)) { + unsigned int i; + switch (format) { +#ifdef BUILD_PCM_PLUGIN_MULAW + case SND_PCM_FORMAT_MU_LAW: +#endif +#ifdef BUILD_PCM_PLUGIN_ALAW + case SND_PCM_FORMAT_A_LAW: +#endif +#ifdef BUILD_PCM_PLUGIN_ADPCM + case SND_PCM_FORMAT_IMA_ADPCM: +#endif + for (i = 0; i < sizeof(linear_preferred_formats) / sizeof(linear_preferred_formats[0]); ++i) { + snd_pcm_format_t f = linear_preferred_formats[i]; + if (snd_pcm_format_mask_test(format_mask, f)) + return f; + } + /* Fall through */ + default: + return SND_PCM_FORMAT_UNKNOWN; + } + + } + snd_mask_intersect(&lin, format_mask); + snd_mask_intersect(&fl, format_mask); + if (snd_mask_empty(&lin) && snd_mask_empty(&fl)) { +#ifdef BUILD_PCM_NONLINEAR + unsigned int i; + for (i = 0; i < sizeof(nonlinear_preferred_formats) / sizeof(nonlinear_preferred_formats[0]); ++i) { + snd_pcm_format_t f = nonlinear_preferred_formats[i]; + if (snd_pcm_format_mask_test(format_mask, f)) + return f; + } +#endif + return SND_PCM_FORMAT_UNKNOWN; + } +#ifdef BUILD_PCM_PLUGIN_LFLOAT + if (snd_pcm_format_float(format)) { + if (snd_pcm_format_mask_test(&fl, format)) { + unsigned int i; + for (i = 0; i < sizeof(float_preferred_formats) / sizeof(float_preferred_formats[0]); ++i) { + snd_pcm_format_t f = float_preferred_formats[i]; + if (snd_pcm_format_mask_test(format_mask, f)) + return f; + } + } + w = 32; + u = 0; + e = snd_pcm_format_big_endian(format); + } else +#endif + if (snd_mask_empty(&lin)) { +#ifdef BUILD_PCM_PLUGIN_LFLOAT + unsigned int i; + for (i = 0; i < sizeof(float_preferred_formats) / sizeof(float_preferred_formats[0]); ++i) { + snd_pcm_format_t f = float_preferred_formats[i]; + if (snd_pcm_format_mask_test(format_mask, f)) + return f; + } +#endif + return SND_PCM_FORMAT_UNKNOWN; + } else { + w = snd_pcm_format_width(format); + u = snd_pcm_format_unsigned(format); + e = snd_pcm_format_big_endian(format); + } + for (w1 = w; w1 <= 32; w1++) { + f = check_linear_format(format_mask, w1, u, e); + if (f != SND_PCM_FORMAT_UNKNOWN) + return f; + } + for (w1 = w - 1; w1 > 0; w1--) { + f = check_linear_format(format_mask, w1, u, e); + if (f != SND_PCM_FORMAT_UNKNOWN) + return f; + } + return SND_PCM_FORMAT_UNKNOWN; +} + +static void snd_pcm_plug_clear(snd_pcm_t *pcm) +{ + snd_pcm_plug_t *plug = pcm->private_data; + snd_pcm_t *slave = plug->req_slave; + /* Clear old plugins */ + if (plug->gen.slave != slave) { + snd_pcm_unlink_hw_ptr(pcm, plug->gen.slave); + snd_pcm_unlink_appl_ptr(pcm, plug->gen.slave); + snd_pcm_close(plug->gen.slave); + plug->gen.slave = slave; + pcm->fast_ops = slave->fast_ops; + pcm->fast_op_arg = slave->fast_op_arg; + } +} + +#ifndef DOC_HIDDEN +typedef struct { + snd_pcm_access_t access; + snd_pcm_format_t format; + unsigned int channels; + unsigned int rate; +} snd_pcm_plug_params_t; +#endif + +#ifdef BUILD_PCM_PLUGIN_RATE +static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv) +{ + snd_pcm_plug_t *plug = pcm->private_data; + int err; + if (clt->rate == slv->rate) + return 0; + assert(snd_pcm_format_linear(slv->format)); + err = snd_pcm_rate_open(new, NULL, slv->format, slv->rate, plug->rate_converter, + plug->gen.slave, plug->gen.slave != plug->req_slave); + if (err < 0) + return err; + slv->access = clt->access; + slv->rate = clt->rate; + if (snd_pcm_format_linear(clt->format)) + slv->format = clt->format; + return 1; +} +#endif + +#ifdef BUILD_PCM_PLUGIN_ROUTE +static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv) +{ + snd_pcm_plug_t *plug = pcm->private_data; + unsigned int tt_ssize, tt_cused, tt_sused; + snd_pcm_route_ttable_entry_t *ttable; + int err; + if (clt->channels == slv->channels && + (!plug->ttable || !plug->ttable_last)) + return 0; + if (clt->rate != slv->rate && + clt->channels > slv->channels) + return 0; + assert(snd_pcm_format_linear(slv->format)); + tt_ssize = slv->channels; + tt_cused = clt->channels; + tt_sused = slv->channels; + ttable = alloca(tt_cused * tt_sused * sizeof(*ttable)); + if (plug->ttable) { /* expand or shrink table */ + unsigned int c = 0, s = 0; + for (c = 0; c < tt_cused; c++) { + for (s = 0; s < tt_sused; s++) { + snd_pcm_route_ttable_entry_t v; + if (c >= plug->tt_cused) + v = 0; + else if (s >= plug->tt_sused) + v = 0; + else + v = plug->ttable[c * plug->tt_ssize + s]; + ttable[c * tt_ssize + s] = v; + } + } + plug->ttable_ok = 1; + } else { + unsigned int k; + unsigned int c = 0, s = 0; + enum snd_pcm_plug_route_policy rpolicy = plug->route_policy; + int n; + for (k = 0; k < tt_cused * tt_sused; ++k) + ttable[k] = 0; + if (rpolicy == PLUG_ROUTE_POLICY_DEFAULT) { + rpolicy = PLUG_ROUTE_POLICY_COPY; + /* it's hack for mono conversion */ + if (clt->channels == 1 || slv->channels == 1) + rpolicy = PLUG_ROUTE_POLICY_AVERAGE; + } + switch (rpolicy) { + case PLUG_ROUTE_POLICY_AVERAGE: + case PLUG_ROUTE_POLICY_DUP: + if (clt->channels > slv->channels) { + n = clt->channels; + } else { + n = slv->channels; + } + while (n-- > 0) { + snd_pcm_route_ttable_entry_t v = SND_PCM_PLUGIN_ROUTE_FULL; + if (rpolicy == PLUG_ROUTE_POLICY_AVERAGE) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK && + clt->channels > slv->channels) { + int srcs = clt->channels / slv->channels; + if (s < clt->channels % slv->channels) + srcs++; + v /= srcs; + } else if (pcm->stream == SND_PCM_STREAM_CAPTURE && + slv->channels > clt->channels) { + int srcs = slv->channels / clt->channels; + if (s < slv->channels % clt->channels) + srcs++; + v /= srcs; + } + } + ttable[c * tt_ssize + s] = v; + if (++c == clt->channels) + c = 0; + if (++s == slv->channels) + s = 0; + } + break; + case PLUG_ROUTE_POLICY_COPY: + if (clt->channels < slv->channels) { + n = clt->channels; + } else { + n = slv->channels; + } + for (c = 0; (int)c < n; c++) + ttable[c * tt_ssize + c] = SND_PCM_PLUGIN_ROUTE_FULL; + break; + default: + SNDERR("Invalid route policy"); + break; + } + } + err = snd_pcm_route_open(new, NULL, slv->format, (int) slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->gen.slave, plug->gen.slave != plug->req_slave); + if (err < 0) + return err; + slv->channels = clt->channels; + slv->access = clt->access; + if (snd_pcm_format_linear(clt->format)) + slv->format = clt->format; + return 1; +} +#endif + +static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv) +{ + snd_pcm_plug_t *plug = pcm->private_data; + int err; + snd_pcm_format_t cfmt; + int (*f)(snd_pcm_t **_pcm, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave); + + /* No conversion is needed */ + if (clt->format == slv->format && + clt->rate == slv->rate && + clt->channels == slv->channels) + return 0; + + if (snd_pcm_format_linear(slv->format)) { + /* Conversion is done in another plugin */ + if (clt->rate != slv->rate || + clt->channels != slv->channels) + return 0; + cfmt = clt->format; + switch (clt->format) { +#ifdef BUILD_PCM_PLUGIN_MULAW + case SND_PCM_FORMAT_MU_LAW: + f = snd_pcm_mulaw_open; + break; +#endif +#ifdef BUILD_PCM_PLUGIN_ALAW + case SND_PCM_FORMAT_A_LAW: + f = snd_pcm_alaw_open; + break; +#endif +#ifdef BUILD_PCM_PLUGIN_ADPCM + case SND_PCM_FORMAT_IMA_ADPCM: + f = snd_pcm_adpcm_open; + break; +#endif + default: +#ifdef BUILD_PCM_PLUGIN_LFLOAT + if (snd_pcm_format_float(clt->format)) + f = snd_pcm_lfloat_open; + + else +#endif + f = snd_pcm_linear_open; + break; + } +#ifdef BUILD_PCM_PLUGIN_LFLOAT + } else if (snd_pcm_format_float(slv->format)) { + /* Conversion is done in another plugin */ + if (clt->format == slv->format && + clt->rate == slv->rate && + clt->channels == slv->channels) + return 0; + cfmt = clt->format; + if (snd_pcm_format_linear(clt->format)) + f = snd_pcm_lfloat_open; + else + return -EINVAL; +#endif +#ifdef BUILD_PCM_NONLINEAR + } else { + switch (slv->format) { +#ifdef BUILD_PCM_PLUGIN_MULAW + case SND_PCM_FORMAT_MU_LAW: + f = snd_pcm_mulaw_open; + break; +#endif +#ifdef BUILD_PCM_PLUGIN_ALAW + case SND_PCM_FORMAT_A_LAW: + f = snd_pcm_alaw_open; + break; +#endif +#ifdef BUILD_PCM_PLUGIN_ADPCM + case SND_PCM_FORMAT_IMA_ADPCM: + f = snd_pcm_adpcm_open; + break; +#endif + default: + return -EINVAL; + } + if (snd_pcm_format_linear(clt->format)) + cfmt = clt->format; + else + cfmt = SND_PCM_FORMAT_S16; +#endif /* NONLINEAR */ + } + err = f(new, NULL, slv->format, plug->gen.slave, plug->gen.slave != plug->req_slave); + if (err < 0) + return err; + slv->format = cfmt; + slv->access = clt->access; + return 1; +} + +static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv) +{ + snd_pcm_plug_t *plug = pcm->private_data; + int err; + if (clt->access == slv->access) + return 0; + err = snd_pcm_copy_open(new, NULL, plug->gen.slave, plug->gen.slave != plug->req_slave); + if (err < 0) + return err; + slv->access = clt->access; + return 1; +} + +#ifdef BUILD_PCM_PLUGIN_MMAP_EMUL +static int snd_pcm_plug_change_mmap(snd_pcm_t *pcm, snd_pcm_t **new, + snd_pcm_plug_params_t *clt, + snd_pcm_plug_params_t *slv) +{ + snd_pcm_plug_t *plug = pcm->private_data; + int err; + + if (clt->access == slv->access) + return 0; + + switch (slv->access) { + case SND_PCM_ACCESS_MMAP_INTERLEAVED: + case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: + case SND_PCM_ACCESS_MMAP_COMPLEX: + return 0; + default: + break; + } + + err = __snd_pcm_mmap_emul_open(new, NULL, plug->gen.slave, + plug->gen.slave != plug->req_slave); + if (err < 0) + return err; + switch (slv->access) { + case SND_PCM_ACCESS_RW_INTERLEAVED: + slv->access = SND_PCM_ACCESS_MMAP_INTERLEAVED; + break; + case SND_PCM_ACCESS_RW_NONINTERLEAVED: + slv->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; + break; + default: + break; + } + return 1; +} +#endif + +static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm, + snd_pcm_plug_params_t *client, + snd_pcm_plug_params_t *slave) +{ + snd_pcm_plug_t *plug = pcm->private_data; + static int (*const funcs[])(snd_pcm_t *_pcm, snd_pcm_t **new, snd_pcm_plug_params_t *s, snd_pcm_plug_params_t *d) = { +#ifdef BUILD_PCM_PLUGIN_MMAP_EMUL + snd_pcm_plug_change_mmap, +#endif + snd_pcm_plug_change_format, +#ifdef BUILD_PCM_PLUGIN_ROUTE + snd_pcm_plug_change_channels, +#endif +#ifdef BUILD_PCM_PLUGIN_RATE + snd_pcm_plug_change_rate, +#endif +#ifdef BUILD_PCM_PLUGIN_ROUTE + snd_pcm_plug_change_channels, +#endif + snd_pcm_plug_change_format, + snd_pcm_plug_change_access + }; + snd_pcm_plug_params_t p = *slave; + unsigned int k = 0; + plug->ttable_ok = plug->ttable_last = 0; + while (client->format != p.format || + client->channels != p.channels || + client->rate != p.rate || + client->access != p.access) { + snd_pcm_t *new; + int err; + if (k >= sizeof(funcs)/sizeof(*funcs)) + return -EINVAL; + err = funcs[k](pcm, &new, client, &p); + if (err < 0) { + snd_pcm_plug_clear(pcm); + return err; + } + if (err) { + plug->gen.slave = new; + pcm->fast_ops = new->fast_ops; + pcm->fast_op_arg = new->fast_op_arg; + } + k++; + } +#ifdef BUILD_PCM_PLUGIN_ROUTE + /* it's exception, user specified ttable, but no reduction/expand */ + if (plug->ttable && !plug->ttable_ok) { + snd_pcm_t *new; + int err; + plug->ttable_last = 1; + err = snd_pcm_plug_change_channels(pcm, &new, client, &p); + if (err < 0) { + snd_pcm_plug_clear(pcm); + return err; + } + assert(err); + assert(plug->ttable_ok); + plug->gen.slave = new; + pcm->fast_ops = new->fast_ops; + pcm->fast_op_arg = new->fast_op_arg; + } +#endif + return 0; +} + +static int snd_pcm_plug_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + unsigned int rate_min, channels_max; + int err; + + /* HACK: to avoid overflow in PARTBIT_RATE code */ + err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, NULL); + if (err < 0) + return err; + if (rate_min < 4000) { + _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, 4000, 0); + if (snd_pcm_hw_param_empty(params, SND_PCM_HW_PARAM_RATE)) + return -EINVAL; + } + /* HACK: to avoid overflow in PERIOD_SIZE code */ + err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_CHANNELS, &channels_max, NULL); + if (err < 0) + return err; + if (channels_max > 10000) { + _snd_pcm_hw_param_set_max(params, SND_PCM_HW_PARAM_CHANNELS, 10000, 0); + if (snd_pcm_hw_param_empty(params, SND_PCM_HW_PARAM_CHANNELS)) + return -EINVAL; + } + return 0; +} + +static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_plug_t *plug = pcm->private_data; + int err; + + _snd_pcm_hw_params_any(sparams); + if (plug->sformat >= 0) { + _snd_pcm_hw_params_set_format(sparams, plug->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + } + if (plug->schannels > 0) + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, + plug->schannels, 0); + if (plug->srate > 0) + _snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE, + plug->srate, 0, plug->srate + 1, -1); + /* reduce the available configurations */ + err = snd_pcm_hw_refine(plug->req_slave, sparams); + if (err < 0) + return err; + return 0; +} + +static int check_access_change(snd_pcm_hw_params_t *cparams, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_access_mask_t *smask; +#ifdef BUILD_PCM_PLUGIN_MMAP_EMUL + const snd_pcm_access_mask_t *cmask; + snd_pcm_access_mask_t mask; +#endif + + smask = (snd_pcm_access_mask_t *) + snd_pcm_hw_param_get_mask(sparams, + SND_PCM_HW_PARAM_ACCESS); + if (snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_MMAP_INTERLEAVED) || + snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) || + snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_MMAP_COMPLEX)) + return 0; /* OK, we have mmap support */ +#ifdef BUILD_PCM_PLUGIN_MMAP_EMUL + /* no mmap support - we need mmap emulation */ + + if (!snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) + return -EINVAL; /* even no RW access? no way! */ + + cmask = (const snd_pcm_access_mask_t *) + snd_pcm_hw_param_get_mask(cparams, + SND_PCM_HW_PARAM_ACCESS); + snd_mask_none(&mask); + if (snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_RW_INTERLEAVED) || + snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) { + if (snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_RW_INTERLEAVED)) + snd_pcm_access_mask_set(&mask, + SND_PCM_ACCESS_RW_INTERLEAVED); + } + if (snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_RW_NONINTERLEAVED) || + snd_pcm_access_mask_test(cmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { + if (snd_pcm_access_mask_test(smask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) + snd_pcm_access_mask_set(&mask, + SND_PCM_ACCESS_RW_NONINTERLEAVED); + } + if (!snd_mask_empty(&mask)) + *smask = mask; /* prefer the straight conversion */ + return 0; +#else + return -EINVAL; +#endif +} + +static int snd_pcm_plug_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_plug_t *plug = pcm->private_data; + snd_pcm_t *slave = plug->req_slave; + unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + const snd_pcm_format_mask_t *format_mask, *sformat_mask; + snd_pcm_format_mask_t sfmt_mask; + int err; + snd_pcm_format_t format; + snd_interval_t t, buffer_size; + const snd_interval_t *srate, *crate; + + if (plug->srate == -2 || + (pcm->mode & SND_PCM_NO_AUTO_RESAMPLE) || + (params->flags & SND_PCM_HW_PARAMS_NORESAMPLE)) + links |= SND_PCM_HW_PARBIT_RATE; + else { + err = snd_pcm_hw_param_refine_multiple(slave, sparams, SND_PCM_HW_PARAM_RATE, params); + if (err < 0) + return err; + } + + if (plug->schannels == -2 || (pcm->mode & SND_PCM_NO_AUTO_CHANNELS)) + links |= SND_PCM_HW_PARBIT_CHANNELS; + else { + err = snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS, params); + if (err < 0) + return err; + } + if (plug->sformat == -2 || (pcm->mode & SND_PCM_NO_AUTO_FORMAT)) + links |= SND_PCM_HW_PARBIT_FORMAT; + else { + format_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_FORMAT); + sformat_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_FORMAT); + snd_mask_none(&sfmt_mask); + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + snd_pcm_format_t f; + if (!snd_pcm_format_mask_test(format_mask, format)) + continue; + if (snd_pcm_format_mask_test(sformat_mask, format)) + f = format; + else { + f = snd_pcm_plug_slave_format(format, sformat_mask); + if (f == SND_PCM_FORMAT_UNKNOWN) + continue; + } + snd_pcm_format_mask_set(&sfmt_mask, f); + } + + if (snd_pcm_format_mask_empty(&sfmt_mask)) { + SNDERR("Unable to find an usable slave format for '%s'", pcm->name); + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (!snd_pcm_format_mask_test(format_mask, format)) + continue; + SNDERR("Format: %s", snd_pcm_format_name(format)); + } + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (!snd_pcm_format_mask_test(sformat_mask, format)) + continue; + SNDERR("Slave format: %s", snd_pcm_format_name(format)); + } + return -EINVAL; + } + err = snd_pcm_hw_param_set_mask(slave, sparams, SND_CHANGE, + SND_PCM_HW_PARAM_FORMAT, &sfmt_mask); + if (err < 0) + return -EINVAL; + } + + if (snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_ACCESS, sparams)) { + err = check_access_change(params, sparams); + if (err < 0) { + SNDERR("Unable to find an usable access for '%s'", + pcm->name); + return err; + } + } + + if ((links & SND_PCM_HW_PARBIT_RATE) || + snd_pcm_hw_param_always_eq(params, SND_PCM_HW_PARAM_RATE, sparams)) + links |= (SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE); + else { + snd_interval_copy(&buffer_size, snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE)); + snd_interval_unfloor(&buffer_size); + crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE); + snd_interval_muldiv(&buffer_size, srate, crate, &t); + err = _snd_pcm_hw_param_set_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_plug_t *plug = pcm->private_data; + unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + const snd_pcm_format_mask_t *format_mask, *sformat_mask; + snd_pcm_format_mask_t fmt_mask; + int err; + snd_pcm_format_t format; + snd_interval_t t; + const snd_interval_t *sbuffer_size; + const snd_interval_t *srate, *crate; + + if (plug->schannels == -2 || (pcm->mode & SND_PCM_NO_AUTO_CHANNELS)) + links |= SND_PCM_HW_PARBIT_CHANNELS; + + if (plug->sformat == -2 || (pcm->mode & SND_PCM_NO_AUTO_FORMAT)) + links |= SND_PCM_HW_PARBIT_FORMAT; + else { + format_mask = snd_pcm_hw_param_get_mask(params, + SND_PCM_HW_PARAM_FORMAT); + sformat_mask = snd_pcm_hw_param_get_mask(sparams, + SND_PCM_HW_PARAM_FORMAT); + snd_mask_none(&fmt_mask); + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + snd_pcm_format_t f; + if (!snd_pcm_format_mask_test(format_mask, format)) + continue; + if (snd_pcm_format_mask_test(sformat_mask, format)) + f = format; + else { + f = snd_pcm_plug_slave_format(format, sformat_mask); + if (f == SND_PCM_FORMAT_UNKNOWN) + continue; + } + snd_pcm_format_mask_set(&fmt_mask, format); + } + + if (snd_pcm_format_mask_empty(&fmt_mask)) { + SNDERR("Unable to find an usable client format"); + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (!snd_pcm_format_mask_test(format_mask, format)) + continue; + SNDERR("Format: %s", snd_pcm_format_name(format)); + } + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { + if (!snd_pcm_format_mask_test(sformat_mask, format)) + continue; + SNDERR("Slave format: %s", snd_pcm_format_name(format)); + } + return -EINVAL; + } + + err = _snd_pcm_hw_param_set_mask(params, + SND_PCM_HW_PARAM_FORMAT, &fmt_mask); + if (err < 0) + return err; + } + + if (plug->srate == -2 || + (pcm->mode & SND_PCM_NO_AUTO_RESAMPLE) || + (params->flags & SND_PCM_HW_PARAMS_NORESAMPLE)) + links |= SND_PCM_HW_PARBIT_RATE; + else { + unsigned int rate_min, srate_min; + int rate_mindir, srate_mindir; + + /* This is a temporary hack, waiting for a better solution */ + err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, &rate_min, &rate_mindir); + if (err < 0) + return err; + err = snd_pcm_hw_param_get_min(sparams, SND_PCM_HW_PARAM_RATE, &srate_min, &srate_mindir); + if (err < 0) + return err; + if (rate_min == srate_min && srate_mindir > rate_mindir) { + err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, srate_min, srate_mindir); + if (err < 0) + return err; + } + } + if ((links & SND_PCM_HW_PARBIT_RATE) || + snd_pcm_hw_param_always_eq(params, SND_PCM_HW_PARAM_RATE, sparams)) + links |= (SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_BUFFER_SIZE); + else { + sbuffer_size = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); + crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE); + snd_interval_muldiv(sbuffer_size, crate, srate, &t); + snd_interval_floor(&t); + if (snd_interval_empty(&t)) + return -EINVAL; + err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + /* FIXME */ + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_plug_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_plug_t *plug = pcm->private_data; + return snd_pcm_hw_refine(plug->req_slave, params); +} + +static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_plug_hw_refine_cprepare, + snd_pcm_plug_hw_refine_cchange, + snd_pcm_plug_hw_refine_sprepare, + snd_pcm_plug_hw_refine_schange, + snd_pcm_plug_hw_refine_slave); +} + +static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_plug_t *plug = pcm->private_data; + snd_pcm_t *slave = plug->req_slave; + snd_pcm_plug_params_t clt_params, slv_params; + snd_pcm_hw_params_t sparams; + int err; + + err = snd_pcm_plug_hw_refine_sprepare(pcm, &sparams); + if (err < 0) + return err; + err = snd_pcm_plug_hw_refine_schange(pcm, params, &sparams); + if (err < 0) + return err; + err = snd_pcm_hw_refine_soft(slave, &sparams); + if (err < 0) + return err; + + INTERNAL(snd_pcm_hw_params_get_access)(params, &clt_params.access); + INTERNAL(snd_pcm_hw_params_get_format)(params, &clt_params.format); + INTERNAL(snd_pcm_hw_params_get_channels)(params, &clt_params.channels); + INTERNAL(snd_pcm_hw_params_get_rate)(params, &clt_params.rate, 0); + + INTERNAL(snd_pcm_hw_params_get_format)(&sparams, &slv_params.format); + INTERNAL(snd_pcm_hw_params_get_channels)(&sparams, &slv_params.channels); + INTERNAL(snd_pcm_hw_params_get_rate)(&sparams, &slv_params.rate, 0); + snd_pcm_plug_clear(pcm); + if (!(clt_params.format == slv_params.format && + clt_params.channels == slv_params.channels && + clt_params.rate == slv_params.rate && + !plug->ttable && + snd_pcm_hw_params_test_access(slave, &sparams, + clt_params.access) >= 0)) { + INTERNAL(snd_pcm_hw_params_set_access_first)(slave, &sparams, &slv_params.access); + err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params); + if (err < 0) + return err; + } + slave = plug->gen.slave; + err = _snd_pcm_hw_params(slave, params); + if (err < 0) { + snd_pcm_plug_clear(pcm); + return err; + } + snd_pcm_unlink_hw_ptr(pcm, plug->req_slave); + snd_pcm_unlink_appl_ptr(pcm, plug->req_slave); + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + return 0; +} + +static int snd_pcm_plug_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_plug_t *plug = pcm->private_data; + snd_pcm_t *slave = plug->gen.slave; + int err = snd_pcm_hw_free(slave); + snd_pcm_plug_clear(pcm); + return err; +} + +static void snd_pcm_plug_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_plug_t *plug = pcm->private_data; + snd_output_printf(out, "Plug PCM: "); + snd_pcm_dump(plug->gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_plug_ops = { + .close = snd_pcm_plug_close, + .info = snd_pcm_plug_info, + .hw_refine = snd_pcm_plug_hw_refine, + .hw_params = snd_pcm_plug_hw_params, + .hw_free = snd_pcm_plug_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_plug_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new Plug PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave (destination) format + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_plug_open(snd_pcm_t **pcmp, + const char *name, + snd_pcm_format_t sformat, int schannels, int srate, + const snd_config_t *rate_converter, + enum snd_pcm_plug_route_policy route_policy, + snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_ssize, + unsigned int tt_cused, unsigned int tt_sused, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_plug_t *plug; + int err; + assert(pcmp && slave); + + plug = calloc(1, sizeof(snd_pcm_plug_t)); + if (!plug) + return -ENOMEM; + plug->sformat = sformat; + plug->schannels = schannels; + plug->srate = srate; + plug->rate_converter = rate_converter; + plug->gen.slave = plug->req_slave = slave; + plug->gen.close_slave = close_slave; + plug->route_policy = route_policy; + plug->ttable = ttable; + plug->tt_ssize = tt_ssize; + plug->tt_cused = tt_cused; + plug->tt_sused = tt_sused; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_PLUG, name, slave->stream, slave->mode); + if (err < 0) { + free(plug); + return err; + } + pcm->ops = &snd_pcm_plug_ops; + pcm->fast_ops = slave->fast_ops; + pcm->fast_op_arg = slave->fast_op_arg; + pcm->private_data = plug; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; + pcm->monotonic = slave->monotonic; + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_plug Automatic conversion plugin + +This plugin converts channels, rate and format on request. + +\code +pcm.name { + type plug # Automatic conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format (default nearest) or "unchanged" + [channels INT] # Slave channels (default nearest) or "unchanged" + [rate INT] # Slave rate (default nearest) or "unchanged" + } + route_policy STR # route policy for automatic ttable generation + # STR can be 'default', 'average', 'copy', 'duplicate' + # average: result is average of input channels + # copy: only first channels are copied to destination + # duplicate: duplicate first set of channels + # default: copy policy, except for mono capture - sum + ttable { # Transfer table (bi-dimensional compound of cchannels * schannels numbers) + CCHANNEL { + SCHANNEL REAL # route value (0.0 - 1.0) + } + } + rate_converter STR # type of rate converter + # or + rate_converter [ STR1 STR2 ... ] + # type of rate converter + # default value is taken from defaults.pcm.rate_converter +} +\endcode + +\subsection pcm_plugins_plug_funcref Function reference + +
    +
  • snd_pcm_plug_open() +
  • _snd_pcm_plug_open() +
+ +*/ + +/** + * \brief Creates a new Plug PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Plug PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_config_t *tt = NULL; + enum snd_pcm_plug_route_policy route_policy = PLUG_ROUTE_POLICY_DEFAULT; + snd_pcm_route_ttable_entry_t *ttable = NULL; + unsigned int csize, ssize; + unsigned int cused, sused; + snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; + int schannels = -1, srate = -1; + const snd_config_t *rate_converter = NULL; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } +#ifdef BUILD_PCM_PLUGIN_ROUTE + if (strcmp(id, "ttable") == 0) { + route_policy = PLUG_ROUTE_POLICY_NONE; + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + tt = n; + continue; + } + if (strcmp(id, "route_policy") == 0) { + const char *str; + if ((err = snd_config_get_string(n, &str)) < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + if (tt != NULL) + SNDERR("Table is defined, route policy is ignored"); + if (!strcmp(str, "default")) + route_policy = PLUG_ROUTE_POLICY_DEFAULT; + else if (!strcmp(str, "average")) + route_policy = PLUG_ROUTE_POLICY_AVERAGE; + else if (!strcmp(str, "copy")) + route_policy = PLUG_ROUTE_POLICY_COPY; + else if (!strcmp(str, "duplicate")) + route_policy = PLUG_ROUTE_POLICY_DUP; + continue; + } +#endif +#ifdef BUILD_PCM_PLUGIN_RATE + if (strcmp(id, "rate_converter") == 0) { + rate_converter = n; + continue; + } +#endif + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 3, + SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &sformat, + SND_PCM_HW_PARAM_CHANNELS, SCONF_UNCHANGED, &schannels, + SND_PCM_HW_PARAM_RATE, SCONF_UNCHANGED, &srate); + if (err < 0) + return err; +#ifdef BUILD_PCM_PLUGIN_ROUTE + if (tt) { + err = snd_pcm_route_determine_ttable(tt, &csize, &ssize); + if (err < 0) { + snd_config_delete(sconf); + return err; + } + ttable = malloc(csize * ssize * sizeof(*ttable)); + if (ttable == NULL) { + snd_config_delete(sconf); + return err; + } + err = snd_pcm_route_load_ttable(tt, ttable, csize, ssize, &cused, &sused, -1); + if (err < 0) { + snd_config_delete(sconf); + return err; + } + } +#endif + +#ifdef BUILD_PCM_PLUGIN_RATE + if (! rate_converter) + rate_converter = snd_pcm_rate_get_default_converter(root); +#endif + + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_plug_open(pcmp, name, sformat, schannels, srate, rate_converter, + route_policy, ttable, ssize, cused, sused, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_plug_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c new file mode 100644 index 0000000..d88e117 --- /dev/null +++ b/src/pcm/pcm_plugin.c @@ -0,0 +1,575 @@ +/** + * \file pcm/pcm_plugin.c + * \ingroup PCM + * \brief PCM Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Common plugin code + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! + +\page pcm_plugins PCM (digital audio) plugins + +PCM plugins extends functionality and features of PCM devices. +The plugins take care about various sample conversions, sample +copying among channels and so on. + +\section pcm_plugins_slave Slave definition + +The slave plugin can be specified directly with a string or the definition +can be entered inside a compound configuration node. Some restrictions can +be also specified (like static rate or count of channels). + +\code +pcm_slave.NAME { + pcm STR # PCM name + # or + pcm { } # PCM definition + format STR # Format or "unchanged" + channels INT # Count of channels or "unchanged" string + rate INT # Rate in Hz or "unchanged" string + period_time INT # Period time in us or "unchanged" string + buffer_time INT # Buffer time in us or "unchanged" string +} +\endcode + +Example: + +\code +pcm_slave.slave_rate44100Hz { + pcm "hw:0,0" + rate 44100 +} + +pcm.rate44100Hz { + type plug + slave slave_rate44100Hz +} +\endcode + +The equivalent configuration (in one compound): + +\code +pcm.rate44100Hz { + type plug + slave { + pcm "hw:0,0" + rate 44100 + } +} +\endcode + +*/ + +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef DOC_HIDDEN + +static snd_pcm_sframes_t +snd_pcm_plugin_undo_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +static snd_pcm_sframes_t +snd_pcm_plugin_undo_write(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED) +{ + return -EIO; +} + +snd_pcm_sframes_t +snd_pcm_plugin_undo_read_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size) +{ + return slave_undo_size; +} + +snd_pcm_sframes_t +snd_pcm_plugin_undo_write_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, + snd_pcm_uframes_t slave_undo_size) +{ + return slave_undo_size; +} + +void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin) +{ + memset(plugin, 0, sizeof(snd_pcm_plugin_t)); + plugin->undo_read = snd_pcm_plugin_undo_read; + plugin->undo_write = snd_pcm_plugin_undo_write; + snd_atomic_write_init(&plugin->watom); +} + +static int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_sframes_t sd; + int err = snd_pcm_delay(plugin->gen.slave, &sd); + if (err < 0) + return err; + if (pcm->stream == SND_PCM_STREAM_CAPTURE && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { + sd += snd_pcm_mmap_capture_avail(pcm); + } + + *delayp = sd; + return 0; +} + +static int snd_pcm_plugin_prepare(snd_pcm_t *pcm) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + int err; + snd_atomic_write_begin(&plugin->watom); + err = snd_pcm_prepare(plugin->gen.slave); + if (err < 0) { + snd_atomic_write_end(&plugin->watom); + return err; + } + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + snd_atomic_write_end(&plugin->watom); + if (plugin->init) { + err = plugin->init(pcm); + if (err < 0) + return err; + } + return 0; +} + +static int snd_pcm_plugin_reset(snd_pcm_t *pcm) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + int err; + snd_atomic_write_begin(&plugin->watom); + err = snd_pcm_reset(plugin->gen.slave); + if (err < 0) { + snd_atomic_write_end(&plugin->watom); + return err; + } + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + snd_atomic_write_end(&plugin->watom); + if (plugin->init) { + err = plugin->init(pcm); + if (err < 0) + return err; + } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_hw_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm); + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n < frames) + frames = n; + if (frames == 0) + return 0; + + sframes = frames; + snd_atomic_write_begin(&plugin->watom); + sframes = snd_pcm_rewind(plugin->gen.slave, sframes); + if (sframes < 0) { + snd_atomic_write_end(&plugin->watom); + return sframes; + } + snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) frames); + snd_atomic_write_end(&plugin->watom); + return (snd_pcm_sframes_t) frames; +} + +static snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_avail(pcm); +} + +static snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm); + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n < frames) + frames = n; + if (frames == 0) + return 0; + + sframes = frames; + snd_atomic_write_begin(&plugin->watom); + sframes = INTERNAL(snd_pcm_forward)(plugin->gen.slave, sframes); + if (sframes < 0) { + snd_atomic_write_end(&plugin->watom); + return sframes; + } + snd_pcm_mmap_appl_forward(pcm, (snd_pcm_uframes_t) frames); + snd_atomic_write_end(&plugin->watom); + return (snd_pcm_sframes_t) frames; +} + +static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; + snd_pcm_uframes_t xfer = 0; + snd_pcm_sframes_t result; + int err; + + while (size > 0) { + snd_pcm_uframes_t frames = size; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + + err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (err < 0 || slave_frames == 0) + break; + frames = plugin->write(pcm, areas, offset, frames, + slave_areas, slave_offset, &slave_frames); + if (CHECK_SANITY(slave_frames > snd_pcm_mmap_playback_avail(slave))) { + SNDMSG("write overflow %ld > %ld", slave_frames, + snd_pcm_mmap_playback_avail(slave)); + return -EPIPE; + } + snd_atomic_write_begin(&plugin->watom); + snd_pcm_mmap_appl_forward(pcm, frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result); + if (res < 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : res; + frames -= res; + } + snd_atomic_write_end(&plugin->watom); + if (result <= 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : result; + offset += frames; + xfer += frames; + size -= frames; + } + return (snd_pcm_sframes_t)xfer; +} + +static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; + snd_pcm_uframes_t xfer = 0; + snd_pcm_sframes_t result; + + while (size > 0) { + snd_pcm_uframes_t frames = size; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + + snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (slave_frames == 0) + break; + frames = (plugin->read)(pcm, areas, offset, frames, + slave_areas, slave_offset, &slave_frames); + if (CHECK_SANITY(slave_frames > snd_pcm_mmap_capture_avail(slave))) { + SNDMSG("read overflow %ld > %ld", slave_frames, + snd_pcm_mmap_playback_avail(slave)); + return -EPIPE; + } + snd_atomic_write_begin(&plugin->watom); + snd_pcm_mmap_appl_forward(pcm, frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + + res = plugin->undo_read(slave, areas, offset, frames, slave_frames - result); + if (res < 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : res; + frames -= res; + } + snd_atomic_write_end(&plugin->watom); + if (result <= 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : result; + offset += frames; + xfer += frames; + size -= frames; + } + return (snd_pcm_sframes_t)xfer; +} + + +static snd_pcm_sframes_t +snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_buf(pcm, areas, (void*)buffer); + return snd_pcm_write_areas(pcm, areas, 0, size, + snd_pcm_plugin_write_areas); +} + +static snd_pcm_sframes_t +snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_bufs(pcm, areas, bufs); + return snd_pcm_write_areas(pcm, areas, 0, size, + snd_pcm_plugin_write_areas); +} + +static snd_pcm_sframes_t +snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_buf(pcm, areas, buffer); + return snd_pcm_read_areas(pcm, areas, 0, size, + snd_pcm_plugin_read_areas); +} + +static snd_pcm_sframes_t +snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_areas_from_bufs(pcm, areas, bufs); + return snd_pcm_read_areas(pcm, areas, 0, size, + snd_pcm_plugin_read_areas); +} + +static snd_pcm_sframes_t +snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t appl_offset; + snd_pcm_sframes_t slave_size; + snd_pcm_sframes_t xfer; + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + snd_atomic_write_begin(&plugin->watom); + snd_pcm_mmap_appl_forward(pcm, size); + snd_atomic_write_end(&plugin->watom); + return size; + } + slave_size = snd_pcm_avail_update(slave); + if (slave_size < 0) + return slave_size; + areas = snd_pcm_mmap_areas(pcm); + appl_offset = snd_pcm_mmap_offset(pcm); + xfer = 0; + while (size > 0 && slave_size > 0) { + snd_pcm_uframes_t frames = size; + snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + int err; + + err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (err < 0) + return xfer > 0 ? xfer : err; + if (frames > cont) + frames = cont; + frames = plugin->write(pcm, areas, appl_offset, frames, + slave_areas, slave_offset, &slave_frames); + snd_atomic_write_begin(&plugin->watom); + snd_pcm_mmap_appl_forward(pcm, frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + snd_atomic_write_end(&plugin->watom); + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + + res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result); + if (res < 0) + return xfer > 0 ? xfer : res; + frames -= res; + } + if (result <= 0) + return xfer > 0 ? xfer : result; + if (frames == cont) + appl_offset = 0; + else + appl_offset += result; + size -= frames; + slave_size -= frames; + xfer += frames; + } + if (CHECK_SANITY(size)) { + SNDMSG("short commit: %ld", size); + return -EPIPE; + } + return xfer; +} + +static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; + snd_pcm_sframes_t slave_size; + + slave_size = snd_pcm_avail_update(slave); + if (pcm->stream == SND_PCM_STREAM_CAPTURE && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) + goto _capture; + *pcm->hw.ptr = *slave->hw.ptr; + return slave_size; + _capture: + { + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t xfer, hw_offset, size; + + xfer = snd_pcm_mmap_capture_avail(pcm); + size = pcm->buffer_size - xfer; + areas = snd_pcm_mmap_areas(pcm); + hw_offset = snd_pcm_mmap_hw_offset(pcm); + while (size > 0 && slave_size > 0) { + snd_pcm_uframes_t frames = size; + snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + int err; + + err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (err < 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; + if (frames > cont) + frames = cont; + frames = (plugin->read)(pcm, areas, hw_offset, frames, + slave_areas, slave_offset, &slave_frames); + snd_atomic_write_begin(&plugin->watom); + snd_pcm_mmap_hw_forward(pcm, frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + snd_atomic_write_end(&plugin->watom); + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + + res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); + if (res < 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : res; + frames -= res; + } + if (result <= 0) + return xfer > 0 ? (snd_pcm_sframes_t)xfer : result; + if (frames == cont) + hw_offset = 0; + else + hw_offset += frames; + size -= frames; + slave_size -= slave_frames; + xfer += frames; + } + return (snd_pcm_sframes_t)xfer; + } +} + +static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_sframes_t err; + snd_atomic_read_t ratom; + snd_atomic_read_init(&ratom, &plugin->watom); + _again: + snd_atomic_read_begin(&ratom); + /* sync with the latest hw and appl ptrs */ + snd_pcm_plugin_avail_update(pcm); + + err = snd_pcm_status(plugin->gen.slave, status); + if (err < 0) { + snd_atomic_read_ok(&ratom); + return err; + } + status->appl_ptr = *pcm->appl.ptr; + status->hw_ptr = *pcm->hw.ptr; + if (!snd_atomic_read_ok(&ratom)) { + snd_atomic_read_wait(&ratom); + goto _again; + } + return 0; +} + +const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { + .status = snd_pcm_plugin_status, + .state = snd_pcm_generic_state, + .hwsync = snd_pcm_generic_hwsync, + .delay = snd_pcm_plugin_delay, + .prepare = snd_pcm_plugin_prepare, + .reset = snd_pcm_plugin_reset, + .start = snd_pcm_generic_start, + .drop = snd_pcm_generic_drop, + .drain = snd_pcm_generic_drain, + .pause = snd_pcm_generic_pause, + .rewindable = snd_pcm_plugin_rewindable, + .rewind = snd_pcm_plugin_rewind, + .forwardable = snd_pcm_plugin_forwardable, + .forward = snd_pcm_plugin_forward, + .resume = snd_pcm_generic_resume, + .link = snd_pcm_generic_link, + .link_slaves = snd_pcm_generic_link_slaves, + .unlink = snd_pcm_generic_unlink, + .writei = snd_pcm_plugin_writei, + .writen = snd_pcm_plugin_writen, + .readi = snd_pcm_plugin_readi, + .readn = snd_pcm_plugin_readn, + .avail_update = snd_pcm_plugin_avail_update, + .mmap_commit = snd_pcm_plugin_mmap_commit, + .htimestamp = snd_pcm_generic_htimestamp, + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_generic_poll_revents, +}; + +#endif diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h new file mode 100644 index 0000000..7ee7c7f --- /dev/null +++ b/src/pcm/pcm_plugin.h @@ -0,0 +1,152 @@ +/* + * PCM - Common plugin code + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "iatomic.h" +#include "pcm_generic.h" + +typedef snd_pcm_uframes_t (*snd_pcm_slave_xfer_areas_func_t) + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep); + +typedef snd_pcm_sframes_t (*snd_pcm_slave_xfer_areas_undo_func_t) + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *res_areas, /* result areas */ + snd_pcm_uframes_t res_offset, /* offset of result areas */ + snd_pcm_uframes_t res_size, /* size of result areas */ + snd_pcm_uframes_t slave_undo_size); + +typedef struct { + snd_pcm_generic_t gen; + snd_pcm_slave_xfer_areas_func_t read; + snd_pcm_slave_xfer_areas_func_t write; + snd_pcm_slave_xfer_areas_undo_func_t undo_read; + snd_pcm_slave_xfer_areas_undo_func_t undo_write; + int (*init)(snd_pcm_t *pcm); + snd_pcm_uframes_t appl_ptr, hw_ptr; + snd_atomic_write_t watom; +} snd_pcm_plugin_t; + +/* make local functions really local */ +#define snd_pcm_plugin_init \ + snd1_pcm_plugin_init +#define snd_pcm_plugin_fast_ops \ + snd1_pcm_plugin_fast_ops +#define snd_pcm_plugin_undo_read_generic \ + snd1_pcm_plugin_undo_read_generic +#define snd_pcm_plugin_undo_write_generic \ + snd1_pcm_plugin_undo_write_generic + +void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin); + +extern const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops; + +snd_pcm_sframes_t snd_pcm_plugin_undo_read_generic + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *res_areas, /* result areas */ + snd_pcm_uframes_t res_offset, /* offset of result areas */ + snd_pcm_uframes_t res_size, /* size of result areas */ + snd_pcm_uframes_t slave_undo_size); + +snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic + (snd_pcm_t *pcm, + const snd_pcm_channel_area_t *res_areas, /* result areas */ + snd_pcm_uframes_t res_offset, /* offset of result areas */ + snd_pcm_uframes_t res_size, /* size of result areas */ + snd_pcm_uframes_t slave_undo_size); + +/* make local functions really local */ +#define snd_pcm_linear_get_index snd1_pcm_linear_get_index +#define snd_pcm_linear_put_index snd1_pcm_linear_put_index +#define snd_pcm_linear_get32_index snd1_pcm_linear_get32_index +#define snd_pcm_linear_put32_index snd1_pcm_linear_put32_index +#define snd_pcm_linear_convert_index snd1_pcm_linear_convert_index +#define snd_pcm_linear_convert snd1_pcm_linear_convert +#define snd_pcm_linear_getput snd1_pcm_linear_getput +#define snd_pcm_alaw_decode snd1_pcm_alaw_decode +#define snd_pcm_alaw_encode snd1_pcm_alaw_encode +#define snd_pcm_mulaw_decode snd1_pcm_mulaw_decode +#define snd_pcm_mulaw_encode snd1_pcm_mulaw_encode +#define snd_pcm_adpcm_decode snd1_pcm_adpcm_decode +#define snd_pcm_adpcm_encode snd1_pcm_adpcm_encode + +int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); +int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); +int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); +int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); +int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); + +void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int convidx); +void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int get_idx, unsigned int put_idx); +void snd_pcm_alaw_decode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int putidx); +void snd_pcm_alaw_encode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getidx); +void snd_pcm_mulaw_decode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int putidx); +void snd_pcm_mulaw_encode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getidx); + +typedef struct _snd_pcm_adpcm_state { + int pred_val; /* Calculated predicted value */ + int step_idx; /* Previous StepSize lookup index */ +} snd_pcm_adpcm_state_t; + +void snd_pcm_adpcm_decode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int putidx, + snd_pcm_adpcm_state_t *states); +void snd_pcm_adpcm_encode(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, + unsigned int getidx, + snd_pcm_adpcm_state_t *states); diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c new file mode 100644 index 0000000..70e30e5 --- /dev/null +++ b/src/pcm/pcm_rate.c @@ -0,0 +1,1539 @@ +/** + * \file pcm/pcm_rate.c + * \ingroup PCM_Plugins + * \brief PCM Rate Plugin Interface + * \author Abramo Bagnara + * \author Jaroslav Kysela + * \date 2000-2004 + */ +/* + * PCM - Rate conversion + * Copyright (c) 2000 by Abramo Bagnara + * 2004 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" +#include "pcm_rate.h" +#include "iatomic.h" + +#include "plugin_ops.h" + +#if 0 +#define DEBUG_REFINE +#endif + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_rate = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef struct _snd_pcm_rate snd_pcm_rate_t; + +struct _snd_pcm_rate { + snd_pcm_generic_t gen; + snd_atomic_write_t watom; + snd_pcm_uframes_t appl_ptr, hw_ptr; + snd_pcm_uframes_t last_commit_ptr; + snd_pcm_uframes_t orig_avail_min; + snd_pcm_sw_params_t sw_params; + snd_pcm_format_t sformat; + unsigned int srate; + snd_pcm_channel_area_t *pareas; /* areas for splitted period (rate pcm) */ + snd_pcm_channel_area_t *sareas; /* areas for splitted period (slave pcm) */ + snd_pcm_rate_info_t info; + void *open_func; + void *obj; + snd_pcm_rate_ops_t ops; + unsigned int get_idx; + unsigned int put_idx; + int16_t *src_buf; + int16_t *dst_buf; + int start_pending; /* start is triggered but not commited to slave */ + snd_htimestamp_t trigger_tstamp; + unsigned int plugin_version; + unsigned int rate_min, rate_max; +}; + +#define SND_PCM_RATE_PLUGIN_VERSION_OLD 0x010001 /* old rate plugin */ + +#endif /* DOC_HIDDEN */ + +static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + snd_pcm_rate_t *rate = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + if (rate->rate_min) { + err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, + rate->rate_min, 0); + if (err < 0) + return err; + } + if (rate->rate_max) { + err = _snd_pcm_hw_param_set_max(params, SND_PCM_HW_PARAM_RATE, + rate->rate_max, 0); + if (err < 0) + return err; + } + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + if (rate->sformat != SND_PCM_FORMAT_UNKNOWN) { + _snd_pcm_hw_params_set_format(sparams, rate->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + } + _snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE, + rate->srate, 0, rate->srate + 1, -1); + return 0; +} + +static int snd_pcm_rate_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_interval_t t, buffer_size; + const snd_interval_t *srate, *crate; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (rate->sformat == SND_PCM_FORMAT_UNKNOWN) + links |= (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS | + SND_PCM_HW_PARBIT_FRAME_BITS); + snd_interval_copy(&buffer_size, snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE)); + snd_interval_unfloor(&buffer_size); + crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE); + snd_interval_muldiv(&buffer_size, srate, crate, &t); + err = _snd_pcm_hw_param_set_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_interval_t t; +#ifdef DEBUG_REFINE + snd_output_t *out; +#endif + const snd_interval_t *sbuffer_size, *buffer_size; + const snd_interval_t *srate, *crate; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (rate->sformat == SND_PCM_FORMAT_UNKNOWN) + links |= (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS | + SND_PCM_HW_PARBIT_FRAME_BITS); + sbuffer_size = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); + crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE); + srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE); + snd_interval_muldiv(sbuffer_size, crate, srate, &t); + snd_interval_floor(&t); + err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); + if (err < 0) + return err; + buffer_size = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE); + /* + * this condition probably needs more work: + * in case when the buffer_size is known and we are looking + * for best period_size, we should prefer situation when + * (buffer_size / period_size) * period_size == buffer_size + */ + if (snd_interval_single(buffer_size) && buffer_size->integer) { + snd_interval_t *period_size; + period_size = (snd_interval_t *)snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE); + if (!snd_interval_checkempty(period_size) && + period_size->openmin && period_size->openmax && + period_size->min + 1 == period_size->max) { + if (period_size->min > 0 && (buffer_size->min / period_size->min) * period_size->min == buffer_size->min) { + snd_interval_set_value(period_size, period_size->min); + } else if ((buffer_size->max / period_size->max) * period_size->max == buffer_size->max) { + snd_interval_set_value(period_size, period_size->max); + } + } + } +#ifdef DEBUG_REFINE + snd_output_stdio_attach(&out, stderr, 0); + snd_output_printf(out, "REFINE (params):\n"); + snd_pcm_hw_params_dump(params, out); + snd_output_printf(out, "REFINE (slave params):\n"); + snd_pcm_hw_params_dump(sparams, out); + snd_output_close(out); +#endif + err = _snd_pcm_hw_params_refine(params, links, sparams); +#ifdef DEBUG_REFINE + snd_output_stdio_attach(&out, stderr, 0); + snd_output_printf(out, "********************\n"); + snd_output_printf(out, "REFINE (params) (%i):\n", err); + snd_pcm_hw_params_dump(params, out); + snd_output_printf(out, "REFINE (slave params):\n"); + snd_pcm_hw_params_dump(sparams, out); + snd_output_close(out); +#endif + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_rate_hw_refine_cprepare, + snd_pcm_rate_hw_refine_cchange, + snd_pcm_rate_hw_refine_sprepare, + snd_pcm_rate_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_t *slave = rate->gen.slave; + snd_pcm_rate_side_info_t *sinfo, *cinfo; + unsigned int channels, cwidth, swidth, chn; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_rate_hw_refine_cchange, + snd_pcm_rate_hw_refine_sprepare, + snd_pcm_rate_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + cinfo = &rate->info.in; + sinfo = &rate->info.out; + } else { + sinfo = &rate->info.in; + cinfo = &rate->info.out; + } + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &cinfo->format); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_rate)(params, &cinfo->rate, 0); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_period_size)(params, &cinfo->period_size, 0); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &cinfo->buffer_size); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_channels)(params, &channels); + if (err < 0) + return err; + + rate->info.channels = channels; + sinfo->format = slave->format; + sinfo->rate = slave->rate; + sinfo->buffer_size = slave->buffer_size; + sinfo->period_size = slave->period_size; + + if (CHECK_SANITY(rate->pareas)) { + SNDMSG("rate plugin already in use"); + return -EBUSY; + } + err = rate->ops.init(rate->obj, &rate->info); + if (err < 0) + return err; + + rate->pareas = malloc(2 * channels * sizeof(*rate->pareas)); + if (rate->pareas == NULL) + goto error; + + cwidth = snd_pcm_format_physical_width(cinfo->format); + swidth = snd_pcm_format_physical_width(sinfo->format); + rate->pareas[0].addr = malloc(((cwidth * channels * cinfo->period_size) / 8) + + ((swidth * channels * sinfo->period_size) / 8)); + if (rate->pareas[0].addr == NULL) + goto error; + + rate->sareas = rate->pareas + channels; + rate->sareas[0].addr = (char *)rate->pareas[0].addr + ((cwidth * channels * cinfo->period_size) / 8); + for (chn = 0; chn < channels; chn++) { + rate->pareas[chn].addr = rate->pareas[0].addr + (cwidth * chn * cinfo->period_size) / 8; + rate->pareas[chn].first = 0; + rate->pareas[chn].step = cwidth; + rate->sareas[chn].addr = rate->sareas[0].addr + (swidth * chn * sinfo->period_size) / 8; + rate->sareas[chn].first = 0; + rate->sareas[chn].step = swidth; + } + + if (rate->ops.convert_s16) { + rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S16); + rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, rate->info.out.format); + free(rate->src_buf); + rate->src_buf = malloc(channels * rate->info.in.period_size * 2); + free(rate->dst_buf); + rate->dst_buf = malloc(channels * rate->info.out.period_size * 2); + if (! rate->src_buf || ! rate->dst_buf) + goto error; + } + + return 0; + + error: + if (rate->pareas) { + free(rate->pareas[0].addr); + free(rate->pareas); + rate->pareas = NULL; + } + if (rate->ops.free) + rate->ops.free(rate->obj); + return -ENOMEM; +} + +static int snd_pcm_rate_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + if (rate->pareas) { + free(rate->pareas[0].addr); + free(rate->pareas); + rate->pareas = NULL; + rate->sareas = NULL; + } + if (rate->ops.free) + rate->ops.free(rate->obj); + free(rate->src_buf); + free(rate->dst_buf); + rate->src_buf = rate->dst_buf = NULL; + return snd_pcm_hw_free(rate->gen.slave); +} + +static void recalc(snd_pcm_t *pcm, snd_pcm_uframes_t *val) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_t *slave = rate->gen.slave; + unsigned long div; + + if (*val == pcm->buffer_size) { + *val = slave->buffer_size; + } else { + div = *val / pcm->period_size; + if (div * pcm->period_size == *val) + *val = div * slave->period_size; + else + *val = muldiv_near(*val, slave->period_size, pcm->period_size); + } +} + +static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_t *slave = rate->gen.slave; + snd_pcm_sw_params_t *sparams; + snd_pcm_uframes_t boundary1, boundary2, sboundary; + int err; + + sparams = &rate->sw_params; + err = snd_pcm_sw_params_current(slave, sparams); + if (err < 0) + return err; + sboundary = sparams->boundary; + *sparams = *params; + boundary1 = pcm->buffer_size; + boundary2 = slave->buffer_size; + while (boundary1 * 2 <= LONG_MAX - pcm->buffer_size && + boundary2 * 2 <= LONG_MAX - slave->buffer_size) { + boundary1 *= 2; + boundary2 *= 2; + } + params->boundary = boundary1; + sparams->boundary = sboundary; + + if (rate->ops.adjust_pitch) + rate->ops.adjust_pitch(rate->obj, &rate->info); + + recalc(pcm, &sparams->avail_min); + rate->orig_avail_min = sparams->avail_min; + recalc(pcm, &sparams->start_threshold); + if (sparams->avail_min < 1) sparams->avail_min = 1; + if (sparams->start_threshold <= slave->buffer_size) { + if (sparams->start_threshold > (slave->buffer_size / sparams->avail_min) * sparams->avail_min) + sparams->start_threshold = (slave->buffer_size / sparams->avail_min) * sparams->avail_min; + } + if (sparams->stop_threshold >= params->boundary) { + sparams->stop_threshold = sparams->boundary; + } else { + recalc(pcm, &sparams->stop_threshold); + } + recalc(pcm, &sparams->silence_threshold); + if (sparams->silence_size >= params->boundary) { + sparams->silence_size = sparams->boundary; + } else { + recalc(pcm, &sparams->silence_size); + } + return snd_pcm_sw_params(slave, sparams); +} + +static int snd_pcm_rate_init(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + + if (rate->ops.reset) + rate->ops.reset(rate->obj); + rate->last_commit_ptr = 0; + rate->start_pending = 0; + return 0; +} + +static void convert_to_s16(snd_pcm_rate_t *rate, int16_t *buf, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, unsigned int frames, + unsigned int channels) +{ +#ifndef DOC_HIDDEN +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS +#endif /* DOC_HIDDEN */ + void *get = get16_labels[rate->get_idx]; + const char *src; + int16_t sample; + const char *srcs[channels]; + int src_step[channels]; + unsigned int c; + + for (c = 0; c < channels; c++) { + srcs[c] = snd_pcm_channel_area_addr(areas + c, offset); + src_step[c] = snd_pcm_channel_area_step(areas + c); + } + + while (frames--) { + for (c = 0; c < channels; c++) { + src = srcs[c]; + goto *get; +#ifndef DOC_HIDDEN +#define GET16_END after_get +#include "plugin_ops.h" +#undef GET16_END +#endif /* DOC_HIDDEN */ + after_get: + *buf++ = sample; + srcs[c] += src_step[c]; + } + } +} + +static void convert_from_s16(snd_pcm_rate_t *rate, const int16_t *buf, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, unsigned int frames, + unsigned int channels) +{ +#ifndef DOC_HIDDEN +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS +#endif /* DOC_HIDDEN */ + void *put = put16_labels[rate->put_idx]; + char *dst; + int16_t sample; + char *dsts[channels]; + int dst_step[channels]; + unsigned int c; + + for (c = 0; c < channels; c++) { + dsts[c] = snd_pcm_channel_area_addr(areas + c, offset); + dst_step[c] = snd_pcm_channel_area_step(areas + c); + } + + while (frames--) { + for (c = 0; c < channels; c++) { + dst = dsts[c]; + sample = *buf++; + goto *put; +#ifndef DOC_HIDDEN +#define PUT16_END after_put +#include "plugin_ops.h" +#undef PUT16_END +#endif /* DOC_HIDDEN */ + after_put: + dsts[c] += dst_step[c]; + } + } +} + +static void do_convert(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames, + unsigned int channels, + snd_pcm_rate_t *rate) +{ + if (rate->ops.convert_s16) { + const int16_t *src; + int16_t *dst; + if (! rate->src_buf) + src = src_areas->addr + src_offset * 2 * channels; + else { + convert_to_s16(rate, rate->src_buf, src_areas, src_offset, + src_frames, channels); + src = rate->src_buf; + } + if (! rate->dst_buf) + dst = dst_areas->addr + dst_offset * 2 * channels; + else + dst = rate->dst_buf; + rate->ops.convert_s16(rate->obj, dst, dst_frames, src, src_frames); + if (dst == rate->dst_buf) + convert_from_s16(rate, rate->dst_buf, dst_areas, dst_offset, + dst_frames, channels); + } else { + rate->ops.convert(rate->obj, dst_areas, dst_offset, dst_frames, + src_areas, src_offset, src_frames); + } +} + +static inline void +snd_pcm_rate_write_areas1(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset) +{ + snd_pcm_rate_t *rate = pcm->private_data; + do_convert(slave_areas, slave_offset, rate->gen.slave->period_size, + areas, offset, pcm->period_size, + pcm->channels, rate); +} + +static inline void +snd_pcm_rate_read_areas1(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset) +{ + snd_pcm_rate_t *rate = pcm->private_data; + do_convert(areas, offset, pcm->period_size, + slave_areas, slave_offset, rate->gen.slave->period_size, + pcm->channels, rate); +} + +static inline snd_pcm_sframes_t snd_pcm_rate_move_applptr(snd_pcm_t *pcm, snd_pcm_sframes_t frames) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_uframes_t orig_appl_ptr, appl_ptr = rate->appl_ptr, slave_appl_ptr; + snd_pcm_sframes_t diff, ndiff; + snd_pcm_t *slave = rate->gen.slave; + + orig_appl_ptr = rate->appl_ptr; + if (frames > 0) + snd_pcm_mmap_appl_forward(pcm, frames); + else + snd_pcm_mmap_appl_backward(pcm, -frames); + slave_appl_ptr = + (appl_ptr / pcm->period_size) * rate->gen.slave->period_size; + diff = slave_appl_ptr - *slave->appl.ptr; + if (diff < -(snd_pcm_sframes_t)(slave->boundary / 2)) { + diff = (slave->boundary - *slave->appl.ptr) + slave_appl_ptr; + } else if (diff > (snd_pcm_sframes_t)(slave->boundary / 2)) { + diff = -((slave->boundary - slave_appl_ptr) + *slave->appl.ptr); + } + if (diff == 0) + return frames; + if (diff > 0) { + ndiff = snd_pcm_forward(rate->gen.slave, diff); + } else { + ndiff = snd_pcm_rewind(rate->gen.slave, diff); + } + if (ndiff < 0) + return diff; + slave_appl_ptr = *slave->appl.ptr; + rate->appl_ptr = + (slave_appl_ptr / rate->gen.slave->period_size) * pcm->period_size + + orig_appl_ptr % pcm->period_size; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + rate->appl_ptr += rate->ops.input_frames(rate->obj, slave_appl_ptr % rate->gen.slave->period_size); + else + rate->appl_ptr += rate->ops.output_frames(rate->obj, slave_appl_ptr % rate->gen.slave->period_size); + + diff = orig_appl_ptr - rate->appl_ptr; + if (diff < -(snd_pcm_sframes_t)(slave->boundary / 2)) { + diff = (slave->boundary - rate->appl_ptr) + orig_appl_ptr; + } else if (diff > (snd_pcm_sframes_t)(slave->boundary / 2)) { + diff = -((slave->boundary - orig_appl_ptr) + rate->appl_ptr); + } + if (frames < 0) + diff = -diff; + + rate->last_commit_ptr = rate->appl_ptr - rate->appl_ptr % pcm->period_size; + + return diff; +} + +static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr = *rate->gen.slave->hw.ptr; + + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return; + /* FIXME: boundary overlap of slave hw_ptr isn't evaluated here! + * e.g. if slave rate is small... + */ + rate->hw_ptr = + (slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size + + rate->ops.input_frames(rate->obj, slave_hw_ptr % rate->gen.slave->period_size); +} + +static int snd_pcm_rate_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + int err = snd_pcm_hwsync(rate->gen.slave); + if (err < 0) + return err; + snd_atomic_write_begin(&rate->watom); + snd_pcm_rate_sync_hwptr(pcm); + snd_atomic_write_end(&rate->watom); + return 0; +} + +static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_rate_hwsync(pcm); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + *delayp = snd_pcm_mmap_playback_hw_avail(pcm); + else + *delayp = snd_pcm_mmap_capture_hw_avail(pcm); + return 0; +} + +static int snd_pcm_rate_prepare(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + int err; + + snd_atomic_write_begin(&rate->watom); + err = snd_pcm_prepare(rate->gen.slave); + if (err < 0) { + snd_atomic_write_end(&rate->watom); + return err; + } + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + snd_atomic_write_end(&rate->watom); + err = snd_pcm_rate_init(pcm); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_rate_reset(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + int err; + snd_atomic_write_begin(&rate->watom); + err = snd_pcm_reset(rate->gen.slave); + if (err < 0) { + snd_atomic_write_end(&rate->watom); + return err; + } + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + snd_atomic_write_end(&rate->watom); + err = snd_pcm_rate_init(pcm); + if (err < 0) + return err; + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm); + + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (frames == 0) + return 0; + + snd_atomic_write_begin(&rate->watom); + n = snd_pcm_rate_move_applptr(pcm, -frames); + snd_atomic_write_end(&rate->watom); + return n; +} + +static snd_pcm_sframes_t snd_pcm_rate_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm); + + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (frames == 0) + return 0; + + snd_atomic_write_begin(&rate->watom); + n = snd_pcm_rate_move_applptr(pcm, frames); + snd_atomic_write_end(&rate->watom); + return n; +} + +static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate, + snd_pcm_uframes_t appl_offset, + snd_pcm_uframes_t size, + snd_pcm_uframes_t slave_size) +{ + snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset; + const snd_pcm_channel_area_t *areas; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset, xfer; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + + areas = snd_pcm_mmap_areas(pcm); + if (cont >= size) { + result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) + return result; + if (slave_frames < slave_size) { + snd_pcm_rate_write_areas1(pcm, areas, appl_offset, rate->sareas, 0); + goto __partial; + } + snd_pcm_rate_write_areas1(pcm, areas, appl_offset, + slave_areas, slave_offset); + result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, slave_size); + if (result < (snd_pcm_sframes_t)slave_size) { + if (result < 0) + return result; + result = snd_pcm_rewind(rate->gen.slave, result); + if (result < 0) + return result; + return 0; + } + } else { + snd_pcm_areas_copy(rate->pareas, 0, + areas, appl_offset, + pcm->channels, cont, + pcm->format); + snd_pcm_areas_copy(rate->pareas, cont, + areas, 0, + pcm->channels, size - cont, + pcm->format); + + snd_pcm_rate_write_areas1(pcm, rate->pareas, 0, rate->sareas, 0); + + /* ok, commit first fragment */ + result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) + return result; + __partial: + xfer = 0; + cont = slave_frames; + if (cont > slave_size) + cont = slave_size; + snd_pcm_areas_copy(slave_areas, slave_offset, + rate->sareas, 0, + pcm->channels, cont, + rate->gen.slave->format); + result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); + if (result < (snd_pcm_sframes_t)cont) { + if (result < 0) + return result; + result = snd_pcm_rewind(rate->gen.slave, result); + if (result < 0) + return result; + return 0; + } + xfer = cont; + + if (xfer == slave_size) + goto commit_done; + + /* commit second fragment */ + cont = slave_size - cont; + slave_frames = cont; + result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) + return result; +#if 0 + if (slave_offset) { + SNDERR("non-zero slave_offset %ld", slave_offset); + return -EIO; + } +#endif + snd_pcm_areas_copy(slave_areas, slave_offset, + rate->sareas, xfer, + pcm->channels, cont, + rate->gen.slave->format); + result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); + if (result < (snd_pcm_sframes_t)cont) { + if (result < 0) + return result; + result = snd_pcm_rewind(rate->gen.slave, result + xfer); + if (result < 0) + return result; + return 0; + } + } + + commit_done: + if (rate->start_pending) { + /* we have pending start-trigger. let's issue it now */ + snd_pcm_start(rate->gen.slave); + rate->start_pending = 0; + } + return 1; +} + +static int snd_pcm_rate_commit_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t appl_offset) +{ + snd_pcm_rate_t *rate = pcm->private_data; + + return snd_pcm_rate_commit_area(pcm, rate, appl_offset, pcm->period_size, + rate->gen.slave->period_size); +} + +static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_offset) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; + const snd_pcm_channel_area_t *areas; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset, xfer; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + + areas = snd_pcm_mmap_areas(pcm); + if (cont >= pcm->period_size) { + result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) + return result; + if (slave_frames < rate->gen.slave->period_size) + goto __partial; + snd_pcm_rate_read_areas1(pcm, areas, hw_offset, + slave_areas, slave_offset); + result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, rate->gen.slave->period_size); + if (result < (snd_pcm_sframes_t)rate->gen.slave->period_size) { + if (result < 0) + return result; + result = snd_pcm_rewind(rate->gen.slave, result); + if (result < 0) + return result; + return 0; + } + } else { + /* ok, grab first fragment */ + result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) + return result; + __partial: + xfer = 0; + cont = slave_frames; + if (cont > rate->gen.slave->period_size) + cont = rate->gen.slave->period_size; + snd_pcm_areas_copy(rate->sareas, 0, + slave_areas, slave_offset, + pcm->channels, cont, + rate->gen.slave->format); + result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); + if (result < (snd_pcm_sframes_t)cont) { + if (result < 0) + return result; + result = snd_pcm_rewind(rate->gen.slave, result); + if (result < 0) + return result; + return 0; + } + xfer = cont; + + if (xfer == rate->gen.slave->period_size) + goto __transfer; + + /* grab second fragment */ + cont = rate->gen.slave->period_size - cont; + slave_frames = cont; + result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) + return result; +#if 0 + if (slave_offset) { + SNDERR("non-zero slave_offset %ld", slave_offset); + return -EIO; + } +#endif + snd_pcm_areas_copy(rate->sareas, xfer, + slave_areas, slave_offset, + pcm->channels, cont, + rate->gen.slave->format); + result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); + if (result < (snd_pcm_sframes_t)cont) { + if (result < 0) + return result; + result = snd_pcm_rewind(rate->gen.slave, result + xfer); + if (result < 0) + return result; + return 0; + } + + __transfer: + cont = pcm->buffer_size - hw_offset; + if (cont >= pcm->period_size) { + snd_pcm_rate_read_areas1(pcm, areas, hw_offset, + rate->sareas, 0); + } else { + snd_pcm_rate_read_areas1(pcm, + rate->pareas, 0, + rate->sareas, 0); + snd_pcm_areas_copy(areas, hw_offset, + rate->pareas, 0, + pcm->channels, cont, + pcm->format); + snd_pcm_areas_copy(areas, 0, + rate->pareas, cont, + pcm->channels, pcm->period_size - cont, + pcm->format); + } + } + return 1; +} + +static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t appl_ptr) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_t *slave = rate->gen.slave; + snd_pcm_uframes_t xfer; + snd_pcm_sframes_t slave_size; + int err; + + slave_size = snd_pcm_avail_update(slave); + if (slave_size < 0) + return slave_size; + + if (appl_ptr < rate->last_commit_ptr) + xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary; + else + xfer = appl_ptr - rate->last_commit_ptr; + while (xfer >= pcm->period_size && + (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { + err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size); + if (err == 0) + break; + if (err < 0) + return err; + xfer -= pcm->period_size; + slave_size -= rate->gen.slave->period_size; + rate->last_commit_ptr += pcm->period_size; + if (rate->last_commit_ptr >= pcm->boundary) + rate->last_commit_ptr = 0; + } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_rate_t *rate = pcm->private_data; + int err; + + if (size == 0) + return 0; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + err = snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr + size); + if (err < 0) + return err; + } + snd_atomic_write_begin(&rate->watom); + snd_pcm_mmap_appl_forward(pcm, size); + snd_atomic_write_end(&rate->watom); + return size; +} + +static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_t *slave = rate->gen.slave; + snd_pcm_uframes_t slave_size; + + slave_size = snd_pcm_avail_update(slave); + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + goto _capture; + snd_atomic_write_begin(&rate->watom); + snd_pcm_rate_sync_hwptr(pcm); + snd_atomic_write_end(&rate->watom); + snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); + return snd_pcm_mmap_avail(pcm); + _capture: { + snd_pcm_uframes_t xfer, hw_offset, size; + + xfer = snd_pcm_mmap_capture_avail(pcm); + size = pcm->buffer_size - xfer; + hw_offset = snd_pcm_mmap_hw_offset(pcm); + while (size >= pcm->period_size && + slave_size >= rate->gen.slave->period_size) { + int err = snd_pcm_rate_grab_next_period(pcm, hw_offset); + if (err < 0) + return err; + if (err == 0) + return (snd_pcm_sframes_t)xfer; + xfer += pcm->period_size; + size -= pcm->period_size; + slave_size -= rate->gen.slave->period_size; + hw_offset += pcm->period_size; + hw_offset %= pcm->buffer_size; + snd_pcm_mmap_hw_forward(pcm, pcm->period_size); + } + return (snd_pcm_sframes_t)xfer; + } +} + +static int snd_pcm_rate_htimestamp(snd_pcm_t *pcm, + snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_sframes_t avail1; + snd_pcm_uframes_t tmp; + int ok = 0, err; + + while (1) { + /* the position is from this plugin itself */ + avail1 = snd_pcm_avail_update(pcm); + if (avail1 < 0) + return avail1; + if (ok && (snd_pcm_uframes_t)avail1 == *avail) + break; + *avail = avail1; + /* timestamp is taken from the slave PCM */ + err = snd_pcm_htimestamp(rate->gen.slave, &tmp, tstamp); + if (err < 0) + return err; + ok = 1; + } + return 0; +} + +static int snd_pcm_rate_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_rate_t *rate = pcm->private_data; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + /* Try to sync as much as possible */ + snd_pcm_rate_hwsync(pcm); + snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); + } + return snd_pcm_poll_descriptors_revents(rate->gen.slave, pfds, nfds, revents); +} + +static int snd_pcm_rate_drain(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + /* commit the remaining fraction (if any) */ + snd_pcm_uframes_t size, ofs, saved_avail_min; + snd_pcm_sw_params_t sw_params; + + /* temporarily set avail_min to one */ + sw_params = rate->sw_params; + saved_avail_min = sw_params.avail_min; + sw_params.avail_min = 1; + snd_pcm_sw_params(rate->gen.slave, &sw_params); + + size = rate->appl_ptr - rate->last_commit_ptr; + ofs = rate->last_commit_ptr % pcm->buffer_size; + while (size > 0) { + snd_pcm_uframes_t psize, spsize; + + if (snd_pcm_wait(rate->gen.slave, -1) < 0) + break; + if (size > pcm->period_size) { + psize = pcm->period_size; + spsize = rate->gen.slave->period_size; + } else { + psize = size; + spsize = rate->ops.output_frames(rate->obj, size); + if (! spsize) + break; + } + snd_pcm_rate_commit_area(pcm, rate, ofs, + psize, spsize); + ofs = (ofs + psize) % pcm->buffer_size; + size -= psize; + } + sw_params.avail_min = saved_avail_min; + snd_pcm_sw_params(rate->gen.slave, &sw_params); + } + return snd_pcm_drain(rate->gen.slave); +} + +static snd_pcm_state_t snd_pcm_rate_state(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + if (rate->start_pending) /* pseudo-state */ + return SND_PCM_STATE_RUNNING; + return snd_pcm_state(rate->gen.slave); +} + + +static int snd_pcm_rate_start(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_uframes_t avail; + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + return snd_pcm_start(rate->gen.slave); + + if (snd_pcm_state(rate->gen.slave) != SND_PCM_STATE_PREPARED) + return -EBADFD; + + gettimestamp(&rate->trigger_tstamp, pcm->monotonic); + + avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave); + if (avail == 0) { + /* postpone the trigger since we have no data committed yet */ + rate->start_pending = 1; + return 0; + } + rate->start_pending = 0; + return snd_pcm_start(rate->gen.slave); +} + +static int snd_pcm_rate_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_sframes_t err; + snd_atomic_read_t ratom; + snd_atomic_read_init(&ratom, &rate->watom); + _again: + snd_atomic_read_begin(&ratom); + err = snd_pcm_status(rate->gen.slave, status); + if (err < 0) { + snd_atomic_read_ok(&ratom); + return err; + } + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (rate->start_pending) + status->state = SND_PCM_STATE_RUNNING; + status->trigger_tstamp = rate->trigger_tstamp; + } + snd_pcm_rate_sync_hwptr(pcm); + status->appl_ptr = *pcm->appl.ptr; + status->hw_ptr = *pcm->hw.ptr; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + status->delay = snd_pcm_mmap_playback_hw_avail(pcm); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max); + } else { + status->delay = snd_pcm_mmap_capture_hw_avail(pcm); + status->avail = snd_pcm_mmap_capture_avail(pcm); + status->avail_max = rate->ops.output_frames(rate->obj, status->avail_max); + } + if (!snd_atomic_read_ok(&ratom)) { + snd_atomic_read_wait(&ratom); + goto _again; + } + return 0; +} + +static void snd_pcm_rate_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_rate_t *rate = pcm->private_data; + if (rate->sformat == SND_PCM_FORMAT_UNKNOWN) + snd_output_printf(out, "Rate conversion PCM (%d)\n", + rate->srate); + else + snd_output_printf(out, "Rate conversion PCM (%d, sformat=%s)\n", + rate->srate, + snd_pcm_format_name(rate->sformat)); + if (rate->ops.dump) + rate->ops.dump(rate->obj, out); + snd_output_printf(out, "Protocol version: %x\n", rate->plugin_version); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(rate->gen.slave, out); +} + +static int snd_pcm_rate_close(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + + if (rate->ops.close) + rate->ops.close(rate->obj); + if (rate->open_func) + snd_dlobj_cache_put(rate->open_func); + return snd_pcm_generic_close(pcm); +} + +static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = { + .status = snd_pcm_rate_status, + .state = snd_pcm_rate_state, + .hwsync = snd_pcm_rate_hwsync, + .delay = snd_pcm_rate_delay, + .prepare = snd_pcm_rate_prepare, + .reset = snd_pcm_rate_reset, + .start = snd_pcm_rate_start, + .drop = snd_pcm_generic_drop, + .drain = snd_pcm_rate_drain, + .pause = snd_pcm_generic_pause, + .rewind = snd_pcm_rate_rewind, + .forward = snd_pcm_rate_forward, + .resume = snd_pcm_generic_resume, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_mmap_readi, + .readn = snd_pcm_mmap_readn, + .avail_update = snd_pcm_rate_avail_update, + .mmap_commit = snd_pcm_rate_mmap_commit, + .htimestamp = snd_pcm_rate_htimestamp, + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_rate_poll_revents, +}; + +static const snd_pcm_ops_t snd_pcm_rate_ops = { + .close = snd_pcm_rate_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_rate_hw_refine, + .hw_params = snd_pcm_rate_hw_params, + .hw_free = snd_pcm_rate_hw_free, + .sw_params = snd_pcm_rate_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_rate_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Get a default converter string + * \param root Root configuration node + * \retval A const config item if found, or NULL + */ +const snd_config_t *snd_pcm_rate_get_default_converter(snd_config_t *root) +{ + snd_config_t *n; + /* look for default definition */ + if (snd_config_search(root, "defaults.pcm.rate_converter", &n) >= 0) + return n; + return NULL; +} + +#ifdef PIC +static int is_builtin_plugin(const char *type) +{ + return strcmp(type, "linear") == 0; +} + +static const char *const default_rate_plugins[] = { + "speexrate", "linear", NULL +}; + +static int rate_open_func(snd_pcm_rate_t *rate, const char *type, int verbose) +{ + char open_name[64], lib_name[128], *lib = NULL; + snd_pcm_rate_open_func_t open_func; + int err; + + snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type); + if (!is_builtin_plugin(type)) { + snprintf(lib_name, sizeof(lib_name), + "%s/libasound_module_rate_%s.so", ALSA_PLUGIN_DIR, type); + lib = lib_name; + } + open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose); + if (!open_func) + return -ENOENT; + + rate->open_func = open_func; + rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; + rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; + rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; + + err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); + if (!err) { + rate->plugin_version = rate->ops.version; + if (rate->ops.get_supported_rates) + rate->ops.get_supported_rates(rate->obj, + &rate->rate_min, + &rate->rate_max); + return 0; + } + + /* try to open with the old protocol version */ + rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION_OLD; + err = open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD, + &rate->obj, &rate->ops); + if (err) { + snd_dlobj_cache_put(open_func); + rate->open_func = NULL; + } + return err; +} +#endif + +/** + * \brief Creates a new rate PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave format + * \param srate Slave rate + * \param converter SRC type string node + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, unsigned int srate, + const snd_config_t *converter, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_rate_t *rate; + const char *type = NULL; + int err; +#ifndef PIC + snd_pcm_rate_open_func_t open_func; + extern int SND_PCM_RATE_PLUGIN_ENTRY(linear) (unsigned int version, void **objp, snd_pcm_rate_ops_t *ops); +#endif + + assert(pcmp && slave); + if (sformat != SND_PCM_FORMAT_UNKNOWN && + snd_pcm_format_linear(sformat) != 1) + return -EINVAL; + rate = calloc(1, sizeof(snd_pcm_rate_t)); + if (!rate) { + return -ENOMEM; + } + rate->gen.slave = slave; + rate->gen.close_slave = close_slave; + rate->srate = srate; + rate->sformat = sformat; + snd_atomic_write_init(&rate->watom); + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_RATE, name, slave->stream, slave->mode); + if (err < 0) { + free(rate); + return err; + } + +#ifdef PIC + err = -ENOENT; + if (!converter) { + const char *const *types; + for (types = default_rate_plugins; *types; types++) { + err = rate_open_func(rate, *types, 0); + if (!err) { + type = *types; + break; + } + } + } else if (!snd_config_get_string(converter, &type)) + err = rate_open_func(rate, type, 1); + else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) { + snd_config_iterator_t i, next; + snd_config_for_each(i, next, converter) { + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &type) < 0) + break; + err = rate_open_func(rate, type, 0); + if (!err) + break; + } + } else { + SNDERR("Invalid type for rate converter"); + snd_pcm_close(pcm); + return -EINVAL; + } + if (err < 0) { + SNDERR("Cannot find rate converter"); + snd_pcm_close(pcm); + return -ENOENT; + } +#else + type = "linear"; + open_func = SND_PCM_RATE_PLUGIN_ENTRY(linear); + err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); + if (err < 0) { + snd_pcm_close(pcm); + return err; + } +#endif + + if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16) || + ! rate->ops.input_frames || ! rate->ops.output_frames) { + SNDERR("Inproper rate plugin %s initialization", type); + snd_pcm_close(pcm); + return err; + } + + pcm->ops = &snd_pcm_rate_ops; + pcm->fast_ops = &snd_pcm_rate_fast_ops; + pcm->private_data = rate; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_rw = 1; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &rate->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &rate->appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_rate Plugin: Rate + +This plugin converts a stream rate. The input and output formats must be linear. + +\code +pcm.name { + type rate # Rate PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + rate INT # Slave rate + [format STR] # Slave format + } + converter STR # optional + # or + converter [ STR1 STR2 ... ] # optional + # Converter type, default is taken from + # defaults.pcm.rate_converter +} +\endcode + +\subsection pcm_plugins_rate_funcref Function reference + +
    +
  • snd_pcm_rate_open() +
  • _snd_pcm_rate_open() +
+ +*/ + +/** + * \brief Creates a new rate PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with rate PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; + int srate = -1; + const snd_config_t *converter = NULL; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "converter") == 0) { + converter = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + + err = snd_pcm_slave_conf(root, slave, &sconf, 2, + SND_PCM_HW_PARAM_FORMAT, 0, &sformat, + SND_PCM_HW_PARAM_RATE, SCONF_MANDATORY, &srate); + if (err < 0) + return err; + if (sformat != SND_PCM_FORMAT_UNKNOWN && + snd_pcm_format_linear(sformat) != 1) { + snd_config_delete(sconf); + SNDERR("slave format is not linear"); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + err = snd_pcm_rate_open(pcmp, name, sformat, (unsigned int) srate, + converter, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_rate_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_rate_linear.c b/src/pcm/pcm_rate_linear.c new file mode 100644 index 0000000..7481b38 --- /dev/null +++ b/src/pcm/pcm_rate_linear.c @@ -0,0 +1,447 @@ +/* + * Linear rate converter plugin + * + * Copyright (c) 2000 by Abramo Bagnara + * 2004 by Jaroslav Kysela + * 2006 by Takashi Iwai + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" +#include "pcm_rate.h" + +#include "plugin_ops.h" + + +/* LINEAR_DIV needs to be large enough to handle resampling from 192000 -> 8000 */ +#define LINEAR_DIV_SHIFT 19 +#define LINEAR_DIV (1<pitch); +} + +static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames) +{ + struct rate_linear *rate = obj; + if (frames == 0) + return 0; + /* Round toward zero */ + return muldiv_near(frames, rate->pitch, LINEAR_DIV); +} + +static void linear_expand(struct rate_linear *rate, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames) +{ +#define GET16_LABELS +#define PUT16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS +#undef PUT16_LABELS + void *get = get16_labels[rate->get_idx]; + void *put = put16_labels[rate->put_idx]; + unsigned int get_threshold = rate->pitch; + unsigned int channel; + unsigned int src_frames1; + unsigned int dst_frames1; + int16_t sample = 0; + unsigned int pos; + + for (channel = 0; channel < rate->channels; ++channel) { + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + const char *src; + char *dst; + int src_step, dst_step; + int16_t old_sample = 0; + int16_t new_sample; + int old_weight, new_weight; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + src_frames1 = 0; + dst_frames1 = 0; + new_sample = rate->old_sample[channel]; + pos = get_threshold; + while (dst_frames1 < dst_frames) { + if (pos >= get_threshold) { + pos -= get_threshold; + old_sample = new_sample; + if (src_frames1 < src_frames) { + goto *get; +#define GET16_END after_get +#include "plugin_ops.h" +#undef GET16_END + after_get: + new_sample = sample; + } + } + new_weight = (pos << (16 - rate->pitch_shift)) / (get_threshold >> rate->pitch_shift); + old_weight = 0x10000 - new_weight; + sample = (old_sample * old_weight + new_sample * new_weight) >> 16; + goto *put; +#define PUT16_END after_put +#include "plugin_ops.h" +#undef PUT16_END + after_put: + dst += dst_step; + dst_frames1++; + pos += LINEAR_DIV; + if (pos >= get_threshold) { + src += src_step; + src_frames1++; + } + } + rate->old_sample[channel] = new_sample; + } +} + +/* optimized version for S16 format */ +static void linear_expand_s16(struct rate_linear *rate, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames) +{ + unsigned int channel; + unsigned int src_frames1; + unsigned int dst_frames1; + unsigned int get_threshold = rate->pitch; + unsigned int pos; + + for (channel = 0; channel < rate->channels; ++channel) { + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + const int16_t *src; + int16_t *dst; + int src_step, dst_step; + int16_t old_sample = 0; + int16_t new_sample; + int old_weight, new_weight; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area) >> 1; + dst_step = snd_pcm_channel_area_step(dst_area) >> 1; + src_frames1 = 0; + dst_frames1 = 0; + new_sample = rate->old_sample[channel]; + pos = get_threshold; + while (dst_frames1 < dst_frames) { + if (pos >= get_threshold) { + pos -= get_threshold; + old_sample = new_sample; + if (src_frames1 < src_frames) + new_sample = *src; + } + new_weight = (pos << (16 - rate->pitch_shift)) / (get_threshold >> rate->pitch_shift); + old_weight = 0x10000 - new_weight; + *dst = (old_sample * old_weight + new_sample * new_weight) >> 16; + dst += dst_step; + dst_frames1++; + pos += LINEAR_DIV; + if (pos >= get_threshold) { + src += src_step; + src_frames1++; + } + } + rate->old_sample[channel] = new_sample; + } +} + +static void linear_shrink(struct rate_linear *rate, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames) +{ +#define GET16_LABELS +#define PUT16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS +#undef PUT16_LABELS + void *get = get16_labels[rate->get_idx]; + void *put = put16_labels[rate->put_idx]; + unsigned int get_increment = rate->pitch; + unsigned int channel; + unsigned int src_frames1; + unsigned int dst_frames1; + int16_t sample = 0; + unsigned int pos; + + for (channel = 0; channel < rate->channels; ++channel) { + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + const char *src; + char *dst; + int src_step, dst_step; + int16_t old_sample = 0; + int16_t new_sample = 0; + int old_weight, new_weight; + pos = LINEAR_DIV - get_increment; /* Force first sample to be copied */ + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + src_frames1 = 0; + dst_frames1 = 0; + while (src_frames1 < src_frames) { + + goto *get; +#define GET16_END after_get +#include "plugin_ops.h" +#undef GET16_END + after_get: + new_sample = sample; + src += src_step; + src_frames1++; + pos += get_increment; + if (pos >= LINEAR_DIV) { + pos -= LINEAR_DIV; + old_weight = (pos << (32 - LINEAR_DIV_SHIFT)) / (get_increment >> (LINEAR_DIV_SHIFT - 16)); + new_weight = 0x10000 - old_weight; + sample = (old_sample * old_weight + new_sample * new_weight) >> 16; + goto *put; +#define PUT16_END after_put +#include "plugin_ops.h" +#undef PUT16_END + after_put: + dst += dst_step; + dst_frames1++; + if (CHECK_SANITY(dst_frames1 > dst_frames)) { + SNDERR("dst_frames overflow"); + break; + } + } + old_sample = new_sample; + } + } +} + +/* optimized version for S16 format */ +static void linear_shrink_s16(struct rate_linear *rate, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames) +{ + unsigned int get_increment = rate->pitch; + unsigned int channel; + unsigned int src_frames1; + unsigned int dst_frames1; + unsigned int pos = 0; + + for (channel = 0; channel < rate->channels; ++channel) { + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + const int16_t *src; + int16_t *dst; + int src_step, dst_step; + int16_t old_sample = 0; + int16_t new_sample = 0; + int old_weight, new_weight; + pos = LINEAR_DIV - get_increment; /* Force first sample to be copied */ + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area) >> 1; + dst_step = snd_pcm_channel_area_step(dst_area) >> 1 ; + src_frames1 = 0; + dst_frames1 = 0; + while (src_frames1 < src_frames) { + + new_sample = *src; + src += src_step; + src_frames1++; + pos += get_increment; + if (pos >= LINEAR_DIV) { + pos -= LINEAR_DIV; + old_weight = (pos << (32 - LINEAR_DIV_SHIFT)) / (get_increment >> (LINEAR_DIV_SHIFT - 16)); + new_weight = 0x10000 - old_weight; + *dst = (old_sample * old_weight + new_sample * new_weight) >> 16; + dst += dst_step; + dst_frames1++; + if (CHECK_SANITY(dst_frames1 > dst_frames)) { + SNDERR("dst_frames overflow"); + break; + } + } + old_sample = new_sample; + } + } +} + +static void linear_convert(void *obj, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames) +{ + struct rate_linear *rate = obj; + rate->func(rate, dst_areas, dst_offset, dst_frames, + src_areas, src_offset, src_frames); +} + +static void linear_free(void *obj) +{ + struct rate_linear *rate = obj; + + free(rate->old_sample); + rate->old_sample = NULL; +} + +static int linear_init(void *obj, snd_pcm_rate_info_t *info) +{ + struct rate_linear *rate = obj; + + rate->get_idx = snd_pcm_linear_get_index(info->in.format, SND_PCM_FORMAT_S16); + rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, info->out.format); + if (info->in.rate < info->out.rate) { + if (info->in.format == info->out.format && info->in.format == SND_PCM_FORMAT_S16) + rate->func = linear_expand_s16; + else + rate->func = linear_expand; + /* pitch is get_threshold */ + } else { + if (info->in.format == info->out.format && info->in.format == SND_PCM_FORMAT_S16) + rate->func = linear_shrink_s16; + else + rate->func = linear_shrink; + /* pitch is get_increment */ + } + rate->pitch = (((u_int64_t)info->out.rate * LINEAR_DIV) + + (info->in.rate / 2)) / info->in.rate; + rate->channels = info->channels; + + free(rate->old_sample); + rate->old_sample = malloc(sizeof(*rate->old_sample) * rate->channels); + if (! rate->old_sample) + return -ENOMEM; + + return 0; +} + +static int linear_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) +{ + struct rate_linear *rate = obj; + snd_pcm_uframes_t cframes; + + rate->pitch = (((u_int64_t)info->out.period_size * LINEAR_DIV) + + (info->in.period_size/2) ) / info->in.period_size; + + cframes = input_frames(rate, info->out.period_size); + while (cframes != info->in.period_size) { + snd_pcm_uframes_t cframes_new; + if (cframes > info->in.period_size) + rate->pitch++; + else + rate->pitch--; + cframes_new = input_frames(rate, info->out.period_size); + if ((cframes > info->in.period_size && cframes_new < info->in.period_size) || + (cframes < info->in.period_size && cframes_new > info->in.period_size)) { + SNDERR("invalid pcm period_size %ld -> %ld", + info->in.period_size, info->out.period_size); + return -EIO; + } + cframes = cframes_new; + } + if (rate->pitch >= LINEAR_DIV) { + /* shift for expand linear interpolation */ + rate->pitch_shift = 0; + while ((rate->pitch >> rate->pitch_shift) >= (1 << 16)) + rate->pitch_shift++; + } + return 0; +} + +static void linear_reset(void *obj) +{ + struct rate_linear *rate = obj; + + /* for expand */ + if (rate->old_sample) + memset(rate->old_sample, 0, sizeof(*rate->old_sample) * rate->channels); +} + +static void linear_close(void *obj) +{ + free(obj); +} + +static int get_supported_rates(ATTRIBUTE_UNUSED void *rate, + unsigned int *rate_min, unsigned int *rate_max) +{ + *rate_min = SND_PCM_PLUGIN_RATE_MIN; + *rate_max = SND_PCM_PLUGIN_RATE_MAX; + return 0; +} + +static void linear_dump(ATTRIBUTE_UNUSED void *rate, snd_output_t *out) +{ + snd_output_printf(out, "Converter: linear-interpolation\n"); +} + +static const snd_pcm_rate_ops_t linear_ops = { + .close = linear_close, + .init = linear_init, + .free = linear_free, + .reset = linear_reset, + .adjust_pitch = linear_adjust_pitch, + .convert = linear_convert, + .input_frames = input_frames, + .output_frames = output_frames, + .version = SND_PCM_RATE_PLUGIN_VERSION, + .get_supported_rates = get_supported_rates, + .dump = linear_dump, +}; + +int SND_PCM_RATE_PLUGIN_ENTRY(linear) (ATTRIBUTE_UNUSED unsigned int version, + void **objp, snd_pcm_rate_ops_t *ops) +{ + struct rate_linear *rate; + + rate = calloc(1, sizeof(*rate)); + if (! rate) + return -ENOMEM; + + *objp = rate; + *ops = linear_ops; + return 0; +} diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c new file mode 100644 index 0000000..4da623f --- /dev/null +++ b/src/pcm/pcm_route.c @@ -0,0 +1,1172 @@ +/** + * \file pcm/pcm_route.c + * \ingroup PCM_Plugins + * \brief PCM Route & Volume Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Route & Volume Plugin + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include "plugin_ops.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_route = ""; +#endif + +#ifndef DOC_HIDDEN + +/* The best possible hack to support missing optimization in gcc 2.7.2.3 */ +#if SND_PCM_PLUGIN_ROUTE_RESOLUTION & (SND_PCM_PLUGIN_ROUTE_RESOLUTION - 1) != 0 +#define div(a) a /= SND_PCM_PLUGIN_ROUTE_RESOLUTION +#elif SND_PCM_PLUGIN_ROUTE_RESOLUTION == 16 +#define div(a) a >>= 4 +#else +#error "Add some code here" +#endif + +typedef struct { + int channel; + int as_int; +#if SND_PCM_PLUGIN_ROUTE_FLOAT + float as_float; +#endif +} snd_pcm_route_ttable_src_t; + +typedef struct snd_pcm_route_ttable_dst snd_pcm_route_ttable_dst_t; + +typedef struct { + enum {UINT32=0, UINT64=1, FLOAT=2} sum_idx; + unsigned int get_idx; + unsigned int put_idx; + unsigned int conv_idx; + int use_getput; + unsigned int src_size; + snd_pcm_format_t dst_sfmt; + unsigned int ndsts; + snd_pcm_route_ttable_dst_t *dsts; +} snd_pcm_route_params_t; + + +typedef void (*route_f)(const snd_pcm_channel_area_t *dst_area, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int src_channels, + snd_pcm_uframes_t frames, + const snd_pcm_route_ttable_dst_t *ttable, + const snd_pcm_route_params_t *params); + +struct snd_pcm_route_ttable_dst { + int att; /* Attenuated */ + unsigned int nsrcs; + snd_pcm_route_ttable_src_t* srcs; + route_f func; +}; + +typedef union { + int32_t as_sint32; + int64_t as_sint64; +#if SND_PCM_PLUGIN_ROUTE_FLOAT + float as_float; +#endif +} sum_t; + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + snd_pcm_format_t sformat; + int schannels; + snd_pcm_route_params_t params; +} snd_pcm_route_t; + +#endif /* DOC_HIDDEN */ + +static void snd_pcm_route_convert1_zero(const snd_pcm_channel_area_t *dst_area, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas ATTRIBUTE_UNUSED, + snd_pcm_uframes_t src_offset ATTRIBUTE_UNUSED, + unsigned int src_channels ATTRIBUTE_UNUSED, + snd_pcm_uframes_t frames, + const snd_pcm_route_ttable_dst_t* ttable ATTRIBUTE_UNUSED, + const snd_pcm_route_params_t *params) +{ + snd_pcm_area_silence(dst_area, dst_offset, frames, params->dst_sfmt); +} + +#ifndef DOC_HIDDEN + +static void snd_pcm_route_convert1_one(const snd_pcm_channel_area_t *dst_area, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int src_channels, + snd_pcm_uframes_t frames, + const snd_pcm_route_ttable_dst_t* ttable, + const snd_pcm_route_params_t *params) +{ +#define CONV_LABELS +#include "plugin_ops.h" +#undef CONV_LABELS + void *conv; + const snd_pcm_channel_area_t *src_area = 0; + unsigned int srcidx; + const char *src; + char *dst; + int src_step, dst_step; + for (srcidx = 0; srcidx < ttable->nsrcs && srcidx < src_channels; ++srcidx) { + unsigned int channel = ttable->srcs[srcidx].channel; + if (channel >= src_channels) + continue; + src_area = &src_areas[channel]; + if (src_area->addr != NULL) + break; + } + if (srcidx == ttable->nsrcs || srcidx == src_channels) { + snd_pcm_route_convert1_zero(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, ttable, params); + return; + } + + conv = conv_labels[params->conv_idx]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + while (frames-- > 0) { + goto *conv; +#define CONV_END after +#include "plugin_ops.h" +#undef CONV_END + after: + src += src_step; + dst += dst_step; + } +} + +static void snd_pcm_route_convert1_one_getput(const snd_pcm_channel_area_t *dst_area, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int src_channels, + snd_pcm_uframes_t frames, + const snd_pcm_route_ttable_dst_t* ttable, + const snd_pcm_route_params_t *params) +{ +#define CONV24_LABELS +#include "plugin_ops.h" +#undef CONV24_LABELS + void *get, *put; + const snd_pcm_channel_area_t *src_area = 0; + unsigned int srcidx; + const char *src; + char *dst; + int src_step, dst_step; + u_int32_t sample = 0; + for (srcidx = 0; srcidx < ttable->nsrcs && srcidx < src_channels; ++srcidx) { + unsigned int channel = ttable->srcs[srcidx].channel; + if (channel >= src_channels) + continue; + src_area = &src_areas[channel]; + if (src_area->addr != NULL) + break; + } + if (srcidx == ttable->nsrcs || srcidx == src_channels) { + snd_pcm_route_convert1_zero(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, ttable, params); + return; + } + + get = get32_labels[params->get_idx]; + put = put32_labels[params->put_idx]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area); + while (frames-- > 0) { + goto *get; +#define CONV24_END after +#include "plugin_ops.h" +#undef CONV24_END + after: + src += src_step; + dst += dst_step; + } +} + +static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int src_channels, + snd_pcm_uframes_t frames, + const snd_pcm_route_ttable_dst_t* ttable, + const snd_pcm_route_params_t *params) +{ +#define GETS_LABELS +#define PUT32_LABELS +#include "plugin_ops.h" +#undef GETS_LABELS +#undef PUT32_LABELS + static void *const zero_labels[3] = { + &&zero_int32, &&zero_int64, +#if SND_PCM_PLUGIN_ROUTE_FLOAT + &&zero_float +#endif + }; + /* sum_type att */ + static void *const add_labels[3 * 2] = { + &&add_int32_noatt, &&add_int32_att, + &&add_int64_noatt, &&add_int64_att, +#if SND_PCM_PLUGIN_ROUTE_FLOAT + &&add_float_noatt, &&add_float_att +#endif + }; + /* sum_type att shift */ + static void *const norm_labels[3 * 2 * 4] = { + 0, + &&norm_int32_8_noatt, + &&norm_int32_16_noatt, + &&norm_int32_24_noatt, + 0, + &&norm_int32_8_att, + &&norm_int32_16_att, + &&norm_int32_24_att, + &&norm_int64_0_noatt, + &&norm_int64_8_noatt, + &&norm_int64_16_noatt, + &&norm_int64_24_noatt, + &&norm_int64_0_att, + &&norm_int64_8_att, + &&norm_int64_16_att, + &&norm_int64_24_att, +#if SND_PCM_PLUGIN_ROUTE_FLOAT + &&norm_float_0, + &&norm_float_8, + &&norm_float_16, + &&norm_float_24, + &&norm_float_0, + &&norm_float_8, + &&norm_float_16, + &&norm_float_24, +#endif + }; + void *zero, *get, *add, *norm, *put32; + int nsrcs = ttable->nsrcs; + char *dst; + int dst_step; + const char *srcs[nsrcs]; + int src_steps[nsrcs]; + snd_pcm_route_ttable_src_t src_tt[nsrcs]; + int32_t sample = 0; + int srcidx, srcidx1 = 0; + for (srcidx = 0; srcidx < nsrcs && (unsigned)srcidx < src_channels; ++srcidx) { + const snd_pcm_channel_area_t *src_area; + unsigned int channel = ttable->srcs[srcidx].channel; + if (channel >= src_channels) + continue; + src_area = &src_areas[channel]; + srcs[srcidx1] = snd_pcm_channel_area_addr(src_area, src_offset); + src_steps[srcidx1] = snd_pcm_channel_area_step(src_area); + src_tt[srcidx1] = ttable->srcs[srcidx]; + srcidx1++; + } + nsrcs = srcidx1; + if (nsrcs == 0) { + snd_pcm_route_convert1_zero(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, ttable, params); + return; + } else if (nsrcs == 1 && src_tt[0].as_int == SND_PCM_PLUGIN_ROUTE_RESOLUTION) { + if (params->use_getput) + snd_pcm_route_convert1_one_getput(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, ttable, params); + else + snd_pcm_route_convert1_one(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, ttable, params); + return; + } + + zero = zero_labels[params->sum_idx]; + get = gets_labels[params->get_idx]; + add = add_labels[params->sum_idx * 2 + ttable->att]; + norm = norm_labels[params->sum_idx * 8 + ttable->att * 4 + 4 - params->src_size]; + put32 = put32_labels[params->put_idx]; + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + dst_step = snd_pcm_channel_area_step(dst_area); + + while (frames-- > 0) { + snd_pcm_route_ttable_src_t *ttp = src_tt; + sum_t sum; + + /* Zero sum */ + goto *zero; + zero_int32: + sum.as_sint32 = 0; + goto zero_end; + zero_int64: + sum.as_sint64 = 0; + goto zero_end; +#if SND_PCM_PLUGIN_ROUTE_FLOAT + zero_float: + sum.as_float = 0.0; + goto zero_end; +#endif + zero_end: + for (srcidx = 0; srcidx < nsrcs; ++srcidx) { + const char *src = srcs[srcidx]; + + /* Get sample */ + goto *get; +#define GETS_END after_get +#include "plugin_ops.h" +#undef GETS_END + after_get: + + /* Sum */ + goto *add; + add_int32_att: + sum.as_sint32 += sample * ttp->as_int; + goto after_sum; + add_int32_noatt: + if (ttp->as_int) + sum.as_sint32 += sample; + goto after_sum; + add_int64_att: + sum.as_sint64 += (int64_t) sample * ttp->as_int; + goto after_sum; + add_int64_noatt: + if (ttp->as_int) + sum.as_sint64 += sample; + goto after_sum; +#if SND_PCM_PLUGIN_ROUTE_FLOAT + add_float_att: + sum.as_float += sample * ttp->as_float; + goto after_sum; + add_float_noatt: + if (ttp->as_int) + sum.as_float += sample; + goto after_sum; +#endif + after_sum: + srcs[srcidx] += src_steps[srcidx]; + ttp++; + } + + /* Normalization */ + goto *norm; + norm_int32_8_att: + sum.as_sint64 = sum.as_sint32; + norm_int64_8_att: + sum.as_sint64 <<= 8; + norm_int64_0_att: + div(sum.as_sint64); + goto norm_int; + + norm_int32_16_att: + sum.as_sint64 = sum.as_sint32; + norm_int64_16_att: + sum.as_sint64 <<= 16; + div(sum.as_sint64); + goto norm_int; + + norm_int32_24_att: + sum.as_sint64 = sum.as_sint32; + norm_int64_24_att: + sum.as_sint64 <<= 24; + div(sum.as_sint64); + goto norm_int; + + norm_int32_8_noatt: + sum.as_sint64 = sum.as_sint32; + norm_int64_8_noatt: + sum.as_sint64 <<= 8; + goto norm_int; + + norm_int32_16_noatt: + sum.as_sint64 = sum.as_sint32; + norm_int64_16_noatt: + sum.as_sint64 <<= 16; + goto norm_int; + + norm_int32_24_noatt: + sum.as_sint64 = sum.as_sint32; + norm_int64_24_noatt: + sum.as_sint64 <<= 24; + goto norm_int; + + norm_int64_0_noatt: + norm_int: + if (sum.as_sint64 > (int64_t)0x7fffffff) + sample = 0x7fffffff; /* maximum positive value */ + else if (sum.as_sint64 < -(int64_t)0x80000000) + sample = 0x80000000; /* maximum negative value */ + else + sample = sum.as_sint64; + goto after_norm; + +#if SND_PCM_PLUGIN_ROUTE_FLOAT + norm_float_8: + sum.as_float *= 1 << 8; + goto norm_float; + norm_float_16: + sum.as_float *= 1 << 16; + goto norm_float; + norm_float_24: + sum.as_float *= 1 << 24; + goto norm_float; + norm_float_0: + norm_float: + sum.as_float = rint(sum.as_float); + if (sum.as_float > (int64_t)0x7fffffff) + sample = 0x7fffffff; /* maximum positive value */ + else if (sum.as_float < -(int64_t)0x80000000) + sample = 0x80000000; /* maximum negative value */ + else + sample = sum.as_float; + goto after_norm; +#endif + after_norm: + + /* Put sample */ + goto *put32; +#define PUT32_END after_put32 +#include "plugin_ops.h" +#undef PUT32_END + after_put32: + + dst += dst_step; + } +} + +#endif /* DOC_HIDDEN */ + +static void snd_pcm_route_convert(const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int src_channels, + unsigned int dst_channels, + snd_pcm_uframes_t frames, + snd_pcm_route_params_t *params) +{ + unsigned int dst_channel; + snd_pcm_route_ttable_dst_t *dstp; + const snd_pcm_channel_area_t *dst_area; + + dstp = params->dsts; + dst_area = dst_areas; + for (dst_channel = 0; dst_channel < dst_channels; ++dst_channel) { + if (dst_channel >= params->ndsts) + snd_pcm_route_convert1_zero(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, dstp, params); + else + dstp->func(dst_area, dst_offset, + src_areas, src_offset, + src_channels, + frames, dstp, params); + dstp++; + dst_area++; + } +} + +static int snd_pcm_route_close(snd_pcm_t *pcm) +{ + snd_pcm_route_t *route = pcm->private_data; + snd_pcm_route_params_t *params = &route->params; + unsigned int dst_channel; + + if (params->dsts) { + for (dst_channel = 0; dst_channel < params->ndsts; ++dst_channel) { + free(params->dsts[dst_channel].srcs); + } + free(params->dsts); + } + return snd_pcm_generic_close(pcm); +} + +static int snd_pcm_route_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_route_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_route_t *route = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + if (route->sformat != SND_PCM_FORMAT_UNKNOWN) { + _snd_pcm_hw_params_set_format(sparams, route->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + } + if (route->schannels >= 0) { + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, + (unsigned int) route->schannels, 0); + } + return 0; +} + +static int snd_pcm_route_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_route_t *route = pcm->private_data; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (route->sformat == SND_PCM_FORMAT_UNKNOWN) + links |= (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS); + if (route->schannels < 0) + links |= SND_PCM_HW_PARBIT_CHANNELS; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_route_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_route_t *route = pcm->private_data; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (route->sformat == SND_PCM_FORMAT_UNKNOWN) + links |= (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS); + if (route->schannels < 0) + links |= SND_PCM_HW_PARBIT_CHANNELS; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_route_hw_refine_cprepare, + snd_pcm_route_hw_refine_cchange, + snd_pcm_route_hw_refine_sprepare, + snd_pcm_route_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_route_t *route = pcm->private_data; + snd_pcm_t *slave = route->plug.gen.slave; + snd_pcm_format_t src_format, dst_format; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_route_hw_refine_cchange, + snd_pcm_route_hw_refine_sprepare, + snd_pcm_route_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &src_format); + dst_format = slave->format; + } else { + src_format = slave->format; + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format); + } + if (err < 0) + return err; + route->params.use_getput = snd_pcm_format_physical_width(src_format) == 24 || + snd_pcm_format_physical_width(dst_format) == 24; + route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16); + route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format); + route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format); + route->params.src_size = snd_pcm_format_width(src_format) / 8; + route->params.dst_sfmt = dst_format; +#if SND_PCM_PLUGIN_ROUTE_FLOAT + route->params.sum_idx = FLOAT; +#else + if (snd_pcm_format_width(src_format) == 32) + route->params.sum_idx = UINT64; + else + route->params.sum_idx = UINT32; +#endif + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_route_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_route_t *route = pcm->private_data; + snd_pcm_t *slave = route->plug.gen.slave; + if (size > *slave_sizep) + size = *slave_sizep; + snd_pcm_route_convert(slave_areas, slave_offset, + areas, offset, + pcm->channels, + slave->channels, + size, &route->params); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_route_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_route_t *route = pcm->private_data; + snd_pcm_t *slave = route->plug.gen.slave; + if (size > *slave_sizep) + size = *slave_sizep; + snd_pcm_route_convert(areas, offset, + slave_areas, slave_offset, + slave->channels, + pcm->channels, + size, &route->params); + *slave_sizep = size; + return size; +} + +static void snd_pcm_route_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_route_t *route = pcm->private_data; + unsigned int dst; + if (route->sformat == SND_PCM_FORMAT_UNKNOWN) + snd_output_printf(out, "Route conversion PCM\n"); + else + snd_output_printf(out, "Route conversion PCM (sformat=%s)\n", + snd_pcm_format_name(route->sformat)); + snd_output_puts(out, " Transformation table:\n"); + for (dst = 0; dst < route->params.ndsts; dst++) { + snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst]; + unsigned int src; + snd_output_printf(out, " %d <- ", dst); + if (d->nsrcs == 0) { + snd_output_printf(out, "none\n"); + continue; + } + src = 0; + while (1) { + snd_pcm_route_ttable_src_t *s = &d->srcs[src]; + if (d->att) +#if SND_PCM_PLUGIN_ROUTE_FLOAT + snd_output_printf(out, "%d*%g", s->channel, s->as_float); +#else + snd_output_printf(out, "%d*%g", s->channel, (double)s->as_int / (double)SND_PCM_PLUGIN_ROUTE_RESOLUTION); +#endif + else + snd_output_printf(out, "%d", s->channel); + src++; + if (src == d->nsrcs) + break; + snd_output_puts(out, " + "); + } + snd_output_putc(out, '\n'); + } + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(route->plug.gen.slave, out); +} + +static const snd_pcm_ops_t snd_pcm_route_ops = { + .close = snd_pcm_route_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_route_hw_refine, + .hw_params = snd_pcm_route_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_route_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +static int route_load_ttable(snd_pcm_route_params_t *params, snd_pcm_stream_t stream, + unsigned int tt_ssize, + snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_cused, unsigned int tt_sused) +{ + unsigned int src_channel, dst_channel; + snd_pcm_route_ttable_dst_t *dptr; + unsigned int sused, dused, smul, dmul; + if (stream == SND_PCM_STREAM_PLAYBACK) { + sused = tt_cused; + dused = tt_sused; + smul = tt_ssize; + dmul = 1; + } else { + sused = tt_sused; + dused = tt_cused; + smul = 1; + dmul = tt_ssize; + } + params->ndsts = dused; + dptr = calloc(dused, sizeof(*params->dsts)); + if (!dptr) + return -ENOMEM; + params->dsts = dptr; + for (dst_channel = 0; dst_channel < dused; ++dst_channel) { + snd_pcm_route_ttable_entry_t t = 0; + int att = 0; + int nsrcs = 0; + snd_pcm_route_ttable_src_t srcs[sused]; + for (src_channel = 0; src_channel < sused; ++src_channel) { + snd_pcm_route_ttable_entry_t v; + v = ttable[src_channel * smul + dst_channel * dmul]; + if (v != 0) { + srcs[nsrcs].channel = src_channel; +#if SND_PCM_PLUGIN_ROUTE_FLOAT + /* Also in user space for non attenuated */ + srcs[nsrcs].as_int = (v == SND_PCM_PLUGIN_ROUTE_FULL ? SND_PCM_PLUGIN_ROUTE_RESOLUTION : 0); + srcs[nsrcs].as_float = v; +#else + assert(v >= 0 && v <= SND_PCM_PLUGIN_ROUTE_FULL); + srcs[nsrcs].as_int = v; +#endif + if (v != SND_PCM_PLUGIN_ROUTE_FULL) + att = 1; + t += v; + nsrcs++; + } + } +#if 0 + assert(t <= SND_PCM_PLUGIN_ROUTE_FULL); +#endif + dptr->att = att; + dptr->nsrcs = nsrcs; + if (nsrcs == 0) + dptr->func = snd_pcm_route_convert1_zero; + else + dptr->func = snd_pcm_route_convert1_many; + if (nsrcs > 0) { + dptr->srcs = calloc((unsigned int) nsrcs, sizeof(*srcs)); + if (!dptr->srcs) + return -ENOMEM; + memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs); + } else + dptr->srcs = 0; + dptr++; + } + return 0; +} + +/** + * \brief Creates a new Route & Volume PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave format + * \param schannels Slave channels + * \param ttable Attenuation table + * \param tt_ssize Attenuation table - slave size + * \param tt_cused Attenuation table - client used count + * \param tt_sused Attenuation table - slave used count + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, int schannels, + snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_ssize, + unsigned int tt_cused, unsigned int tt_sused, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_route_t *route; + int err; + assert(pcmp && slave && ttable); + if (sformat != SND_PCM_FORMAT_UNKNOWN && + snd_pcm_format_linear(sformat) != 1) + return -EINVAL; + route = calloc(1, sizeof(snd_pcm_route_t)); + if (!route) { + return -ENOMEM; + } + snd_pcm_plugin_init(&route->plug); + route->sformat = sformat; + route->schannels = schannels; + route->plug.read = snd_pcm_route_read_areas; + route->plug.write = snd_pcm_route_write_areas; + route->plug.undo_read = snd_pcm_plugin_undo_read_generic; + route->plug.undo_write = snd_pcm_plugin_undo_write_generic; + route->plug.gen.slave = slave; + route->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_ROUTE, name, slave->stream, slave->mode); + if (err < 0) { + free(route); + return err; + } + pcm->ops = &snd_pcm_route_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = route; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0); + err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused); + if (err < 0) { + snd_pcm_close(pcm); + return err; + } + *pcmp = pcm; + + return 0; +} + +/** + * \brief Determine route matrix sizes + * \param tt Configuration root describing route matrix + * \param tt_csize Returned client size in elements + * \param tt_ssize Returned slave size in elements + * \retval zero on success otherwise a negative error code + */ +int snd_pcm_route_determine_ttable(snd_config_t *tt, + unsigned int *tt_csize, + unsigned int *tt_ssize) +{ + snd_config_iterator_t i, inext; + long csize = 0, ssize = 0; + int err; + + assert(tt && tt_csize && tt_ssize); + snd_config_for_each(i, inext, tt) { + snd_config_t *in = snd_config_iterator_entry(i); + snd_config_iterator_t j, jnext; + long cchannel; + const char *id; + if (!snd_config_get_id(in, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0) { + SNDERR("Invalid client channel: %s", id); + return -EINVAL; + } + if (cchannel + 1 > csize) + csize = cchannel + 1; + if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + snd_config_for_each(j, jnext, in) { + snd_config_t *jnode = snd_config_iterator_entry(j); + long schannel; + const char *id; + if (snd_config_get_id(jnode, &id) < 0) + continue; + err = safe_strtol(id, &schannel); + if (err < 0) { + SNDERR("Invalid slave channel: %s", id); + return -EINVAL; + } + if (schannel + 1 > ssize) + ssize = schannel + 1; + } + } + if (csize == 0 || ssize == 0) { + SNDERR("Invalid null ttable configuration"); + return -EINVAL; + } + *tt_csize = csize; + *tt_ssize = ssize; + return 0; +} + +/** + * \brief Load route matrix + * \param tt Configuration root describing route matrix + * \param ttable Returned route matrix + * \param tt_csize Client size in elements + * \param tt_ssize Slave size in elements + * \param tt_cused Used client elements + * \param tt_sused Used slave elements + * \param schannels Slave channels + * \retval zero on success otherwise a negative error code + */ +int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_csize, unsigned int tt_ssize, + unsigned int *tt_cused, unsigned int *tt_sused, + int schannels) +{ + int cused = -1; + int sused = -1; + snd_config_iterator_t i, inext; + unsigned int k; + int err; + for (k = 0; k < tt_csize * tt_ssize; ++k) + ttable[k] = 0.0; + snd_config_for_each(i, inext, tt) { + snd_config_t *in = snd_config_iterator_entry(i); + snd_config_iterator_t j, jnext; + long cchannel; + const char *id; + if (!snd_config_get_id(in, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0 || + cchannel < 0 || (unsigned int) cchannel > tt_csize) { + SNDERR("Invalid client channel: %s", id); + return -EINVAL; + } + if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + snd_config_for_each(j, jnext, in) { + snd_config_t *jnode = snd_config_iterator_entry(j); + double value; + long schannel; + const char *id; + if (snd_config_get_id(jnode, &id) < 0) + continue; + err = safe_strtol(id, &schannel); + if (err < 0 || + schannel < 0 || (unsigned int) schannel > tt_ssize || + (schannels > 0 && schannel >= schannels)) { + SNDERR("Invalid slave channel: %s", id); + return -EINVAL; + } + err = snd_config_get_real(jnode, &value); + if (err < 0) { + long v; + err = snd_config_get_integer(jnode, &v); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + value = v; + } + ttable[cchannel * tt_ssize + schannel] = value; + if (schannel > sused) + sused = schannel; + } + if (cchannel > cused) + cused = cchannel; + } + *tt_sused = sused + 1; + *tt_cused = cused + 1; + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_route Plugin: Route & Volume + +This plugin converts channels and applies volume during the conversion. +The format and rate must match for both of them. + +\code +pcm.name { + type route # Route & Volume conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format + [channels INT] # Slave channels + } + ttable { # Transfer table (bi-dimensional compound of cchannels * schannels numbers) + CCHANNEL { + SCHANNEL REAL # route value (0.0 - 1.0) + } + } +} +\endcode + +\subsection pcm_plugins_route_funcref Function reference + +
    +
  • snd_pcm_route_open() +
  • _snd_pcm_route_open() +
+ +*/ + +/** + * \brief Creates a new Route & Volume PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Route & Volume PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; + int schannels = -1; + snd_config_t *tt = NULL; + snd_pcm_route_ttable_entry_t *ttable = NULL; + unsigned int csize, ssize; + unsigned int cused, sused; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "ttable") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + tt = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + if (!tt) { + SNDERR("ttable is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 2, + SND_PCM_HW_PARAM_FORMAT, 0, &sformat, + SND_PCM_HW_PARAM_CHANNELS, 0, &schannels); + if (err < 0) + return err; + if (sformat != SND_PCM_FORMAT_UNKNOWN && + snd_pcm_format_linear(sformat) != 1) { + snd_config_delete(sconf); + SNDERR("slave format is not linear"); + return -EINVAL; + } + + err = snd_pcm_route_determine_ttable(tt, &csize, &ssize); + if (err < 0) { + snd_config_delete(sconf); + return err; + } + ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t)); + if (ttable == NULL) { + snd_config_delete(sconf); + return -ENOMEM; + } + err = snd_pcm_route_load_ttable(tt, ttable, csize, ssize, + &cused, &sused, schannels); + if (err < 0) { + free(ttable); + snd_config_delete(sconf); + return err; + } + + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) { + free(ttable); + return err; + } + err = snd_pcm_route_open(pcmp, name, sformat, schannels, + ttable, ssize, + cused, sused, + spcm, 1); + free(ttable); + if (err < 0) + snd_pcm_close(spcm); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_route_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c new file mode 100644 index 0000000..56a8685 --- /dev/null +++ b/src/pcm/pcm_share.c @@ -0,0 +1,1723 @@ +/** + * \file pcm/pcm_share.c + * \ingroup PCM_Plugins + * \brief PCM Share Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Share + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcm_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_share = ""; +#endif + +#ifndef DOC_HIDDEN + +static LIST_HEAD(snd_pcm_share_slaves); +static pthread_mutex_t snd_pcm_share_slaves_mutex = PTHREAD_MUTEX_INITIALIZER; + +#ifdef MUTEX_DEBUG +#define Pthread_mutex_lock(mutex) \ +char *snd_pcm_share_slaves_mutex_holder; +do { \ + int err = pthread_mutex_trylock(mutex); \ + if (err < 0) { \ + fprintf(stderr, "lock " #mutex " is busy (%s): waiting in " __FUNCTION__ "\n", *(mutex##_holder)); \ + pthread_mutex_lock(mutex); \ + fprintf(stderr, "... got\n"); \ + } \ + *(mutex##_holder) = __FUNCTION__; \ +} while (0) + +#define Pthread_mutex_unlock(mutex) \ +do { \ + *(mutex##_holder) = 0; \ + pthread_mutex_unlock(mutex); \ +} while (0) +#else +#define Pthread_mutex_lock(mutex) pthread_mutex_lock(mutex) +#define Pthread_mutex_unlock(mutex) pthread_mutex_unlock(mutex) +#endif + +typedef struct { + struct list_head clients; + struct list_head list; + snd_pcm_t *pcm; + snd_pcm_format_t format; + int rate; + unsigned int channels; + snd_pcm_sframes_t period_time; + snd_pcm_sframes_t buffer_time; + unsigned int open_count; + unsigned int setup_count; + unsigned int prepared_count; + unsigned int running_count; + snd_pcm_uframes_t safety_threshold; + snd_pcm_uframes_t silence_frames; + snd_pcm_sw_params_t sw_params; + snd_pcm_uframes_t hw_ptr; + int poll[2]; + int polling; + pthread_t thread; + pthread_mutex_t mutex; +#ifdef MUTEX_DEBUG + char *mutex_holder; +#endif + pthread_cond_t poll_cond; +} snd_pcm_share_slave_t; + +typedef struct { + struct list_head list; + snd_pcm_t *pcm; + snd_pcm_share_slave_t *slave; + unsigned int channels; + unsigned int *slave_channels; + int drain_silenced; + snd_htimestamp_t trigger_tstamp; + snd_pcm_state_t state; + snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t appl_ptr; + int ready; + int client_socket; + int slave_socket; +} snd_pcm_share_t; + +#endif /* DOC_HIDDEN */ + +static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state); + +static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave) +{ + snd_pcm_sframes_t avail; + snd_pcm_t *pcm = slave->pcm; + avail = slave->hw_ptr - *pcm->appl.ptr; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + avail += pcm->buffer_size; + if (avail < 0) + avail += pcm->boundary; + return avail; +} + +/* Warning: take the mutex before to call this */ +/* Return number of frames to mmap_commit the slave */ +static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave) +{ + struct list_head *i; + snd_pcm_uframes_t buffer_size, boundary; + snd_pcm_uframes_t slave_appl_ptr; + snd_pcm_sframes_t frames, safety_frames; + snd_pcm_sframes_t min_frames, max_frames; + snd_pcm_uframes_t avail, slave_avail; + snd_pcm_uframes_t slave_hw_avail; + slave_avail = snd_pcm_share_slave_avail(slave); + boundary = slave->pcm->boundary; + buffer_size = slave->pcm->buffer_size; + min_frames = slave_avail; + max_frames = 0; + slave_appl_ptr = *slave->pcm->appl.ptr; + list_for_each(i, &slave->clients) { + snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); + snd_pcm_t *pcm = share->pcm; + switch (share->state) { + case SND_PCM_STATE_RUNNING: + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + continue; + break; + default: + continue; + } + avail = snd_pcm_mmap_avail(pcm); + frames = slave_avail - avail; + if (frames > max_frames) + max_frames = frames; + if (share->state != SND_PCM_STATE_RUNNING) + continue; + if (frames < min_frames) + min_frames = frames; + } + if (max_frames == 0) + return 0; + frames = min_frames; + /* Slave xrun prevention */ + slave_hw_avail = buffer_size - slave_avail; + safety_frames = slave->safety_threshold - slave_hw_avail; + if (safety_frames > 0 && + frames < safety_frames) { + /* Avoid to pass over the last */ + if (max_frames < safety_frames) + frames = max_frames; + else + frames = safety_frames; + } + if (frames < 0) + return 0; + return frames; +} + + +/* + - stop PCM on xrun + - update poll status + - draining silencing + - return distance in frames to next event +*/ +static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_t *spcm = slave->pcm; + snd_pcm_uframes_t buffer_size = spcm->buffer_size; + int ready = 1, running = 0; + snd_pcm_uframes_t avail = 0, slave_avail; + snd_pcm_sframes_t hw_avail; + snd_pcm_uframes_t missing = INT_MAX; + snd_pcm_sframes_t ready_missing; + // printf("state=%s hw_ptr=%ld appl_ptr=%ld slave appl_ptr=%ld safety=%ld silence=%ld\n", snd_pcm_state_name(share->state), slave->hw_ptr, share->appl_ptr, *slave->pcm->appl_ptr, slave->safety_threshold, slave->silence_frames); + switch (share->state) { + case SND_PCM_STATE_RUNNING: + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + break; + /* Fall through */ + default: + return INT_MAX; + } + share->hw_ptr = slave->hw_ptr; + avail = snd_pcm_mmap_avail(pcm); + if (avail >= pcm->stop_threshold) { + _snd_pcm_share_stop(pcm, share->state == SND_PCM_STATE_DRAINING ? SND_PCM_STATE_SETUP : SND_PCM_STATE_XRUN); + goto update_poll; + } + hw_avail = buffer_size - avail; + slave_avail = snd_pcm_share_slave_avail(slave); + if (avail < slave_avail) { + /* Some frames need still to be transferred */ + snd_pcm_sframes_t slave_hw_avail = buffer_size - slave_avail; + snd_pcm_sframes_t safety_missing = slave_hw_avail - slave->safety_threshold; + if (safety_missing < 0) { + snd_pcm_sframes_t err; + snd_pcm_sframes_t frames = slave_avail - avail; + if (-safety_missing <= frames) { + frames = -safety_missing; + missing = 1; + } + err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames); + if (err < 0) { + SYSMSG("snd_pcm_mmap_commit error"); + return INT_MAX; + } + if (err != frames) + SYSMSG("commit returns %ld for size %ld", err, frames); + slave_avail -= err; + } else { + if (safety_missing == 0) + missing = 1; + else + missing = safety_missing; + } + } + switch (share->state) { + case SND_PCM_STATE_DRAINING: + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (hw_avail <= 0) { + _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP); + break; + } + if ((snd_pcm_uframes_t)hw_avail < missing) + missing = hw_avail; + running = 1; + ready = 0; + } + break; + case SND_PCM_STATE_RUNNING: + if (avail >= pcm->stop_threshold) { + _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN); + break; + } else { + snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail; + if (missing > xrun_missing) + missing = xrun_missing; + } + ready_missing = pcm->avail_min - avail; + if (ready_missing > 0) { + ready = 0; + if (missing > (snd_pcm_uframes_t)ready_missing) + missing = ready_missing; + } + running = 1; + break; + default: + SNDERR("invalid shared PCM state %d", share->state); + return INT_MAX; + } + + update_poll: + if (ready != share->ready) { + char buf[1]; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (ready) + read(share->slave_socket, buf, 1); + else + write(share->client_socket, buf, 1); + } else { + if (ready) + write(share->slave_socket, buf, 1); + else + read(share->client_socket, buf, 1); + } + share->ready = ready; + } + if (!running) + return INT_MAX; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK && + share->state == SND_PCM_STATE_DRAINING && + !share->drain_silenced) { + /* drain silencing */ + if (avail >= slave->silence_frames) { + snd_pcm_uframes_t offset = share->appl_ptr % buffer_size; + snd_pcm_uframes_t xfer = 0; + snd_pcm_uframes_t size = slave->silence_frames; + while (xfer < size) { + snd_pcm_uframes_t frames = size - xfer; + snd_pcm_uframes_t cont = buffer_size - offset; + if (cont < frames) + frames = cont; + snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format); + offset += frames; + if (offset >= buffer_size) + offset = 0; + xfer += frames; + } + share->drain_silenced = 1; + } else { + snd_pcm_uframes_t silence_missing; + silence_missing = slave->silence_frames - avail; + if (silence_missing < missing) + missing = silence_missing; + } + } + // printf("missing=%d\n", missing); + return missing; +} + +static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *slave) +{ + snd_pcm_uframes_t missing = INT_MAX; + struct list_head *i; + /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm); + slave->hw_ptr = *slave->pcm->hw.ptr; + list_for_each(i, &slave->clients) { + snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); + snd_pcm_t *pcm = share->pcm; + snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm); + if (m < missing) + missing = m; + } + return missing; +} + +static void *snd_pcm_share_thread(void *data) +{ + snd_pcm_share_slave_t *slave = data; + snd_pcm_t *spcm = slave->pcm; + struct pollfd pfd[2]; + int err; + + pfd[0].fd = slave->poll[0]; + pfd[0].events = POLLIN; + err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1); + if (err != 1) { + SNDERR("invalid poll descriptors %d", err); + return NULL; + } + Pthread_mutex_lock(&slave->mutex); + err = pipe(slave->poll); + if (err < 0) { + SYSERR("can't create a pipe"); + return NULL; + } + while (slave->open_count > 0) { + snd_pcm_uframes_t missing; + // printf("begin min_missing\n"); + missing = _snd_pcm_share_slave_missing(slave); + // printf("min_missing=%ld\n", missing); + if (missing < INT_MAX) { + snd_pcm_uframes_t hw_ptr; + snd_pcm_sframes_t avail_min; + hw_ptr = slave->hw_ptr + missing; + hw_ptr += spcm->period_size - 1; + if (hw_ptr >= spcm->boundary) + hw_ptr -= spcm->boundary; + hw_ptr -= hw_ptr % spcm->period_size; + avail_min = hw_ptr - *spcm->appl.ptr; + if (spcm->stream == SND_PCM_STREAM_PLAYBACK) + avail_min += spcm->buffer_size; + if (avail_min < 0) + avail_min += spcm->boundary; + // printf("avail_min=%d\n", avail_min); + if ((snd_pcm_uframes_t)avail_min != spcm->avail_min) { + snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min); + err = snd_pcm_sw_params(spcm, &slave->sw_params); + if (err < 0) { + SYSERR("snd_pcm_sw_params error"); + return NULL; + } + } + slave->polling = 1; + Pthread_mutex_unlock(&slave->mutex); + err = poll(pfd, 2, -1); + Pthread_mutex_lock(&slave->mutex); + if (pfd[0].revents & POLLIN) { + char buf[1]; + read(pfd[0].fd, buf, 1); + } + } else { + slave->polling = 0; + pthread_cond_wait(&slave->poll_cond, &slave->mutex); + } + } + Pthread_mutex_unlock(&slave->mutex); + return NULL; +} + +static void _snd_pcm_share_update(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_t *spcm = slave->pcm; + snd_pcm_uframes_t missing; + /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(spcm); + slave->hw_ptr = *slave->pcm->hw.ptr; + missing = _snd_pcm_share_missing(pcm); + // printf("missing %ld\n", missing); + if (!slave->polling) { + pthread_cond_signal(&slave->poll_cond); + return; + } + if (missing < INT_MAX) { + snd_pcm_uframes_t hw_ptr; + snd_pcm_sframes_t avail_min; + hw_ptr = slave->hw_ptr + missing; + hw_ptr += spcm->period_size - 1; + if (hw_ptr >= spcm->boundary) + hw_ptr -= spcm->boundary; + hw_ptr -= hw_ptr % spcm->period_size; + avail_min = hw_ptr - *spcm->appl.ptr; + if (spcm->stream == SND_PCM_STREAM_PLAYBACK) + avail_min += spcm->buffer_size; + if (avail_min < 0) + avail_min += spcm->boundary; + if ((snd_pcm_uframes_t)avail_min < spcm->avail_min) { + int err; + snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min); + err = snd_pcm_sw_params(spcm, &slave->sw_params); + if (err < 0) { + SYSERR("snd_pcm_sw_params error"); + return; + } + } + } +} + +static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_share_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info) +{ + snd_pcm_share_t *share = pcm->private_data; + return snd_pcm_info(share->slave->pcm, info); +} + +static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_access_mask_t access_mask; + int err; + snd_pcm_access_mask_any(&access_mask); + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, + share->channels, 0); + if (err < 0) + return err; + if (slave->format != SND_PCM_FORMAT_UNKNOWN) { + err = _snd_pcm_hw_params_set_format(params, slave->format); + if (err < 0) + return err; + } + + if (slave->rate >= 0) { + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_RATE, + slave->rate, 0); + if (err < 0) + return err; + } + if (slave->period_time >= 0) { + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_TIME, + slave->period_time, 0); + if (err < 0) + return err; + } + if (slave->buffer_time >= 0) { + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_TIME, + slave->buffer_time, 0); + if (err < 0) + return err; + } + params->info |= SND_PCM_INFO_DOUBLE; + return 0; +} + +static int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, + slave->channels, 0); + return 0; +} + +static int snd_pcm_share_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_PERIODS); + const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) && + !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { + snd_pcm_access_mask_t saccess_mask; + snd_pcm_access_mask_any(&saccess_mask); + snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_share_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_PERIODS); + snd_pcm_access_mask_t access_mask; + const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS); + snd_pcm_access_mask_any(&access_mask); + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); + if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && + !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) + snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX); + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_share_t *share = pcm->private_data; + return snd_pcm_hw_refine(share->slave->pcm, params); +} + +static int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_share_t *share = pcm->private_data; + return _snd_pcm_hw_params(share->slave->pcm, params); +} + +static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_share_hw_refine_cprepare, + snd_pcm_share_hw_refine_cchange, + snd_pcm_share_hw_refine_sprepare, + snd_pcm_share_hw_refine_schange, + snd_pcm_share_hw_refine_slave); +} + +static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_t *spcm = slave->pcm; + int err = 0; + Pthread_mutex_lock(&slave->mutex); + if (slave->setup_count) { + err = _snd_pcm_hw_params_set_format(params, spcm->format); + if (err < 0) + goto _err; + err = _snd_pcm_hw_params_set_subformat(params, spcm->subformat); + if (err < 0) + goto _err; + err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE, + spcm->rate, 0, + spcm->rate, 1); + if (err < 0) + goto _err; + err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_PERIOD_TIME, + spcm->period_time, 0, + spcm->period_time, 1); + if (err < 0) + goto _err; + err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + spcm->buffer_size, 0); + _err: + if (err < 0) { + SNDERR("slave is already running with incompatible setup"); + err = -EBUSY; + goto _end; + } + } else { + err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_share_hw_refine_cchange, + snd_pcm_share_hw_refine_sprepare, + snd_pcm_share_hw_refine_schange, + snd_pcm_share_hw_params_slave); + if (err < 0) + goto _end; + snd_pcm_sw_params_current(slave->pcm, &slave->sw_params); + /* >= 30 ms */ + slave->safety_threshold = slave->pcm->rate * 30 / 1000; + slave->safety_threshold += slave->pcm->period_size - 1; + slave->safety_threshold -= slave->safety_threshold % slave->pcm->period_size; + slave->silence_frames = slave->safety_threshold; + if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK) + snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format); + } + share->state = SND_PCM_STATE_SETUP; + slave->setup_count++; + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + Pthread_mutex_lock(&slave->mutex); + slave->setup_count--; + if (slave->setup_count == 0) + err = snd_pcm_hw_free(slave->pcm); + share->state = SND_PCM_STATE_OPEN; + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + snd_pcm_sframes_t sd = 0, d = 0; + Pthread_mutex_lock(&slave->mutex); + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + status->avail = snd_pcm_mmap_playback_avail(pcm); + if (share->state != SND_PCM_STATE_RUNNING && + share->state != SND_PCM_STATE_DRAINING) + goto _notrunning; + d = pcm->buffer_size - status->avail; + } else { + status->avail = snd_pcm_mmap_capture_avail(pcm); + if (share->state != SND_PCM_STATE_RUNNING) + goto _notrunning; + d = status->avail; + } + err = snd_pcm_delay(slave->pcm, &sd); + if (err < 0) + goto _end; + _notrunning: + status->delay = sd + d; + status->state = share->state; + status->trigger_tstamp = share->trigger_tstamp; + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + return share->state; +} + +static int _snd_pcm_share_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + switch (share->state) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + break; + } + return snd_pcm_hwsync(slave->pcm); +} + +static int snd_pcm_share_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err; + Pthread_mutex_lock(&slave->mutex); + err = _snd_pcm_share_hwsync(pcm); + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + switch (share->state) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_RUNNING: + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + break; + /* Fall through */ + default: + return -EBADFD; + } + return snd_pcm_delay(slave->pcm, delayp); +} + +static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err; + Pthread_mutex_lock(&slave->mutex); + err = _snd_pcm_share_delay(pcm, delayp); + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t avail; + Pthread_mutex_lock(&slave->mutex); + if (share->state == SND_PCM_STATE_RUNNING) { + avail = snd_pcm_avail_update(slave->pcm); + if (avail < 0) { + Pthread_mutex_unlock(&slave->mutex); + return avail; + } + share->hw_ptr = *slave->pcm->hw.ptr; + } + Pthread_mutex_unlock(&slave->mutex); + avail = snd_pcm_mmap_avail(pcm); + if ((snd_pcm_uframes_t)avail > pcm->buffer_size) + return -EPIPE; + return avail; +} + +static int snd_pcm_share_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + snd_htimestamp_t *tstamp) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err; + Pthread_mutex_lock(&slave->mutex); + err = snd_pcm_htimestamp(slave->pcm, avail, tstamp); + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +/* Call it with mutex held */ +static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_t *spcm = slave->pcm; + snd_pcm_sframes_t ret; + snd_pcm_sframes_t frames; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK && + share->state == SND_PCM_STATE_RUNNING) { + frames = *spcm->appl.ptr - share->appl_ptr; + if (frames > (snd_pcm_sframes_t)pcm->buffer_size) + frames -= pcm->boundary; + else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size) + frames += pcm->boundary; + if (frames > 0) { + /* Latecomer PCM */ + ret = snd_pcm_rewind(spcm, frames); + if (ret < 0) + return ret; + } + } + snd_pcm_mmap_appl_forward(pcm, size); + if (share->state == SND_PCM_STATE_RUNNING) { + frames = _snd_pcm_share_slave_forward(slave); + if (frames > 0) { + snd_pcm_sframes_t err; + err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames); + if (err < 0) { + SYSMSG("snd_pcm_mmap_commit error"); + return err; + } + if (err != frames) { + SYSMSG("commit returns %ld for size %ld", err, frames); + return err; + } + } + _snd_pcm_share_update(pcm); + } + return size; +} + +static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t ret; + Pthread_mutex_lock(&slave->mutex); + ret = _snd_pcm_share_mmap_commit(pcm, offset, size); + Pthread_mutex_unlock(&slave->mutex); + return ret; +} + +static int snd_pcm_share_prepare(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + Pthread_mutex_lock(&slave->mutex); + switch (share->state) { + case SND_PCM_STATE_OPEN: + err = -EBADFD; + goto _end; + case SND_PCM_STATE_RUNNING: + err = -EBUSY; + goto _end; + case SND_PCM_STATE_PREPARED: + err = 0; + goto _end; + default: /* nothing todo */ + break; + } + if (slave->prepared_count == 0) { + err = snd_pcm_prepare(slave->pcm); + if (err < 0) + goto _end; + } + slave->prepared_count++; + share->hw_ptr = 0; + share->appl_ptr = 0; + share->state = SND_PCM_STATE_PREPARED; + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_reset(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + /* FIXME? */ + Pthread_mutex_lock(&slave->mutex); + snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format); + share->hw_ptr = *slave->pcm->hw.ptr; + share->appl_ptr = share->hw_ptr; + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_start(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_t *spcm = slave->pcm; + int err = 0; + if (share->state != SND_PCM_STATE_PREPARED) + return -EBADFD; + Pthread_mutex_lock(&slave->mutex); + share->state = SND_PCM_STATE_RUNNING; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + snd_pcm_uframes_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm); + snd_pcm_uframes_t xfer = 0; + if (hw_avail == 0) { + err = -EPIPE; + goto _end; + } + if (slave->running_count) { + snd_pcm_sframes_t sd; + err = snd_pcm_delay(spcm, &sd); + if (err < 0) + goto _end; + err = snd_pcm_rewind(spcm, sd); + if (err < 0) + goto _end; + } + assert(share->hw_ptr == 0); + share->hw_ptr = *spcm->hw.ptr; + share->appl_ptr = *spcm->appl.ptr; + while (xfer < hw_avail) { + snd_pcm_uframes_t frames = hw_avail - xfer; + snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm); + snd_pcm_uframes_t cont = pcm->buffer_size - offset; + if (cont < frames) + frames = cont; + if (pcm->stopped_areas != NULL) + snd_pcm_areas_copy(pcm->running_areas, offset, + pcm->stopped_areas, xfer, + pcm->channels, frames, + pcm->format); + xfer += frames; + } + snd_pcm_mmap_appl_forward(pcm, hw_avail); + if (slave->running_count == 0) { + snd_pcm_sframes_t res; + res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail); + if (res < 0) { + err = res; + goto _end; + } + assert((snd_pcm_uframes_t)res == hw_avail); + } + } + if (slave->running_count == 0) { + err = snd_pcm_start(spcm); + if (err < 0) + goto _end; + } + slave->running_count++; + _snd_pcm_share_update(pcm); + gettimestamp(&share->trigger_tstamp, pcm->monotonic); + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +static int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + unsigned int channel = info->channel; + int c = share->slave_channels[channel]; + int err; + info->channel = c; + err = snd_pcm_channel_info(slave->pcm, info); + info->channel = channel; + return err; +} + +static snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t n; + switch (share->state) { + case SND_PCM_STATE_RUNNING: + break; + case SND_PCM_STATE_PREPARED: + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return -EBADFD; + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream != SND_PCM_STREAM_CAPTURE) + return -EBADFD; + break; + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } + n = snd_pcm_mmap_hw_avail(pcm); + assert(n >= 0); + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { + snd_pcm_sframes_t ret = snd_pcm_rewind(slave->pcm, frames); + if (ret < 0) + return ret; + frames = ret; + } + snd_pcm_mmap_appl_backward(pcm, frames); + _snd_pcm_share_update(pcm); + return n; +} + +static snd_pcm_sframes_t snd_pcm_share_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t ret; + Pthread_mutex_lock(&slave->mutex); + ret = snd_pcm_rewindable(slave->pcm); + Pthread_mutex_unlock(&slave->mutex); + return ret; +} + +static snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t ret; + Pthread_mutex_lock(&slave->mutex); + ret = _snd_pcm_share_rewind(pcm, frames); + Pthread_mutex_unlock(&slave->mutex); + return ret; +} + +static snd_pcm_sframes_t _snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t n; + switch (share->state) { + case SND_PCM_STATE_RUNNING: + break; + case SND_PCM_STATE_PREPARED: + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return -EBADFD; + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream != SND_PCM_STREAM_CAPTURE) + return -EBADFD; + break; + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } + n = snd_pcm_mmap_avail(pcm); + if ((snd_pcm_uframes_t)n > frames) + frames = n; + if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { + snd_pcm_sframes_t ret = INTERNAL(snd_pcm_forward)(slave->pcm, frames); + if (ret < 0) + return ret; + frames = ret; + } + snd_pcm_mmap_appl_forward(pcm, frames); + _snd_pcm_share_update(pcm); + return n; +} + +static snd_pcm_sframes_t snd_pcm_share_forwardable(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t ret; + Pthread_mutex_lock(&slave->mutex); + ret = snd_pcm_forwardable(slave->pcm); + Pthread_mutex_unlock(&slave->mutex); + return ret; +} + +static snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + snd_pcm_sframes_t ret; + Pthread_mutex_lock(&slave->mutex); + ret = _snd_pcm_share_forward(pcm, frames); + Pthread_mutex_unlock(&slave->mutex); + return ret; +} + +/* Warning: take the mutex before to call this */ +static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; +#if 0 + if (!pcm->mmap_channels) { + /* PCM closing already begun in the main thread */ + return; + } +#endif + gettimestamp(&share->trigger_tstamp, pcm->monotonic); + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + snd_pcm_areas_copy(pcm->stopped_areas, 0, + pcm->running_areas, 0, + pcm->channels, pcm->buffer_size, + pcm->format); + } else if (slave->running_count > 1) { + int err; + snd_pcm_sframes_t delay; + snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, + pcm->buffer_size, pcm->format); + err = snd_pcm_delay(slave->pcm, &delay); + if (err >= 0 && delay > 0) + snd_pcm_rewind(slave->pcm, delay); + share->drain_silenced = 0; + } + share->state = state; + slave->prepared_count--; + slave->running_count--; + if (slave->running_count == 0) { + int err = snd_pcm_drop(slave->pcm); + assert(err >= 0); + } +} + +static int snd_pcm_share_drain(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + Pthread_mutex_lock(&slave->mutex); + switch (share->state) { + case SND_PCM_STATE_OPEN: + err = -EBADFD; + goto _end; + case SND_PCM_STATE_PREPARED: + share->state = SND_PCM_STATE_SETUP; + goto _end; + case SND_PCM_STATE_SETUP: + goto _end; + default: + break; + } + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + switch (share->state) { + case SND_PCM_STATE_XRUN: + share->state = SND_PCM_STATE_SETUP; + goto _end; + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_RUNNING: + share->state = SND_PCM_STATE_DRAINING; + _snd_pcm_share_update(pcm); + Pthread_mutex_unlock(&slave->mutex); + if (!(pcm->mode & SND_PCM_NONBLOCK)) + snd_pcm_wait(pcm, -1); + return 0; + default: + assert(0); + break; + } + } else { + switch (share->state) { + case SND_PCM_STATE_RUNNING: + _snd_pcm_share_stop(pcm, SND_PCM_STATE_DRAINING); + _snd_pcm_share_update(pcm); + /* Fall through */ + case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_DRAINING: + if (snd_pcm_mmap_capture_avail(pcm) <= 0) + share->state = SND_PCM_STATE_SETUP; + else + share->state = SND_PCM_STATE_DRAINING; + break; + default: + assert(0); + break; + } + } + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_drop(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + Pthread_mutex_lock(&slave->mutex); + switch (share->state) { + case SND_PCM_STATE_OPEN: + err = -EBADFD; + goto _end; + case SND_PCM_STATE_SETUP: + break; + case SND_PCM_STATE_DRAINING: + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + share->state = SND_PCM_STATE_SETUP; + break; + } + /* Fall through */ + case SND_PCM_STATE_RUNNING: + _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP); + _snd_pcm_share_update(pcm); + break; + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_XRUN: + share->state = SND_PCM_STATE_SETUP; + break; + default: + assert(0); + break; + } + + share->appl_ptr = share->hw_ptr = 0; + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +} + +static int snd_pcm_share_close(snd_pcm_t *pcm) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + int err = 0; + + Pthread_mutex_lock(&snd_pcm_share_slaves_mutex); + Pthread_mutex_lock(&slave->mutex); + slave->open_count--; + if (slave->open_count == 0) { + pthread_cond_signal(&slave->poll_cond); + Pthread_mutex_unlock(&slave->mutex); + err = pthread_join(slave->thread, 0); + assert(err == 0); + err = snd_pcm_close(slave->pcm); + pthread_mutex_destroy(&slave->mutex); + pthread_cond_destroy(&slave->poll_cond); + list_del(&slave->list); + free(slave); + list_del(&share->list); + } else { + list_del(&share->list); + Pthread_mutex_unlock(&slave->mutex); + } + Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); + close(share->client_socket); + close(share->slave_socket); + free(share->slave_channels); + free(share); + return err; +} + +static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static void snd_pcm_share_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_share_t *share = pcm->private_data; + snd_pcm_share_slave_t *slave = share->slave; + unsigned int k; + snd_output_printf(out, "Share PCM\n"); + snd_output_printf(out, " Channel bindings:\n"); + for (k = 0; k < share->channels; ++k) + snd_output_printf(out, " %d: %d\n", k, share->slave_channels[k]); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(slave->pcm, out); +} + +static const snd_pcm_ops_t snd_pcm_share_ops = { + .close = snd_pcm_share_close, + .info = snd_pcm_share_info, + .hw_refine = snd_pcm_share_hw_refine, + .hw_params = snd_pcm_share_hw_params, + .hw_free = snd_pcm_share_hw_free, + .sw_params = snd_pcm_share_sw_params, + .channel_info = snd_pcm_share_channel_info, + .dump = snd_pcm_share_dump, + .nonblock = snd_pcm_share_nonblock, + .async = snd_pcm_share_async, + .mmap = snd_pcm_share_mmap, + .munmap = snd_pcm_share_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { + .status = snd_pcm_share_status, + .state = snd_pcm_share_state, + .hwsync = snd_pcm_share_hwsync, + .delay = snd_pcm_share_delay, + .prepare = snd_pcm_share_prepare, + .reset = snd_pcm_share_reset, + .start = snd_pcm_share_start, + .drop = snd_pcm_share_drop, + .drain = snd_pcm_share_drain, + .pause = snd_pcm_share_pause, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_mmap_readi, + .readn = snd_pcm_mmap_readn, + .rewindable = snd_pcm_share_rewindable, + .rewind = snd_pcm_share_rewind, + .forwardable = snd_pcm_share_forwardable, + .forward = snd_pcm_share_forward, + .resume = snd_pcm_share_resume, + .avail_update = snd_pcm_share_avail_update, + .htimestamp = snd_pcm_share_htimestamp, + .mmap_commit = snd_pcm_share_mmap_commit, +}; + +/** + * \brief Creates a new Share PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sname Slave name + * \param sformat Slave format + * \param srate Slave rate + * \param schannels Slave channels + * \param speriod_time Slave period time + * \param sbuffer_time Slave buffer time + * \param channels Count of channels + * \param channels_map Map of channels + * \param stream Direction + * \param mode PCM mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, + snd_pcm_format_t sformat, int srate, + unsigned int schannels, + int speriod_time, int sbuffer_time, + unsigned int channels, unsigned int *channels_map, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm; + snd_pcm_share_t *share; + int err; + struct list_head *i; + char slave_map[32] = { 0 }; + unsigned int k; + snd_pcm_share_slave_t *slave = NULL; + int sd[2]; + + assert(pcmp); + assert(channels > 0 && sname && channels_map); + + for (k = 0; k < channels; ++k) { + if (channels_map[k] >= sizeof(slave_map) / sizeof(slave_map[0])) { + SNDERR("Invalid slave channel (%d) in binding", channels_map[k]); + return -EINVAL; + } + if (slave_map[channels_map[k]]) { + SNDERR("Repeated slave channel (%d) in binding", channels_map[k]); + return -EINVAL; + } + slave_map[channels_map[k]] = 1; + assert((unsigned)channels_map[k] < schannels); + } + + share = calloc(1, sizeof(snd_pcm_share_t)); + if (!share) + return -ENOMEM; + + share->channels = channels; + share->slave_channels = calloc(channels, sizeof(*share->slave_channels)); + if (!share->slave_channels) { + free(share); + return -ENOMEM; + } + memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels)); + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHARE, name, stream, mode); + if (err < 0) { + free(share->slave_channels); + free(share); + return err; + } + err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sd); + if (err < 0) { + snd_pcm_free(pcm); + free(share->slave_channels); + free(share); + return -errno; + } + + if (stream == SND_PCM_STREAM_PLAYBACK) { + int bufsize = 1; + err = setsockopt(sd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); + if (err >= 0) { + struct pollfd pfd; + pfd.fd = sd[0]; + pfd.events = POLLOUT; + while ((err = poll(&pfd, 1, 0)) == 1) { + char buf[1]; + err = write(sd[0], buf, 1); + assert(err != 0); + if (err != 1) + break; + } + } + } + if (err < 0) { + err = -errno; + close(sd[0]); + close(sd[1]); + snd_pcm_free(pcm); + free(share->slave_channels); + free(share); + return err; + } + + Pthread_mutex_lock(&snd_pcm_share_slaves_mutex); + list_for_each(i, &snd_pcm_share_slaves) { + snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list); + if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) { + slave = s; + break; + } + } + if (!slave) { + snd_pcm_t *spcm; + err = snd_pcm_open(&spcm, sname, stream, mode); + if (err < 0) { + Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); + close(sd[0]); + close(sd[1]); + snd_pcm_free(pcm); + free(share->slave_channels); + free(share); + return err; + } + /* FIXME: bellow is a real ugly hack to get things working */ + /* there is a memory leak somewhere, but I'm unable to trace it --jk */ + slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8); + if (!slave) { + Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); + snd_pcm_close(spcm); + close(sd[0]); + close(sd[1]); + snd_pcm_free(pcm); + free(share->slave_channels); + free(share); + return err; + } + INIT_LIST_HEAD(&slave->clients); + slave->pcm = spcm; + slave->channels = schannels; + slave->format = sformat; + slave->rate = srate; + slave->period_time = speriod_time; + slave->buffer_time = sbuffer_time; + pthread_mutex_init(&slave->mutex, NULL); + pthread_cond_init(&slave->poll_cond, NULL); + list_add_tail(&slave->list, &snd_pcm_share_slaves); + Pthread_mutex_lock(&slave->mutex); + err = pthread_create(&slave->thread, NULL, snd_pcm_share_thread, slave); + assert(err == 0); + Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); + } else { + Pthread_mutex_lock(&slave->mutex); + Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); + list_for_each(i, &slave->clients) { + snd_pcm_share_t *sh = list_entry(i, snd_pcm_share_t, list); + for (k = 0; k < sh->channels; ++k) { + if (slave_map[sh->slave_channels[k]]) { + SNDERR("Slave channel %d is already in use", sh->slave_channels[k]); + Pthread_mutex_unlock(&slave->mutex); + close(sd[0]); + close(sd[1]); + snd_pcm_free(pcm); + free(share->slave_channels); + free(share); + return -EBUSY; + } + } + } + } + + share->slave = slave; + share->pcm = pcm; + share->client_socket = sd[0]; + share->slave_socket = sd[1]; + + pcm->mmap_rw = 1; + pcm->ops = &snd_pcm_share_ops; + pcm->fast_ops = &snd_pcm_share_fast_ops; + pcm->private_data = share; + pcm->poll_fd = share->client_socket; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; + pcm->monotonic = slave->pcm->monotonic; + snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0); + + slave->open_count++; + list_add_tail(&share->list, &slave->clients); + + Pthread_mutex_unlock(&slave->mutex); + + *pcmp = pcm; + return 0; +} + +/*! \page pcm_plugins + +\section pcm_plugins_share Plugin: Share + +This plugin allows sharing of multiple channels with more clients. The access +to each channel is exlusive (samples are not mixed together). It means, if +the channel zero is used with first client, the channel cannot be used with +second one. If you are looking for a mixing plugin, use the +\ref pcm_plugins_dmix "dmix plugin". + +The difference from \ref pcm_plugins_dshare "dshare plugin" is that +share plugin requires the server program "aserver", while dshare plugin +doesn't need the explicit server but access to the shared buffer. + +\code +pcm.name { + type share # Share PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + [format STR] # Slave format + [channels INT] # Slave channels + [rate INT] # Slave rate + [period_time INT] # Slave period time in us + [buffer_time INT] # Slave buffer time in us + } + bindings { + N INT # Slave channel INT for client channel N + } +} +\endcode + +\subsection pcm_plugins_share_funcref Function reference + +
    +
  • snd_pcm_share_open() +
  • _snd_pcm_share_open() +
+ +*/ + +/** + * \brief Creates a new Share PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Share PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + const char *sname = NULL; + snd_config_t *bindings = NULL; + int err; + snd_config_t *slave = NULL, *sconf; + unsigned int *channels_map = NULL; + unsigned int channels = 0; + snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; + int schannels = -1; + int srate = -1; + int speriod_time= -1, sbuffer_time = -1; + unsigned int schannel_max = 0; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "bindings") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + bindings = n; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + err = snd_pcm_slave_conf(root, slave, &sconf, 5, + SND_PCM_HW_PARAM_FORMAT, 0, &sformat, + SND_PCM_HW_PARAM_CHANNELS, 0, &schannels, + SND_PCM_HW_PARAM_RATE, 0, &srate, + SND_PCM_HW_PARAM_PERIOD_TIME, 0, &speriod_time, + SND_PCM_HW_PARAM_BUFFER_TIME, 0, &sbuffer_time); + if (err < 0) + return err; + + /* FIXME: nothing strictly forces to have named definition */ + err = snd_config_get_string(sconf, &sname); + sname = err >= 0 && sname ? strdup(sname) : NULL; + snd_config_delete(sconf); + if (sname == NULL) { + SNDERR("slave.pcm is not a string"); + return err; + } + + if (!bindings) { + SNDERR("bindings is not defined"); + err = -EINVAL; + goto _free; + } + snd_config_for_each(i, next, bindings) { + long cchannel = -1; + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0 || cchannel < 0) { + SNDERR("Invalid client channel in binding: %s", id); + err = -EINVAL; + goto _free; + } + if ((unsigned)cchannel >= channels) + channels = cchannel + 1; + } + if (channels == 0) { + SNDERR("No bindings defined"); + err = -EINVAL; + goto _free; + } + channels_map = calloc(channels, sizeof(*channels_map)); + if (! channels_map) { + err = -ENOMEM; + goto _free; + } + + snd_config_for_each(i, next, bindings) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + long cchannel; + long schannel = -1; + if (snd_config_get_id(n, &id) < 0) + continue; + cchannel = atoi(id); + err = snd_config_get_integer(n, &schannel); + if (err < 0) { + goto _free; + } + assert(schannel >= 0); + assert(schannels <= 0 || schannel < schannels); + channels_map[cchannel] = schannel; + if ((unsigned)schannel > schannel_max) + schannel_max = schannel; + } + if (schannels <= 0) + schannels = schannel_max + 1; + err = snd_pcm_share_open(pcmp, name, sname, sformat, srate, + (unsigned int) schannels, + speriod_time, sbuffer_time, + channels, channels_map, stream, mode); +_free: + free(channels_map); + free((char *)sname); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_share_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c new file mode 100644 index 0000000..69d0524 --- /dev/null +++ b/src/pcm/pcm_shm.c @@ -0,0 +1,956 @@ +/** + * \file pcm/pcm_shm.c + * \ingroup PCM_Plugins + * \brief PCM Shared Memory Plugin Interface + * \author Abramo Bagnara + * \date 2000-2001 + */ +/* + * PCM - Shared Memory Client + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aserver.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_shm = ""; +#endif + +#ifndef DOC_HIDDEN +typedef struct { + int socket; + volatile snd_pcm_shm_ctrl_t *ctrl; +} snd_pcm_shm_t; +#endif + +static long snd_pcm_shm_action_fd0(snd_pcm_t *pcm, int *fd) +{ + snd_pcm_shm_t *shm = pcm->private_data; + int err; + char buf[1]; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = snd_receive_fd(shm->socket, buf, 1, fd); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + SNDERR("Server has not done the cmd"); + return -EBADFD; + } + return ctrl->result; +} + +static int snd_pcm_shm_new_rbptr(snd_pcm_t *pcm, snd_pcm_shm_t *shm, + snd_pcm_rbptr_t *rbptr, volatile snd_pcm_shm_rbptr_t *shm_rbptr) +{ + if (!shm_rbptr->use_mmap) { + if (&pcm->hw == rbptr) + snd_pcm_set_hw_ptr(pcm, &shm_rbptr->ptr, -1, 0); + else + snd_pcm_set_appl_ptr(pcm, &shm_rbptr->ptr, -1, 0); + } else { + void *ptr; + size_t mmap_size, mmap_offset, offset; + int fd; + long result; + + shm->ctrl->cmd = &pcm->hw == rbptr ? SND_PCM_IOCTL_HW_PTR_FD : SND_PCM_IOCTL_APPL_PTR_FD; + result = snd_pcm_shm_action_fd0(pcm, &fd); + if (result < 0) + return result; + mmap_size = page_ptr(shm_rbptr->offset, sizeof(snd_pcm_uframes_t), &offset, &mmap_offset); + ptr = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, mmap_offset); + if (ptr == MAP_FAILED || ptr == NULL) { + SYSERR("shm rbptr mmap failed"); + return -errno; + } + if (&pcm->hw == rbptr) + snd_pcm_set_hw_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset); + else + snd_pcm_set_appl_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset); + } + return 0; +} + +static long snd_pcm_shm_action(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + int err, result; + char buf[1]; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + + if (ctrl->hw.changed || ctrl->appl.changed) + return -EBADFD; + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = read(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + SNDERR("Server has not done the cmd"); + return -EBADFD; + } + result = ctrl->result; + if (ctrl->hw.changed) { + err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw); + if (err < 0) + return err; + ctrl->hw.changed = 0; + } + if (ctrl->appl.changed) { + err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl); + if (err < 0) + return err; + ctrl->appl.changed = 0; + } + return result; +} + +static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd) +{ + snd_pcm_shm_t *shm = pcm->private_data; + int err; + char buf[1]; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + + if (ctrl->hw.changed || ctrl->appl.changed) + return -EBADFD; + err = write(shm->socket, buf, 1); + if (err != 1) + return -EBADFD; + err = snd_receive_fd(shm->socket, buf, 1, fd); + if (err != 1) + return -EBADFD; + if (ctrl->cmd) { + SNDERR("Server has not done the cmd"); + return -EBADFD; + } + if (ctrl->hw.changed) { + err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw); + if (err < 0) + return err; + ctrl->hw.changed = 0; + } + if (ctrl->appl.changed) { + err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl); + if (err < 0) + return err; + ctrl->appl.changed = 0; + } + return ctrl->result; +} + +static int snd_pcm_shm_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_shm_async(snd_pcm_t *pcm, int sig, pid_t pid) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_PCM_IOCTL_ASYNC; + ctrl->u.async.sig = sig; + ctrl->u.async.pid = pid; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; +// ctrl->u.info = *info; + ctrl->cmd = SNDRV_PCM_IOCTL_INFO; + err = snd_pcm_shm_action(pcm); + if (err < 0) + return err; + *info = ctrl->u.info; + return err; +} + +static int snd_pcm_shm_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_shm_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + return 0; +} + +static int snd_pcm_shm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); + if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && + !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) { + err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + access_mask); + if (err < 0) + return err; + } + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_shm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + int err; + unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS; + snd_pcm_access_mask_t access_mask; + snd_mask_copy(&access_mask, snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS)); + snd_pcm_access_mask_set(&access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_access_mask_set(&access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); + err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + return 0; +} + +static int snd_pcm_shm_hw_refine_slave(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->u.hw_refine = *params; + ctrl->cmd = SNDRV_PCM_IOCTL_HW_REFINE; + err = snd_pcm_shm_action(pcm); + *params = ctrl->u.hw_refine; + return err; +} + +static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_shm_hw_refine_cprepare, + snd_pcm_shm_hw_refine_cchange, + snd_pcm_shm_hw_refine_sprepare, + snd_pcm_shm_hw_refine_schange, + snd_pcm_shm_hw_refine_slave); +} + +static int snd_pcm_shm_hw_params_slave(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + params->flags |= SND_PCM_HW_PARAMS_EXPORT_BUFFER; + ctrl->cmd = SNDRV_PCM_IOCTL_HW_PARAMS; + ctrl->u.hw_params = *params; + err = snd_pcm_shm_action(pcm); + *params = ctrl->u.hw_params; + return err; +} + +static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + return snd_pcm_hw_params_slave(pcm, params, + snd_pcm_shm_hw_refine_cchange, + snd_pcm_shm_hw_refine_sprepare, + snd_pcm_shm_hw_refine_schange, + snd_pcm_shm_hw_params_slave); +} + +static int snd_pcm_shm_hw_free(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_HW_FREE; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SNDRV_PCM_IOCTL_SW_PARAMS; + ctrl->u.sw_params = *params; + err = snd_pcm_shm_action(pcm); + *params = ctrl->u.sw_params; + if (err < 0) + return err; + return err; +} + +static int snd_pcm_shm_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_pcm_shm_munmap(snd_pcm_t *pcm) +{ + unsigned int c; + for (c = 0; c < pcm->channels; ++c) { + snd_pcm_channel_info_t *i = &pcm->mmap_channels[c]; + unsigned int c1; + int err; + if (i->type != SND_PCM_AREA_MMAP) + continue; + if (i->u.mmap.fd < 0) + continue; + for (c1 = c + 1; c1 < pcm->channels; ++c1) { + snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; + if (i1->type != SND_PCM_AREA_MMAP) + continue; + if (i1->u.mmap.fd != i->u.mmap.fd) + continue; + i1->u.mmap.fd = -1; + } + err = close(i->u.mmap.fd); + if (err < 0) { + SYSERR("close failed"); + return -errno; + } + } + return 0; +} + +static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + int fd; + ctrl->cmd = SNDRV_PCM_IOCTL_CHANNEL_INFO; + ctrl->u.channel_info = *info; + err = snd_pcm_shm_action_fd(pcm, &fd); + if (err < 0) + return err; + *info = ctrl->u.channel_info; + info->addr = 0; + switch (info->type) { + case SND_PCM_AREA_MMAP: + info->u.mmap.fd = fd; + break; + case SND_PCM_AREA_SHM: + break; + default: + assert(0); + break; + } + return err; +} + +static int snd_pcm_shm_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SNDRV_PCM_IOCTL_STATUS; + // ctrl->u.status = *status; + err = snd_pcm_shm_action(pcm); + if (err < 0) + return err; + *status = ctrl->u.status; + return err; +} + +static snd_pcm_state_t snd_pcm_shm_state(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_PCM_IOCTL_STATE; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_PCM_IOCTL_HWSYNC; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SNDRV_PCM_IOCTL_DELAY; + err = snd_pcm_shm_action(pcm); + if (err < 0) + return err; + *delayp = ctrl->u.delay.frames; + return err; +} + +static snd_pcm_sframes_t snd_pcm_shm_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + ctrl->cmd = SND_PCM_IOCTL_AVAIL_UPDATE; + err = snd_pcm_shm_action(pcm); + if (err < 0) + return err; + return err; +} + +static int snd_pcm_shm_htimestamp(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + snd_pcm_uframes_t *avail ATTRIBUTE_UNUSED, + snd_htimestamp_t *tstamp ATTRIBUTE_UNUSED) +{ + return -EIO; /* not implemented yet */ +} + +static int snd_pcm_shm_prepare(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_PREPARE; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_reset(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_RESET; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_start(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_START; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_drop(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_DROP; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_drain(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int err; + do { + ctrl->cmd = SNDRV_PCM_IOCTL_DRAIN; + err = snd_pcm_shm_action(pcm); + if (err != -EAGAIN) + break; + usleep(10000); + } while (1); + if (err < 0) + return err; + if (!(pcm->mode & SND_PCM_NONBLOCK)) + snd_pcm_wait(pcm, -1); + return err; +} + +static int snd_pcm_shm_pause(snd_pcm_t *pcm, int enable) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_PAUSE; + ctrl->u.pause.enable = enable; + return snd_pcm_shm_action(pcm); +} + +static snd_pcm_sframes_t snd_pcm_shm_rewindable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; /* FIX ME */ +} + +static snd_pcm_sframes_t snd_pcm_shm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_REWIND; + ctrl->u.rewind.frames = frames; + return snd_pcm_shm_action(pcm); +} + +static snd_pcm_sframes_t snd_pcm_shm_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; /* FIX ME */ +} + +static snd_pcm_sframes_t snd_pcm_shm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_PCM_IOCTL_FORWARD; + ctrl->u.forward.frames = frames; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_resume(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SNDRV_PCM_IOCTL_RESUME; + return snd_pcm_shm_action(pcm); +} + +static snd_pcm_sframes_t snd_pcm_shm_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + ctrl->cmd = SND_PCM_IOCTL_MMAP_COMMIT; + ctrl->u.mmap_commit.offset = offset; + ctrl->u.mmap_commit.frames = size; + return snd_pcm_shm_action(pcm); +} + +static int snd_pcm_shm_poll_descriptor(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int fd, err; + ctrl->cmd = SND_PCM_IOCTL_POLL_DESCRIPTOR; + err = snd_pcm_shm_action_fd(pcm, &fd); + if (err < 0) + return err; + return fd; +} + +static int snd_pcm_shm_close(snd_pcm_t *pcm) +{ + snd_pcm_shm_t *shm = pcm->private_data; + volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; + int result; + ctrl->cmd = SND_PCM_IOCTL_CLOSE; + result = snd_pcm_shm_action(pcm); + shmdt((void *)ctrl); + close(shm->socket); + close(pcm->poll_fd); + free(shm); + return result; +} + +static void snd_pcm_shm_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_output_printf(out, "Shm PCM\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } +} + +static const snd_pcm_ops_t snd_pcm_shm_ops = { + .close = snd_pcm_shm_close, + .info = snd_pcm_shm_info, + .hw_refine = snd_pcm_shm_hw_refine, + .hw_params = snd_pcm_shm_hw_params, + .hw_free = snd_pcm_shm_hw_free, + .sw_params = snd_pcm_shm_sw_params, + .channel_info = snd_pcm_shm_channel_info, + .dump = snd_pcm_shm_dump, + .nonblock = snd_pcm_shm_nonblock, + .async = snd_pcm_shm_async, + .mmap = snd_pcm_shm_mmap, + .munmap = snd_pcm_shm_munmap, +}; + +static const snd_pcm_fast_ops_t snd_pcm_shm_fast_ops = { + .status = snd_pcm_shm_status, + .state = snd_pcm_shm_state, + .hwsync = snd_pcm_shm_hwsync, + .delay = snd_pcm_shm_delay, + .prepare = snd_pcm_shm_prepare, + .reset = snd_pcm_shm_reset, + .start = snd_pcm_shm_start, + .drop = snd_pcm_shm_drop, + .drain = snd_pcm_shm_drain, + .pause = snd_pcm_shm_pause, + .rewindable = snd_pcm_shm_rewindable, + .rewind = snd_pcm_shm_rewind, + .forwardable = snd_pcm_shm_forwardable, + .forward = snd_pcm_shm_forward, + .resume = snd_pcm_shm_resume, + .writei = snd_pcm_mmap_writei, + .writen = snd_pcm_mmap_writen, + .readi = snd_pcm_mmap_readi, + .readn = snd_pcm_mmap_readn, + .avail_update = snd_pcm_shm_avail_update, + .mmap_commit = snd_pcm_shm_mmap_commit, + .htimestamp = snd_pcm_shm_htimestamp, +}; + +static int make_local_socket(const char *filename) +{ + size_t l = strlen(filename); + size_t size = offsetof(struct sockaddr_un, sun_path) + l; + struct sockaddr_un *addr = alloca(size); + int sock; + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) { + SYSERR("socket failed"); + return -errno; + } + + addr->sun_family = AF_LOCAL; + memcpy(addr->sun_path, filename, l); + + if (connect(sock, (struct sockaddr *) addr, size) < 0) { + SYSERR("connect failed"); + return -errno; + } + return sock; +} + +#if 0 +static int make_inet_socket(const char *host, int port) +{ + struct sockaddr_in addr; + int sock; + struct hostent *h = gethostbyname(host); + if (!h) + return -ENOENT; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + SYSERR("socket failed"); + return -errno; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr)); + + if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + SYSERR("connect failed"); + return -errno; + } + return sock; +} +#endif + +/** + * \brief Creates a new shared memory PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sockname Unix socket name + * \param sname Server name + * \param stream PCM Stream + * \param mode PCM Mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name, + const char *sockname, const char *sname, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm; + snd_pcm_shm_t *shm = NULL; + snd_client_open_request_t *req; + snd_client_open_answer_t ans; + size_t snamelen, reqlen; + int err; + int result; + snd_pcm_shm_ctrl_t *ctrl = NULL; + int sock = -1; + snamelen = strlen(sname); + if (snamelen > 255) + return -EINVAL; + + result = make_local_socket(sockname); + if (result < 0) { + SNDERR("server for socket %s is not running", sockname); + goto _err; + } + sock = result; + + reqlen = sizeof(*req) + snamelen; + req = alloca(reqlen); + memcpy(req->name, sname, snamelen); + req->dev_type = SND_DEV_TYPE_PCM; + req->transport_type = SND_TRANSPORT_TYPE_SHM; + req->stream = stream; + req->mode = mode; + req->namelen = snamelen; + err = write(sock, req, reqlen); + if (err < 0) { + SYSERR("write error"); + result = -errno; + goto _err; + } + if ((size_t) err != reqlen) { + SNDERR("write size error"); + result = -EINVAL; + goto _err; + } + err = read(sock, &ans, sizeof(ans)); + if (err < 0) { + SYSERR("read error"); + result = -errno; + goto _err; + } + if (err != sizeof(ans)) { + SNDERR("read size error"); + result = -EINVAL; + goto _err; + } + result = ans.result; + if (result < 0) + goto _err; + + ctrl = shmat(ans.cookie, 0, 0); + if (!ctrl) { + SYSERR("shmat error"); + result = -errno; + goto _err; + } + + shm = calloc(1, sizeof(snd_pcm_shm_t)); + if (!shm) { + result = -ENOMEM; + goto _err; + } + + shm->socket = sock; + shm->ctrl = ctrl; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHM, name, stream, mode); + if (err < 0) { + result = err; + goto _err; + } + pcm->mmap_rw = 1; + pcm->ops = &snd_pcm_shm_ops; + pcm->fast_ops = &snd_pcm_shm_fast_ops; + pcm->private_data = shm; + err = snd_pcm_shm_poll_descriptor(pcm); + if (err < 0) { + snd_pcm_close(pcm); + return err; + } + pcm->poll_fd = err; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; + snd_pcm_set_hw_ptr(pcm, &ctrl->hw.ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0); + *pcmp = pcm; + return 0; + + _err: + close(sock); + if (ctrl) + shmdt(ctrl); + free(shm); + return result; +} + +/*! \page pcm_plugins + +\section pcm_plugins_shm Plugin: shm + +This plugin communicates with aserver via shared memory. It is a raw +communication without any conversions, but it can be expected worse +performance. + +\code +pcm.name { + type shm # Shared memory PCM + server STR # Server name + pcm STR # PCM name +} +\endcode + +\subsection pcm_plugins_shm_funcref Function reference + +
    +
  • snd_pcm_shm_open() +
  • _snd_pcm_shm_open() +
+ +*/ + +/** + * \brief Creates a new shm PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with hw PCM description + * \param stream PCM Stream + * \param mode PCM Mode + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + const char *server = NULL; + const char *pcm_name = NULL; + snd_config_t *sconfig; + const char *host = NULL; + const char *sockname = NULL; + long port = -1; + int err; + int local; + struct hostent *h; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "server") == 0) { + err = snd_config_get_string(n, &server); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "pcm") == 0) { + err = snd_config_get_string(n, &pcm_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!pcm_name) { + SNDERR("pcm is not defined"); + return -EINVAL; + } + if (!server) { + SNDERR("server is not defined"); + return -EINVAL; + } + err = snd_config_search_definition(root, "server", server, &sconfig); + if (err < 0) { + SNDERR("Unknown server %s", server); + return -EINVAL; + } + if (snd_config_get_type(sconfig) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for server %s definition", server); + goto _err; + } + snd_config_for_each(i, next, sconfig) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "host") == 0) { + err = snd_config_get_string(n, &host); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "socket") == 0) { + err = snd_config_get_string(n, &sockname); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "port") == 0) { + err = snd_config_get_integer(n, &port); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + _err: + err = -EINVAL; + goto __error; + } + + if (!host) { + SNDERR("host is not defined"); + goto _err; + } + if (!sockname) { + SNDERR("socket is not defined"); + goto _err; + } + h = gethostbyname(host); + if (!h) { + SNDERR("Cannot resolve %s", host); + goto _err; + } + local = snd_is_local(h); + if (!local) { + SNDERR("%s is not the local host", host); + goto _err; + } + err = snd_pcm_shm_open(pcmp, name, sockname, pcm_name, stream, mode); + __error: + snd_config_delete(sconfig); + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_shm_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_simple.c b/src/pcm/pcm_simple.c new file mode 100644 index 0000000..975f699 --- /dev/null +++ b/src/pcm/pcm_simple.c @@ -0,0 +1,305 @@ +/** + * \file pcm/pcm_simple.c + * \ingroup PCM_Simple + * \brief PCM Simple Interface + * \author Jaroslav Kysela + * \date 2004 + */ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "pcm_local.h" + +static int set_buffer_time(snd_spcm_latency_t latency, + unsigned int *buffer_time) +{ + switch (latency) { + case SND_SPCM_LATENCY_STANDARD: + *buffer_time = 350000; + break; + case SND_SPCM_LATENCY_MEDIUM: + *buffer_time = 25000; + break; + case SND_SPCM_LATENCY_REALTIME: + *buffer_time = 2500; + break; + default: + return -EINVAL; + } + return 0; +} + +static int set_hw_params(snd_pcm_t *pcm, + snd_pcm_hw_params_t *hw_params, + unsigned int *rate, + unsigned int channels, + snd_pcm_format_t format, + snd_pcm_subformat_t subformat, + unsigned int *buffer_time, + unsigned int *period_time, + snd_pcm_access_t access) +{ + int err; + + /* + * hardware parameters + */ + err = snd_pcm_hw_params_any(pcm, hw_params); + if (err < 0) + return err; + err = snd_pcm_hw_params_set_access(pcm, hw_params, access); + if (err < 0) + return err; + err = snd_pcm_hw_params_set_format(pcm, hw_params, format); + if (err < 0) + return err; + if (subformat != SND_PCM_SUBFORMAT_STD) { + err = snd_pcm_hw_params_set_subformat(pcm, hw_params, subformat); + if (err < 0) + return err; + } + err = snd_pcm_hw_params_set_channels(pcm, hw_params, channels); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, 0); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, hw_params, buffer_time, NULL); + if (err < 0) + return err; + if (period_time == NULL || *period_time == 0) { + unsigned int periods = 3; + err = INTERNAL(snd_pcm_hw_params_set_periods_near)(pcm, hw_params, &periods, NULL); + if (err < 0) + return err; + if (periods == 1) + return -EINVAL; + if (*period_time == 0) { + err = INTERNAL(snd_pcm_hw_params_get_period_time)(hw_params, period_time, NULL); + if (err < 0) + return err; + } + } else { + err = snd_pcm_hw_params_set_period_time(pcm, hw_params, *period_time, 0); + if (err < 0) + return err; + if (*buffer_time == *period_time) + return -EINVAL; + } + err = snd_pcm_hw_params(pcm, hw_params); + if (err < 0) + return err; + return 0; +} + +static int set_sw_params(snd_pcm_t *pcm, + snd_pcm_sw_params_t *sw_params, + snd_spcm_xrun_type_t xrun_type) +{ + int err; + + err = snd_pcm_sw_params_current(pcm, sw_params); + if (err < 0) + return err; + err = snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (pcm->buffer_size / pcm->period_size) * pcm->period_size); + if (err < 0) + return err; + err = snd_pcm_sw_params_set_avail_min(pcm, sw_params, pcm->period_size); + if (err < 0) + return err; + switch (xrun_type) { + case SND_SPCM_XRUN_STOP: + err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->buffer_size); + break; + case SND_SPCM_XRUN_IGNORE: + err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->boundary); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + err = snd_pcm_sw_params(pcm, sw_params); + if (err < 0) + return err; + return 0; +} + +/** + * \brief Set up a simple PCM + * \param pcm PCM handle + * \param rate Sample rate + * \param channels Number of channels + * \param format PCM format + * \param subformat PCM subformat + * \param latency Latency type + * \param access PCM acceess type + * \param xrun_type XRUN type + * \return 0 if successful, or a negative error code + * + * \warning The simple PCM API may be broken in the current release. + */ +int snd_spcm_init(snd_pcm_t *pcm, + unsigned int rate, + unsigned int channels, + snd_pcm_format_t format, + snd_pcm_subformat_t subformat, + snd_spcm_latency_t latency, + snd_pcm_access_t access, + snd_spcm_xrun_type_t xrun_type) +{ + int err; + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + unsigned int rrate; + unsigned int buffer_time; + + snd_pcm_hw_params_alloca(&hw_params); + snd_pcm_sw_params_alloca(&sw_params); + + assert(pcm); + assert(rate > 5000 && rate < 192000); + assert(channels > 1 && channels < 512); + + rrate = rate; + err = set_buffer_time(latency, &buffer_time); + if (err < 0) + return err; + err = set_hw_params(pcm, hw_params, + &rrate, channels, format, subformat, + &buffer_time, NULL, access); + if (err < 0) + return err; + + err = set_sw_params(pcm, sw_params, xrun_type); + if (err < 0) + return err; + + return 0; +} + +/** + * \brief Initialize simple PCMs in the duplex mode + * \param playback_pcm PCM handle for playback + * \param capture_pcm PCM handle for capture + * \param rate Sample rate + * \param channels Number of channels + * \param format PCM format + * \param subformat PCM subformat + * \param latency Latency type + * \param access PCM acceess type + * \param xrun_type XRUN type + * \param duplex_type Duplex mode + * \return 0 if successful, or a negative error code + * + * \warning The simple PCM API may be broken in the current release. + */ +int snd_spcm_init_duplex(snd_pcm_t *playback_pcm, + snd_pcm_t *capture_pcm, + unsigned int rate, + unsigned int channels, + snd_pcm_format_t format, + snd_pcm_subformat_t subformat, + snd_spcm_latency_t latency, + snd_pcm_access_t access, + snd_spcm_xrun_type_t xrun_type, + snd_spcm_duplex_type_t duplex_type) +{ + int err, i; + snd_pcm_hw_params_t *hw_params; + snd_pcm_sw_params_t *sw_params; + unsigned int rrate; + unsigned int xbuffer_time, buffer_time[2]; + unsigned int period_time[2]; + snd_pcm_t *pcms[2]; + + snd_pcm_hw_params_alloca(&hw_params); + snd_pcm_sw_params_alloca(&sw_params); + + assert(playback_pcm); + assert(capture_pcm); + assert(rate > 5000 && rate < 192000); + assert(channels > 1 && channels < 512); + + pcms[0] = playback_pcm; + pcms[1] = capture_pcm; + + /* + * hardware parameters + */ + err = set_buffer_time(latency, &xbuffer_time); + if (err < 0) + return err; + + for (i = 0; i < 2; i++) { + buffer_time[i] = xbuffer_time; + period_time[i] = i > 0 ? period_time[0] : 0; + rrate = rate; + err = set_hw_params(pcms[i], hw_params, + &rrate, channels, format, subformat, + &buffer_time[i], &period_time[i], access); + if (err < 0) + return err; + } + if (buffer_time[0] == buffer_time[1] && + period_time[0] == period_time[1]) + goto __sw_params; + if (duplex_type == SND_SPCM_DUPLEX_LIBERAL) + goto __sw_params; + /* FIXME: */ + return -EINVAL; + + /* + * software parameters + */ + __sw_params: + for (i = 0; i < 2; i++) { + err = set_sw_params(pcms[i], sw_params, xrun_type); + if (err < 0) + return err; + } + + return 0; +} + +/** + * \brief Get the set up of simple PCM + * \param pcm PCM handle + * \param rate Pointer to store the current sample rate + * \param buffer_size Pointer to store the current buffer size + * \param period_size Pointer to store the current period size + * \return 0 if successful, or a negative error code + * + * \warning The simple PCM API may be broken in the current release. + */ +int snd_spcm_init_get_params(snd_pcm_t *pcm, + unsigned int *rate, + snd_pcm_uframes_t *buffer_size, + snd_pcm_uframes_t *period_size) +{ + assert(pcm); + if (!pcm->setup) + return -EBADFD; + if (rate) + *rate = pcm->rate; + if (buffer_size) + *buffer_size = pcm->buffer_size; + if (period_size) + *period_size = pcm->period_size; + return 0; +} diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c new file mode 100644 index 0000000..2c7c006 --- /dev/null +++ b/src/pcm/pcm_softvol.c @@ -0,0 +1,1100 @@ +/** + * \file pcm/pcm_softvol.c + * \ingroup PCM_Plugins + * \brief PCM Soft Volume Plugin Interface + * \author Takashi Iwai + * \date 2004 + */ +/* + * PCM - Soft Volume Plugin + * Copyright (c) 2004 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_pcm_softvol = ""; +#endif + +#ifndef DOC_HIDDEN + +typedef struct { + /* This field need to be the first */ + snd_pcm_plugin_t plug; + snd_pcm_format_t sformat; + unsigned int cchannels; + snd_ctl_t *ctl; + snd_ctl_elem_value_t elem; + unsigned int cur_vol[2]; + unsigned int max_val; /* max index */ + unsigned int zero_dB_val; /* index at 0 dB */ + double min_dB; + double max_dB; + unsigned int *dB_value; +} snd_pcm_softvol_t; + +#define VOL_SCALE_SHIFT 16 +#define VOL_SCALE_MASK ((1 << VOL_SCALE_SHIFT) - 1) + +#define PRESET_RESOLUTION 256 +#define PRESET_MIN_DB -51.0 +#define ZERO_DB 0.0 +#define MAX_DB_UPPER_LIMIT 50 + +static const unsigned int preset_dB_value[PRESET_RESOLUTION] = { + 0x00b8, 0x00bd, 0x00c1, 0x00c5, 0x00ca, 0x00cf, 0x00d4, 0x00d9, + 0x00de, 0x00e3, 0x00e8, 0x00ed, 0x00f3, 0x00f9, 0x00fe, 0x0104, + 0x010a, 0x0111, 0x0117, 0x011e, 0x0124, 0x012b, 0x0132, 0x0139, + 0x0140, 0x0148, 0x0150, 0x0157, 0x015f, 0x0168, 0x0170, 0x0179, + 0x0181, 0x018a, 0x0194, 0x019d, 0x01a7, 0x01b0, 0x01bb, 0x01c5, + 0x01cf, 0x01da, 0x01e5, 0x01f1, 0x01fc, 0x0208, 0x0214, 0x0221, + 0x022d, 0x023a, 0x0248, 0x0255, 0x0263, 0x0271, 0x0280, 0x028f, + 0x029e, 0x02ae, 0x02be, 0x02ce, 0x02df, 0x02f0, 0x0301, 0x0313, + 0x0326, 0x0339, 0x034c, 0x035f, 0x0374, 0x0388, 0x039d, 0x03b3, + 0x03c9, 0x03df, 0x03f7, 0x040e, 0x0426, 0x043f, 0x0458, 0x0472, + 0x048d, 0x04a8, 0x04c4, 0x04e0, 0x04fd, 0x051b, 0x053a, 0x0559, + 0x0579, 0x0599, 0x05bb, 0x05dd, 0x0600, 0x0624, 0x0648, 0x066e, + 0x0694, 0x06bb, 0x06e3, 0x070c, 0x0737, 0x0762, 0x078e, 0x07bb, + 0x07e9, 0x0818, 0x0848, 0x087a, 0x08ac, 0x08e0, 0x0915, 0x094b, + 0x0982, 0x09bb, 0x09f5, 0x0a30, 0x0a6d, 0x0aab, 0x0aeb, 0x0b2c, + 0x0b6f, 0x0bb3, 0x0bf9, 0x0c40, 0x0c89, 0x0cd4, 0x0d21, 0x0d6f, + 0x0dbf, 0x0e11, 0x0e65, 0x0ebb, 0x0f12, 0x0f6c, 0x0fc8, 0x1026, + 0x1087, 0x10e9, 0x114e, 0x11b5, 0x121f, 0x128b, 0x12fa, 0x136b, + 0x13df, 0x1455, 0x14ce, 0x154a, 0x15c9, 0x164b, 0x16d0, 0x1758, + 0x17e4, 0x1872, 0x1904, 0x1999, 0x1a32, 0x1ace, 0x1b6e, 0x1c11, + 0x1cb9, 0x1d64, 0x1e13, 0x1ec7, 0x1f7e, 0x203a, 0x20fa, 0x21bf, + 0x2288, 0x2356, 0x2429, 0x2500, 0x25dd, 0x26bf, 0x27a6, 0x2892, + 0x2984, 0x2a7c, 0x2b79, 0x2c7c, 0x2d85, 0x2e95, 0x2fab, 0x30c7, + 0x31ea, 0x3313, 0x3444, 0x357c, 0x36bb, 0x3801, 0x394f, 0x3aa5, + 0x3c02, 0x3d68, 0x3ed6, 0x404d, 0x41cd, 0x4355, 0x44e6, 0x4681, + 0x4826, 0x49d4, 0x4b8c, 0x4d4f, 0x4f1c, 0x50f3, 0x52d6, 0x54c4, + 0x56be, 0x58c3, 0x5ad4, 0x5cf2, 0x5f1c, 0x6153, 0x6398, 0x65e9, + 0x6849, 0x6ab7, 0x6d33, 0x6fbf, 0x7259, 0x7503, 0x77bd, 0x7a87, + 0x7d61, 0x804d, 0x834a, 0x8659, 0x897a, 0x8cae, 0x8ff5, 0x934f, + 0x96bd, 0x9a40, 0x9dd8, 0xa185, 0xa548, 0xa922, 0xad13, 0xb11b, + 0xb53b, 0xb973, 0xbdc5, 0xc231, 0xc6b7, 0xcb58, 0xd014, 0xd4ed, + 0xd9e3, 0xdef6, 0xe428, 0xe978, 0xeee8, 0xf479, 0xfa2b, 0xffff, +}; + +/* (32bit x 16bit) >> 16 */ +typedef union { + int i; + short s[2]; +} val_t; +static inline int MULTI_DIV_32x16(int a, unsigned short b) +{ + val_t v, x, y; + v.i = a; + y.i = 0; +#if __BYTE_ORDER == __LITTLE_ENDIAN + x.i = (unsigned short)v.s[0]; + x.i *= b; + y.s[0] = x.s[1]; + y.i += (int)v.s[1] * b; +#else + x.i = (unsigned int)v.s[1] * b; + y.s[1] = x.s[0]; + y.i += (int)v.s[0] * b; +#endif + return y.i; +} + +static inline int MULTI_DIV_int(int a, unsigned int b, int swap) +{ + unsigned int gain = (b >> VOL_SCALE_SHIFT); + int fraction; + a = swap ? (int)bswap_32(a) : a; + fraction = MULTI_DIV_32x16(a, b & VOL_SCALE_MASK); + if (gain) { + long long amp = (long long)a * gain + fraction; + if (amp > (int)0x7fffffff) + amp = (int)0x7fffffff; + else if (amp < (int)0x80000000) + amp = (int)0x80000000; + return swap ? (int)bswap_32((int)amp) : (int)amp; + } + return swap ? (int)bswap_32(fraction) : fraction; +} + +/* always little endian */ +static inline int MULTI_DIV_24(int a, unsigned int b) +{ + unsigned int gain = b >> VOL_SCALE_SHIFT; + int fraction; + fraction = MULTI_DIV_32x16(a, b & VOL_SCALE_MASK); + if (gain) { + long long amp = (long long)a * gain + fraction; + if (amp > (int)0x7fffff) + amp = (int)0x7fffff; + else if (amp < (int)0x800000) + amp = (int)0x800000; + return (int)amp; + } + return fraction; +} + +static inline short MULTI_DIV_short(short a, unsigned int b, int swap) +{ + unsigned int gain = b >> VOL_SCALE_SHIFT; + int fraction; + a = swap ? (short)bswap_16(a) : a; + fraction = (int)(a * (b & VOL_SCALE_MASK)) >> VOL_SCALE_SHIFT; + if (gain) { + int amp = a * gain + fraction; + if (abs(amp) > 0x7fff) + amp = (a<0) ? (short)0x8000 : (short)0x7fff; + return swap ? (short)bswap_16((short)amp) : (short)amp; + } + return swap ? (short)bswap_16((short)fraction) : (short)fraction; +} + +#endif /* DOC_HIDDEN */ + +/* + * apply volumue attenuation + * + * TODO: use SIMD operations + */ + +#ifndef DOC_HIDDEN +#define CONVERT_AREA(TYPE, swap) do { \ + unsigned int ch, fr; \ + TYPE *src, *dst; \ + for (ch = 0; ch < channels; ch++) { \ + src_area = &src_areas[ch]; \ + dst_area = &dst_areas[ch]; \ + src = snd_pcm_channel_area_addr(src_area, src_offset); \ + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \ + src_step = snd_pcm_channel_area_step(src_area) / sizeof(TYPE); \ + dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(TYPE); \ + GET_VOL_SCALE; \ + fr = frames; \ + if (! vol_scale) { \ + while (fr--) { \ + *dst = 0; \ + dst += dst_step; \ + } \ + } else if (vol_scale == 0xffff) { \ + while (fr--) { \ + *dst = *src; \ + src += src_step; \ + dst += dst_step; \ + } \ + } else { \ + while (fr--) { \ + *dst = (TYPE) MULTI_DIV_##TYPE(*src, vol_scale, swap); \ + src += src_step; \ + dst += dst_step; \ + } \ + } \ + } \ +} while (0) + +#define CONVERT_AREA_S24_3LE() do { \ + unsigned int ch, fr; \ + unsigned char *src, *dst; \ + int tmp; \ + for (ch = 0; ch < channels; ch++) { \ + src_area = &src_areas[ch]; \ + dst_area = &dst_areas[ch]; \ + src = snd_pcm_channel_area_addr(src_area, src_offset); \ + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \ + src_step = snd_pcm_channel_area_step(src_area); \ + dst_step = snd_pcm_channel_area_step(dst_area); \ + GET_VOL_SCALE; \ + fr = frames; \ + if (! vol_scale) { \ + while (fr--) { \ + dst[0] = dst[1] = dst[2] = 0; \ + dst += dst_step; \ + } \ + } else if (vol_scale == 0xffff) { \ + while (fr--) { \ + dst[0] = src[0]; \ + dst[1] = src[1]; \ + dst[2] = src[2]; \ + src += dst_step; \ + dst += src_step; \ + } \ + } else { \ + while (fr--) { \ + tmp = src[0] | \ + (src[1] << 8) | \ + (((signed char *) src)[2] << 16); \ + tmp = MULTI_DIV_24(tmp, vol_scale); \ + dst[0] = tmp; \ + dst[1] = tmp >> 8; \ + dst[2] = tmp >> 16; \ + src += dst_step; \ + dst += src_step; \ + } \ + } \ + } \ +} while (0) + +#define GET_VOL_SCALE \ + switch (ch) { \ + case 0: \ + case 2: \ + vol_scale = (channels == ch + 1) ? vol_c : vol[0]; \ + break; \ + case 4: \ + case 5: \ + vol_scale = vol_c; \ + break; \ + default: \ + vol_scale = vol[ch & 1]; \ + break; \ + } + +#endif /* DOC_HIDDEN */ + +/* 2-channel stereo control */ +static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, + snd_pcm_uframes_t frames) +{ + const snd_pcm_channel_area_t *dst_area, *src_area; + unsigned int src_step, dst_step; + unsigned int vol_scale, vol[2], vol_c; + + if (svol->cur_vol[0] == 0 && svol->cur_vol[1] == 0) { + snd_pcm_areas_silence(dst_areas, dst_offset, channels, frames, + svol->sformat); + return; + } else if (svol->zero_dB_val && svol->cur_vol[0] == svol->zero_dB_val && + svol->cur_vol[1] == svol->zero_dB_val) { + snd_pcm_areas_copy(dst_areas, dst_offset, src_areas, src_offset, + channels, frames, svol->sformat); + return; + } + + if (svol->max_val == 1) { + vol[0] = svol->cur_vol[0] ? 0xffff : 0; + vol[1] = svol->cur_vol[1] ? 0xffff : 0; + vol_c = vol[0] | vol[1]; + } else { + vol[0] = svol->dB_value[svol->cur_vol[0]]; + vol[1] = svol->dB_value[svol->cur_vol[1]]; + vol_c = svol->dB_value[(svol->cur_vol[0] + svol->cur_vol[1]) / 2]; + } + switch (svol->sformat) { + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + /* 16bit samples */ + CONVERT_AREA(short, + !snd_pcm_format_cpu_endian(svol->sformat)); + break; + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + /* 32bit samples */ + CONVERT_AREA(int, + !snd_pcm_format_cpu_endian(svol->sformat)); + break; + case SND_PCM_FORMAT_S24_3LE: + CONVERT_AREA_S24_3LE(); + break; + default: + break; + } +} + +#undef GET_VOL_SCALE +#define GET_VOL_SCALE + +/* mono control */ +static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int channels, + snd_pcm_uframes_t frames) +{ + const snd_pcm_channel_area_t *dst_area, *src_area; + unsigned int src_step, dst_step; + unsigned int vol_scale; + + if (svol->cur_vol[0] == 0) { + snd_pcm_areas_silence(dst_areas, dst_offset, channels, frames, + svol->sformat); + return; + } else if (svol->zero_dB_val && svol->cur_vol[0] == svol->zero_dB_val) { + snd_pcm_areas_copy(dst_areas, dst_offset, src_areas, src_offset, + channels, frames, svol->sformat); + return; + } + + if (svol->max_val == 1) + vol_scale = svol->cur_vol[0] ? 0xffff : 0; + else + vol_scale = svol->dB_value[svol->cur_vol[0]]; + switch (svol->sformat) { + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + /* 16bit samples */ + CONVERT_AREA(short, + !snd_pcm_format_cpu_endian(svol->sformat)); + break; + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + /* 32bit samples */ + CONVERT_AREA(int, + !snd_pcm_format_cpu_endian(svol->sformat)); + break; + case SND_PCM_FORMAT_S24_3LE: + CONVERT_AREA_S24_3LE(); + break; + default: + break; + } +} + +/* + * get the current volume value from driver + * + * TODO: mmap support? + */ +static void get_current_volume(snd_pcm_softvol_t *svol) +{ + unsigned int val; + unsigned int i; + + if (snd_ctl_elem_read(svol->ctl, &svol->elem) < 0) + return; + for (i = 0; i < svol->cchannels; i++) { + val = svol->elem.value.integer.value[i]; + if (val > svol->max_val) + val = svol->max_val; + svol->cur_vol[i] = val; + } +} + +static void softvol_free(snd_pcm_softvol_t *svol) +{ + if (svol->plug.gen.close_slave) + snd_pcm_close(svol->plug.gen.slave); + if (svol->ctl) + snd_ctl_close(svol->ctl); + if (svol->dB_value && svol->dB_value != preset_dB_value) + free(svol->dB_value); + free(svol); +} + +static int snd_pcm_softvol_close(snd_pcm_t *pcm) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + softvol_free(svol); + return 0; +} + +static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + int err; + snd_pcm_softvol_t *svol = pcm->private_data; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + snd_pcm_format_mask_t format_mask = { + { + (1ULL << SND_PCM_FORMAT_S16_LE) | + (1ULL << SND_PCM_FORMAT_S16_BE) | + (1ULL << SND_PCM_FORMAT_S32_LE) | + (1ULL << SND_PCM_FORMAT_S32_BE), + (1ULL << (SND_PCM_FORMAT_S24_3LE - 32)) + } + }; + if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) { + snd_pcm_format_mask_none(&format_mask); + snd_pcm_format_mask_set(&format_mask, svol->sformat); + } + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, + &format_mask); + if (err < 0) + return err; + err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); + if (err < 0) + return err; + err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_softvol_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) { + _snd_pcm_hw_params_set_format(sparams, svol->sformat); + _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); + } + return 0; +} + +/* + * refine the access mask + */ +static int check_access_mask(snd_pcm_hw_params_t *src, + snd_pcm_hw_params_t *dst) +{ + const snd_pcm_access_mask_t *mask; + snd_pcm_access_mask_t smask; + + mask = snd_pcm_hw_param_get_mask(src, SND_PCM_HW_PARAM_ACCESS); + snd_mask_none(&smask); + if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_RW_INTERLEAVED) || + snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) { + snd_pcm_access_mask_set(&smask, + SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_access_mask_set(&smask, + SND_PCM_ACCESS_MMAP_INTERLEAVED); + } + if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) || + snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { + snd_pcm_access_mask_set(&smask, + SND_PCM_ACCESS_RW_NONINTERLEAVED); + snd_pcm_access_mask_set(&smask, + SND_PCM_ACCESS_MMAP_NONINTERLEAVED); + } + if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_COMPLEX)) + snd_pcm_access_mask_set(&smask, + SND_PCM_ACCESS_MMAP_COMPLEX); + + return _snd_pcm_hw_param_set_mask(dst, SND_PCM_HW_PARAM_ACCESS, &smask); +} + +static int snd_pcm_softvol_hw_refine_schange(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (svol->sformat == SND_PCM_FORMAT_UNKNOWN) + links |= (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS); + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + + err = check_access_mask(params, sparams); + if (err < 0) + return err; + + return 0; +} + +static int snd_pcm_softvol_hw_refine_cchange(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + int err; + unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | + SND_PCM_HW_PARBIT_RATE | + SND_PCM_HW_PARBIT_PERIODS | + SND_PCM_HW_PARBIT_PERIOD_SIZE | + SND_PCM_HW_PARBIT_PERIOD_TIME | + SND_PCM_HW_PARBIT_BUFFER_SIZE | + SND_PCM_HW_PARBIT_BUFFER_TIME | + SND_PCM_HW_PARBIT_TICK_TIME); + if (svol->sformat == SND_PCM_FORMAT_UNKNOWN) + links |= (SND_PCM_HW_PARBIT_FORMAT | + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS); + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + + err = check_access_mask(sparams, params); + if (err < 0) + return err; + + return 0; +} + +static int snd_pcm_softvol_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_softvol_hw_refine_cprepare, + snd_pcm_softvol_hw_refine_cchange, + snd_pcm_softvol_hw_refine_sprepare, + snd_pcm_softvol_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + snd_pcm_t *slave = svol->plug.gen.slave; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_softvol_hw_refine_cchange, + snd_pcm_softvol_hw_refine_sprepare, + snd_pcm_softvol_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + if (slave->format != SND_PCM_FORMAT_S16_LE && + slave->format != SND_PCM_FORMAT_S16_BE && + slave->format != SND_PCM_FORMAT_S24_3LE && + slave->format != SND_PCM_FORMAT_S32_LE && + slave->format != SND_PCM_FORMAT_S32_BE) { + SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE " + " or S32_BE"); + return -EINVAL; + } + svol->sformat = slave->format; + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_softvol_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + get_current_volume(svol); + if (svol->cchannels == 1) + softvol_convert_mono_vol(svol, slave_areas, slave_offset, + areas, offset, pcm->channels, size); + else + softvol_convert_stereo_vol(svol, slave_areas, slave_offset, + areas, offset, pcm->channels, size); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_softvol_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + if (size > *slave_sizep) + size = *slave_sizep; + get_current_volume(svol); + if (svol->cchannels == 1) + softvol_convert_mono_vol(svol, areas, offset, slave_areas, + slave_offset, pcm->channels, size); + else + softvol_convert_stereo_vol(svol, areas, offset, slave_areas, + slave_offset, pcm->channels, size); + *slave_sizep = size; + return size; +} + +static void snd_pcm_softvol_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + snd_pcm_softvol_t *svol = pcm->private_data; + snd_output_printf(out, "Soft volume PCM\n"); + snd_output_printf(out, "Control: %s\n", svol->elem.id.name); + if (svol->max_val == 1) + snd_output_printf(out, "boolean\n"); + else { + snd_output_printf(out, "min_dB: %g\n", svol->min_dB); + snd_output_printf(out, "max_dB: %g\n", svol->max_dB); + snd_output_printf(out, "resolution: %d\n", svol->max_val + 1); + } + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(svol->plug.gen.slave, out); +} + +static int add_tlv_info(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo) +{ + unsigned int tlv[4]; + tlv[0] = SND_CTL_TLVT_DB_SCALE; + tlv[1] = 2 * sizeof(int); + tlv[2] = svol->min_dB * 100; + tlv[3] = (svol->max_dB - svol->min_dB) * 100 / svol->max_val; + return snd_ctl_elem_tlv_write(svol->ctl, &cinfo->id, tlv); +} + +static int add_user_ctl(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo, int count) +{ + int err; + int i; + unsigned int def_val; + + if (svol->max_val == 1) + err = snd_ctl_elem_add_boolean(svol->ctl, &cinfo->id, count); + else + err = snd_ctl_elem_add_integer(svol->ctl, &cinfo->id, count, + 0, svol->max_val, 0); + if (err < 0) + return err; + if (svol->max_val == 1) + def_val = 1; + else { + add_tlv_info(svol, cinfo); + /* set zero dB value as default, or max_val if + there is no 0 dB setting */ + def_val = svol->zero_dB_val ? svol->zero_dB_val : svol->max_val; + } + for (i = 0; i < count; i++) + svol->elem.value.integer.value[i] = def_val; + return snd_ctl_elem_write(svol->ctl, &svol->elem); +} + +/* + * load and set up user-control + * returns 0 if the user-control is found or created, + * returns 1 if the control is a hw control, + * or a negative error code + */ +static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol, + int ctl_card, snd_ctl_elem_id_t *ctl_id, + int cchannels, double min_dB, double max_dB, + int resolution) +{ + char tmp_name[32]; + snd_pcm_info_t *info; + snd_ctl_elem_info_t *cinfo; + int err; + unsigned int i; + + if (ctl_card < 0) { + snd_pcm_info_alloca(&info); + err = snd_pcm_info(pcm, info); + if (err < 0) + return err; + ctl_card = snd_pcm_info_get_card(info); + if (ctl_card < 0) { + SNDERR("No card defined for softvol control"); + return -EINVAL; + } + } + sprintf(tmp_name, "hw:%d", ctl_card); + err = snd_ctl_open(&svol->ctl, tmp_name, 0); + if (err < 0) { + SNDERR("Cannot open CTL %s", tmp_name); + return err; + } + + svol->elem.id = *ctl_id; + svol->max_val = resolution - 1; + svol->min_dB = min_dB; + svol->max_dB = max_dB; + if (svol->max_val == 1 || svol->max_dB == ZERO_DB) + svol->zero_dB_val = svol->max_val; + else if (svol->max_dB < 0) + svol->zero_dB_val = 0; /* there is no 0 dB setting */ + else + svol->zero_dB_val = (min_dB / (min_dB - max_dB)) * svol->max_val; + + snd_ctl_elem_info_alloca(&cinfo); + snd_ctl_elem_info_set_id(cinfo, ctl_id); + if ((err = snd_ctl_elem_info(svol->ctl, cinfo)) < 0) { + if (err != -ENOENT) { + SNDERR("Cannot get info for CTL %s", tmp_name); + return err; + } + err = add_user_ctl(svol, cinfo, cchannels); + if (err < 0) { + SNDERR("Cannot add a control"); + return err; + } + } else { + if (! (cinfo->access & SNDRV_CTL_ELEM_ACCESS_USER)) { + /* hardware control exists */ + return 1; /* notify */ + + } else if ((cinfo->type != SND_CTL_ELEM_TYPE_INTEGER && + cinfo->type != SND_CTL_ELEM_TYPE_BOOLEAN) || + cinfo->count != (unsigned int)cchannels || + cinfo->value.integer.min != 0 || + cinfo->value.integer.max != resolution - 1) { + if ((err = snd_ctl_elem_remove(svol->ctl, &cinfo->id)) < 0) { + SNDERR("Control %s mismatch", tmp_name); + return err; + } + snd_ctl_elem_info_set_id(cinfo, ctl_id); /* reset numid */ + if ((err = add_user_ctl(svol, cinfo, cchannels)) < 0) { + SNDERR("Cannot add a control"); + return err; + } + } else if (svol->max_val > 1) { + /* check TLV availability */ + unsigned int tlv[4]; + err = snd_ctl_elem_tlv_read(svol->ctl, &cinfo->id, tlv, sizeof(tlv)); + if (err < 0) + add_tlv_info(svol, cinfo); + } + } + + if (svol->max_val == 1) + return 0; + + /* set up dB table */ + if (min_dB == PRESET_MIN_DB && max_dB == ZERO_DB && resolution == PRESET_RESOLUTION) + svol->dB_value = (unsigned int*)preset_dB_value; + else { +#ifndef HAVE_SOFT_FLOAT + svol->dB_value = calloc(resolution, sizeof(unsigned int)); + if (! svol->dB_value) { + SNDERR("cannot allocate dB table"); + return -ENOMEM; + } + svol->min_dB = min_dB; + svol->max_dB = max_dB; + for (i = 0; i <= svol->max_val; i++) { + double db = svol->min_dB + (i * (svol->max_dB - svol->min_dB)) / svol->max_val; + double v = (pow(10.0, db / 20.0) * (double)(1 << VOL_SCALE_SHIFT)); + svol->dB_value[i] = (unsigned int)v; + } + if (svol->zero_dB_val) + svol->dB_value[svol->zero_dB_val] = 65535; +#else + SNDERR("Cannot handle the given dB range and resolution"); + return -EINVAL; +#endif + } + return 0; +} + +static const snd_pcm_ops_t snd_pcm_softvol_ops = { + .close = snd_pcm_softvol_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_softvol_hw_refine, + .hw_params = snd_pcm_softvol_hw_params, + .hw_free = snd_pcm_generic_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_softvol_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/** + * \brief Creates a new SoftVolume PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param sformat Slave format + * \param ctl_card card index of the control + * \param ctl_id The control element + * \param cchannels PCM channels + * \param min_dB minimal dB value + * \param max_dB maximal dB value + * \param resolution resolution of control + * \param slave Slave PCM handle + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_format_t sformat, + int ctl_card, snd_ctl_elem_id_t *ctl_id, + int cchannels, + double min_dB, double max_dB, int resolution, + snd_pcm_t *slave, int close_slave) +{ + snd_pcm_t *pcm; + snd_pcm_softvol_t *svol; + int err; + assert(pcmp && slave); + if (sformat != SND_PCM_FORMAT_UNKNOWN && + sformat != SND_PCM_FORMAT_S16_LE && + sformat != SND_PCM_FORMAT_S16_BE && + sformat != SND_PCM_FORMAT_S24_3LE && + sformat != SND_PCM_FORMAT_S32_LE && + sformat != SND_PCM_FORMAT_S32_BE) + return -EINVAL; + svol = calloc(1, sizeof(*svol)); + if (! svol) + return -ENOMEM; + err = softvol_load_control(slave, svol, ctl_card, ctl_id, cchannels, + min_dB, max_dB, resolution); + if (err < 0) { + softvol_free(svol); + return err; + } + if (err > 0) { /* hardware control - no need for softvol! */ + softvol_free(svol); + *pcmp = slave; /* just pass the slave */ + if (!slave->name && name) + slave->name = strdup(name); + return 0; + } + + /* do softvol */ + snd_pcm_plugin_init(&svol->plug); + svol->sformat = sformat; + svol->cchannels = cchannels; + svol->plug.read = snd_pcm_softvol_read_areas; + svol->plug.write = snd_pcm_softvol_write_areas; + svol->plug.undo_read = snd_pcm_plugin_undo_read_generic; + svol->plug.undo_write = snd_pcm_plugin_undo_write_generic; + svol->plug.gen.slave = slave; + svol->plug.gen.close_slave = close_slave; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_SOFTVOL, name, slave->stream, slave->mode); + if (err < 0) { + softvol_free(svol); + return err; + } + pcm->ops = &snd_pcm_softvol_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = svol; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + /* + * Since the softvol converts on the place, and the format/channels + * must be identical between source and destination, we don't need + * an extra buffer. + */ + pcm->mmap_shadow = 1; + pcm->monotonic = slave->monotonic; + snd_pcm_set_hw_ptr(pcm, &svol->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &svol->plug.appl_ptr, -1, 0); + *pcmp = pcm; + + return 0; +} + +/* in pcm_misc.c */ +int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, + int *cchannelsp, int *hwctlp); + +/*! \page pcm_plugins + +\section pcm_plugins_softvol Plugin: Soft Volume + +This plugin applies the software volume attenuation. +The format, rate and channels must match for both of source and destination. + +When the control is stereo (count=2), the channels are assumed to be either +mono, 2.0, 2.1, 4.0, 4.1, 5.1 or 7.1. + +If the control already exists and it's a system control (i.e. no +user-defined control), the plugin simply passes its slave without +any changes. + +\code +pcm.name { + type softvol # Soft Volume conversion PCM + slave STR # Slave name + # or + slave { # Slave definition + pcm STR # Slave PCM name + # or + pcm { } # Slave PCM definition + [format STR] # Slave format + } + control { + name STR # control element id string + [card STR] # control card index + [iface STR] # interface of the element + [index INT] # index of the element + [device INT] # device number of the element + [subdevice INT] # subdevice number of the element + [count INT] # control channels 1 or 2 (default: 2) + } + [min_dB REAL] # minimal dB value (default: -51.0) + [max_dB REAL] # maximal dB value (default: 0.0) + [resolution INT] # resolution (default: 256) + # resolution = 2 means a mute switch +} +\endcode + +\subsection pcm_plugins_softvol_funcref Function reference + +
    +
  • snd_pcm_softvol_open() +
  • _snd_pcm_softvol_open() +
+ +*/ + +/** + * \brief Creates a new Soft Volume PCM + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param root Root configuration node + * \param conf Configuration node with Soft Volume PCM description + * \param stream Stream type + * \param mode Stream mode + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, + snd_config_t *root, snd_config_t *conf, + snd_pcm_stream_t stream, int mode) +{ + snd_config_iterator_t i, next; + int err; + snd_pcm_t *spcm; + snd_config_t *slave = NULL, *sconf; + snd_config_t *control = NULL; + snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; + snd_ctl_elem_id_t *ctl_id; + int resolution = PRESET_RESOLUTION; + double min_dB = PRESET_MIN_DB; + double max_dB = ZERO_DB; + int card = -1, cchannels = 2; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + slave = n; + continue; + } + if (strcmp(id, "control") == 0) { + control = n; + continue; + } + if (strcmp(id, "resolution") == 0) { + long v; + err = snd_config_get_integer(n, &v); + if (err < 0) { + SNDERR("Invalid resolution value"); + return err; + } + resolution = v; + continue; + } + if (strcmp(id, "min_dB") == 0) { + err = snd_config_get_real(n, &min_dB); + if (err < 0) { + SNDERR("Invalid min_dB value"); + return err; + } + continue; + } + if (strcmp(id, "max_dB") == 0) { + err = snd_config_get_real(n, &max_dB); + if (err < 0) { + SNDERR("Invalid max_dB value"); + return err; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (!slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + if (!control) { + SNDERR("control is not defined"); + return -EINVAL; + } + if (min_dB >= 0) { + SNDERR("min_dB must be a negative value"); + return -EINVAL; + } + if (max_dB <= min_dB || max_dB > MAX_DB_UPPER_LIMIT) { + SNDERR("max_dB must be larger than min_dB and less than %d dB", + MAX_DB_UPPER_LIMIT); + return -EINVAL; + } + if (resolution <= 1 || resolution > 1024) { + SNDERR("Invalid resolution value %d", resolution); + return -EINVAL; + } + if (mode & SND_PCM_NO_SOFTVOL) { + err = snd_pcm_slave_conf(root, slave, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_named_slave(pcmp, name, root, sconf, stream, + mode, conf); + snd_config_delete(sconf); + } else { + snd_ctl_elem_id_alloca(&ctl_id); + err = snd_pcm_slave_conf(root, slave, &sconf, 1, + SND_PCM_HW_PARAM_FORMAT, 0, &sformat); + if (err < 0) + return err; + if (sformat != SND_PCM_FORMAT_UNKNOWN && + sformat != SND_PCM_FORMAT_S16_LE && + sformat != SND_PCM_FORMAT_S16_BE && + sformat != SND_PCM_FORMAT_S24_3LE && + sformat != SND_PCM_FORMAT_S32_LE && + sformat != SND_PCM_FORMAT_S32_BE) { + SNDERR("only S16_LE, S16_BE, S24_3LE, S32_LE or S32_BE format " + "is supported"); + snd_config_delete(sconf); + return -EINVAL; + } + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) + return err; + if ((err = snd_pcm_parse_control_id(control, ctl_id, &card, &cchannels, NULL)) < 0) { + snd_pcm_close(spcm); + return err; + } + err = snd_pcm_softvol_open(pcmp, name, sformat, card, ctl_id, cchannels, + min_dB, max_dB, resolution, spcm, 1); + if (err < 0) + snd_pcm_close(spcm); + } + return err; +} +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_pcm_softvol_open, SND_PCM_DLSYM_VERSION); +#endif diff --git a/src/pcm/pcm_symbols.c b/src/pcm/pcm_symbols.c new file mode 100644 index 0000000..91982df --- /dev/null +++ b/src/pcm/pcm_symbols.c @@ -0,0 +1,64 @@ +/* + * PCM Symbols + * Copyright (c) 2001 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +#include "config.h" + +extern const char *_snd_module_pcm_adpcm; +extern const char *_snd_module_pcm_alaw; +extern const char *_snd_module_pcm_copy; +extern const char *_snd_module_pcm_file; +extern const char *_snd_module_pcm_hooks; +extern const char *_snd_module_pcm_hw; +extern const char *_snd_module_pcm_linear; +extern const char *_snd_module_pcm_meter; +extern const char *_snd_module_pcm_mulaw; +extern const char *_snd_module_pcm_multi; +extern const char *_snd_module_pcm_null; +extern const char *_snd_module_pcm_empty; +extern const char *_snd_module_pcm_plug; +extern const char *_snd_module_pcm_rate; +extern const char *_snd_module_pcm_route; +extern const char *_snd_module_pcm_share; +extern const char *_snd_module_pcm_shm; +extern const char *_snd_module_pcm_lfloat; +extern const char *_snd_module_pcm_ladspa; +extern const char *_snd_module_pcm_dmix; +extern const char *_snd_module_pcm_dsnoop; +extern const char *_snd_module_pcm_dshare; +extern const char *_snd_module_pcm_asym; +extern const char *_snd_module_pcm_iec958; +extern const char *_snd_module_pcm_softvol; +extern const char *_snd_module_pcm_extplug; +extern const char *_snd_module_pcm_ioplug; +extern const char *_snd_module_pcm_mmap_emul; + +static const char **snd_pcm_open_objects[] = { + &_snd_module_pcm_hw, +#include "pcm_symbols_list.c" +}; + +void *snd_pcm_open_symbols(void) +{ + return snd_pcm_open_objects; +} + +#endif /* !PIC */ diff --git a/src/pcm/pcm_symbols_list.c b/src/pcm/pcm_symbols_list.c new file mode 100644 index 0000000..90efa3e --- /dev/null +++ b/src/pcm/pcm_symbols_list.c @@ -0,0 +1,27 @@ +&_snd_module_pcm_copy, +&_snd_module_pcm_linear, +&_snd_module_pcm_route, +&_snd_module_pcm_mulaw, +&_snd_module_pcm_alaw, +&_snd_module_pcm_adpcm, +&_snd_module_pcm_rate, +&_snd_module_pcm_plug, +&_snd_module_pcm_multi, +&_snd_module_pcm_shm, +&_snd_module_pcm_file, +&_snd_module_pcm_null, +&_snd_module_pcm_empty, +&_snd_module_pcm_share, +&_snd_module_pcm_meter, +&_snd_module_pcm_hooks, +&_snd_module_pcm_lfloat, +&_snd_module_pcm_ladspa, +&_snd_module_pcm_dmix, +&_snd_module_pcm_dshare, +&_snd_module_pcm_dsnoop, +&_snd_module_pcm_asym, +&_snd_module_pcm_iec958, +&_snd_module_pcm_softvol, +&_snd_module_pcm_extplug, +&_snd_module_pcm_ioplug, +&_snd_module_pcm_mmap_emul, diff --git a/src/pcm/plugin_ops.h b/src/pcm/plugin_ops.h new file mode 100644 index 0000000..21535c9 --- /dev/null +++ b/src/pcm/plugin_ops.h @@ -0,0 +1,1106 @@ +/* + * Plugin sample operators with fast switch + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef SX_INLINES +#define SX_INLINES +static inline u_int32_t sx24(u_int32_t x) +{ + if(x&0x00800000) + return x|0xFF000000; + return x&0x00FFFFFF; +} +static inline u_int32_t sx24s(u_int32_t x) +{ + if(x&0x00008000) + return x|0x000000FF; + return x&0xFFFFFF00; +} +#endif + +#define as_u8(ptr) (*(u_int8_t*)(ptr)) +#define as_u16(ptr) (*(u_int16_t*)(ptr)) +#define as_u32(ptr) (*(u_int32_t*)(ptr)) +#define as_u64(ptr) (*(u_int64_t*)(ptr)) +#define as_s8(ptr) (*(int8_t*)(ptr)) +#define as_s16(ptr) (*(int16_t*)(ptr)) +#define as_s32(ptr) (*(int32_t*)(ptr)) +#define as_s64(ptr) (*(int64_t*)(ptr)) +#define as_float(ptr) (*(float_t*)(ptr)) +#define as_double(ptr) (*(double_t*)(ptr)) + +#define as_u8c(ptr) (*(const u_int8_t*)(ptr)) +#define as_u16c(ptr) (*(const u_int16_t*)(ptr)) +#define as_u32c(ptr) (*(const u_int32_t*)(ptr)) +#define as_u64c(ptr) (*(const u_int64_t*)(ptr)) +#define as_s8c(ptr) (*(const int8_t*)(ptr)) +#define as_s16c(ptr) (*(const int16_t*)(ptr)) +#define as_s32c(ptr) (*(const int32_t*)(ptr)) +#define as_s64c(ptr) (*(const int64_t*)(ptr)) +#define as_floatc(ptr) (*(const float_t*)(ptr)) +#define as_doublec(ptr) (*(const double_t*)(ptr)) + +#define _get_triple_le(ptr) (*(u_int8_t*)(ptr) | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | (u_int32_t)*((u_int8_t*)(ptr) + 2) << 16) +#define _get_triple_be(ptr) ((u_int32_t)*(u_int8_t*)(ptr) << 16 | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | *((u_int8_t*)(ptr) + 2)) +#define _put_triple_le(ptr,val) do { \ + u_int8_t *_tmp = (u_int8_t *)(ptr); \ + u_int32_t _val = (val); \ + _tmp[0] = _val; \ + _tmp[1] = _val >> 8; \ + _tmp[2] = _val >> 16; \ +} while(0) +#define _put_triple_be(ptr,val) do { \ + u_int8_t *_tmp = (u_int8_t *)(ptr); \ + u_int32_t _val = (val); \ + _tmp[0] = _val >> 16; \ + _tmp[1] = _val >> 8; \ + _tmp[2] = _val; \ +} while(0) + +#ifdef SNDRV_LITTLE_ENDIAN +#define _get_triple(ptr) _get_triple_le(ptr) +#define _get_triple_s(ptr) _get_triple_be(ptr) +#define _put_triple(ptr,val) _put_triple_le(ptr,val) +#define _put_triple_s(ptr,val) _put_triple_be(ptr,val) +#else +#define _get_triple(ptr) _get_triple_be(ptr) +#define _get_triple_s(ptr) _get_triple_le(ptr) +#define _put_triple(ptr,val) _put_triple_be(ptr,val) +#define _put_triple_s(ptr,val) _put_triple_le(ptr,val) +#endif + +#ifdef COPY_LABELS +static void *copy_labels[5] = { + &©_8, + &©_16, + &©_24 + &©_32, + &©_64 +}; +#endif + +#ifdef COPY_END +while(0) { +copy_8: as_s8(dst) = as_s8c(src); goto COPY_END; +copy_16: as_s16(dst) = as_s16c(src); goto COPY_END; +copy_24: memcpy(dst,src,3); goto COPY_END; +copy_32: as_s32(dst) = as_s32c(src); goto COPY_END; +copy_64: as_s64(dst) = as_s64c(src); goto COPY_END; +} +#endif + +#ifdef CONV_LABELS +/* src_wid src_endswap sign_toggle dst_wid dst_endswap */ +static void *const conv_labels[4 * 2 * 2 * 4 * 2] = { + &&conv_xxx1_xxx1, /* 8h -> 8h */ + &&conv_xxx1_xxx1, /* 8h -> 8s */ + &&conv_xxx1_xx10, /* 8h -> 16h */ + &&conv_xxx1_xx01, /* 8h -> 16s */ + &&conv_xxx1_x100, /* 8h -> 24h */ + &&conv_xxx1_001x, /* 8h -> 24s */ + &&conv_xxx1_1000, /* 8h -> 32h */ + &&conv_xxx1_0001, /* 8h -> 32s */ + &&conv_xxx1_xxx9, /* 8h ^> 8h */ + &&conv_xxx1_xxx9, /* 8h ^> 8s */ + &&conv_xxx1_xx90, /* 8h ^> 16h */ + &&conv_xxx1_xx09, /* 8h ^> 16s */ + &&conv_xxx1_x900, /* 8h ^> 24h */ + &&conv_xxx1_009x, /* 8h ^> 24s */ + &&conv_xxx1_9000, /* 8h ^> 32h */ + &&conv_xxx1_0009, /* 8h ^> 32s */ + &&conv_xxx1_xxx1, /* 8s -> 8h */ + &&conv_xxx1_xxx1, /* 8s -> 8s */ + &&conv_xxx1_xx10, /* 8s -> 16h */ + &&conv_xxx1_xx01, /* 8s -> 16s */ + &&conv_xxx1_x100, /* 8s -> 24h */ + &&conv_xxx1_001x, /* 8s -> 24s */ + &&conv_xxx1_1000, /* 8s -> 32h */ + &&conv_xxx1_0001, /* 8s -> 32s */ + &&conv_xxx1_xxx9, /* 8s ^> 8h */ + &&conv_xxx1_xxx9, /* 8s ^> 8s */ + &&conv_xxx1_xx90, /* 8s ^> 16h */ + &&conv_xxx1_xx09, /* 8s ^> 16s */ + &&conv_xxx1_x900, /* 8s ^> 24h */ + &&conv_xxx1_009x, /* 8s ^> 24s */ + &&conv_xxx1_9000, /* 8s ^> 32h */ + &&conv_xxx1_0009, /* 8s ^> 32s */ + &&conv_xx12_xxx1, /* 16h -> 8h */ + &&conv_xx12_xxx1, /* 16h -> 8s */ + &&conv_xx12_xx12, /* 16h -> 16h */ + &&conv_xx12_xx21, /* 16h -> 16s */ + &&conv_xx12_x120, /* 16h -> 24h */ + &&conv_xx12_021x, /* 16h -> 24s */ + &&conv_xx12_1200, /* 16h -> 32h */ + &&conv_xx12_0021, /* 16h -> 32s */ + &&conv_xx12_xxx9, /* 16h ^> 8h */ + &&conv_xx12_xxx9, /* 16h ^> 8s */ + &&conv_xx12_xx92, /* 16h ^> 16h */ + &&conv_xx12_xx29, /* 16h ^> 16s */ + &&conv_xx12_x920, /* 16h ^> 24h */ + &&conv_xx12_029x, /* 16h ^> 24s */ + &&conv_xx12_9200, /* 16h ^> 32h */ + &&conv_xx12_0029, /* 16h ^> 32s */ + &&conv_xx12_xxx2, /* 16s -> 8h */ + &&conv_xx12_xxx2, /* 16s -> 8s */ + &&conv_xx12_xx21, /* 16s -> 16h */ + &&conv_xx12_xx12, /* 16s -> 16s */ + &&conv_xx12_x210, /* 16s -> 24h */ + &&conv_xx12_012x, /* 16s -> 24s */ + &&conv_xx12_2100, /* 16s -> 32h */ + &&conv_xx12_0012, /* 16s -> 32s */ + &&conv_xx12_xxxA, /* 16s ^> 8h */ + &&conv_xx12_xxxA, /* 16s ^> 8s */ + &&conv_xx12_xxA1, /* 16s ^> 16h */ + &&conv_xx12_xx1A, /* 16s ^> 16s */ + &&conv_xx12_xA10, /* 16s ^> 24h */ + &&conv_xx12_01Ax, /* 16s ^> 24s */ + &&conv_xx12_A100, /* 16s ^> 32h */ + &&conv_xx12_001A, /* 16s ^> 32s */ + &&conv_x123_xxx1, /* 24h -> 8h */ + &&conv_x123_xxx1, /* 24h -> 8s */ + &&conv_x123_xx12, /* 24h -> 16h */ + &&conv_x123_xx21, /* 24h -> 16s */ + &&conv_x123_x123, /* 24h -> 24h */ + &&conv_x123_321x, /* 24h -> 24s */ + &&conv_x123_1230, /* 24h -> 32h */ + &&conv_x123_0321, /* 24h -> 32s */ + &&conv_x123_xxx9, /* 24h ^> 8h */ + &&conv_x123_xxx9, /* 24h ^> 8s */ + &&conv_x123_xx92, /* 24h ^> 16h */ + &&conv_x123_xx29, /* 24h ^> 16s */ + &&conv_x123_x923, /* 24h ^> 24h */ + &&conv_x123_329x, /* 24h ^> 24s */ + &&conv_x123_9230, /* 24h ^> 32h */ + &&conv_x123_0329, /* 24h ^> 32s */ + &&conv_123x_xxx3, /* 24s -> 8h */ + &&conv_123x_xxx3, /* 24s -> 8s */ + &&conv_123x_xx32, /* 24s -> 16h */ + &&conv_123x_xx23, /* 24s -> 16s */ + &&conv_123x_x321, /* 24s -> 24h */ + &&conv_123x_123x, /* 24s -> 24s */ + &&conv_123x_3210, /* 24s -> 32h */ + &&conv_123x_0123, /* 24s -> 32s */ + &&conv_123x_xxxB, /* 24s ^> 8h */ + &&conv_123x_xxxB, /* 24s ^> 8s */ + &&conv_123x_xxB2, /* 24s ^> 16h */ + &&conv_123x_xx2B, /* 24s ^> 16s */ + &&conv_123x_xB21, /* 24s ^> 24h */ + &&conv_123x_12Bx, /* 24s ^> 24s */ + &&conv_123x_B210, /* 24s ^> 32h */ + &&conv_123x_012B, /* 24s ^> 32s */ + &&conv_1234_xxx1, /* 32h -> 8h */ + &&conv_1234_xxx1, /* 32h -> 8s */ + &&conv_1234_xx12, /* 32h -> 16h */ + &&conv_1234_xx21, /* 32h -> 16s */ + &&conv_1234_x123, /* 32h -> 24h */ + &&conv_1234_321x, /* 32h -> 24s */ + &&conv_1234_1234, /* 32h -> 32h */ + &&conv_1234_4321, /* 32h -> 32s */ + &&conv_1234_xxx9, /* 32h ^> 8h */ + &&conv_1234_xxx9, /* 32h ^> 8s */ + &&conv_1234_xx92, /* 32h ^> 16h */ + &&conv_1234_xx29, /* 32h ^> 16s */ + &&conv_1234_x923, /* 32h ^> 24h */ + &&conv_1234_329x, /* 32h ^> 24s */ + &&conv_1234_9234, /* 32h ^> 32h */ + &&conv_1234_4329, /* 32h ^> 32s */ + &&conv_1234_xxx4, /* 32s -> 8h */ + &&conv_1234_xxx4, /* 32s -> 8s */ + &&conv_1234_xx43, /* 32s -> 16h */ + &&conv_1234_xx34, /* 32s -> 16s */ + &&conv_1234_x432, /* 32s -> 24h */ + &&conv_1234_234x, /* 32s -> 24s */ + &&conv_1234_4321, /* 32s -> 32h */ + &&conv_1234_1234, /* 32s -> 32s */ + &&conv_1234_xxxC, /* 32s ^> 8h */ + &&conv_1234_xxxC, /* 32s ^> 8s */ + &&conv_1234_xxC3, /* 32s ^> 16h */ + &&conv_1234_xx3C, /* 32s ^> 16s */ + &&conv_1234_xC32, /* 32s ^> 24h */ + &&conv_1234_23Cx, /* 32s ^> 24s */ + &&conv_1234_C321, /* 32s ^> 32h */ + &&conv_1234_123C, /* 32s ^> 32s */ +}; +#endif + +#ifdef CONV_END +while(0) { +conv_xxx1_xxx1: as_u8(dst) = as_u8c(src); goto CONV_END; +conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8c(src) << 8; goto CONV_END; +conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8c(src); goto CONV_END; +conv_xxx1_x100: as_u32(dst) = sx24((u_int32_t)as_u8c(src) << 16); goto CONV_END; +conv_xxx1_001x: as_u32(dst) = sx24s((u_int32_t)as_u8c(src) << 8); goto CONV_END; +conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8c(src) << 24; goto CONV_END; +conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8c(src); goto CONV_END; +conv_xxx1_xxx9: as_u8(dst) = as_u8c(src) ^ 0x80; goto CONV_END; +conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8c(src) ^ 0x80) << 8; goto CONV_END; +conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8c(src) ^ 0x80); goto CONV_END; +conv_xxx1_x900: as_u32(dst) = sx24((u_int32_t)(as_u8c(src) ^ 0x80) << 16); goto CONV_END; +conv_xxx1_009x: as_u32(dst) = sx24s((u_int32_t)(as_u8c(src) ^ 0x80) << 8); goto CONV_END; +conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8c(src) ^ 0x80) << 24; goto CONV_END; +conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8c(src) ^ 0x80); goto CONV_END; +conv_xx12_xxx1: as_u8(dst) = as_u16c(src) >> 8; goto CONV_END; +conv_xx12_xx12: as_u16(dst) = as_u16c(src); goto CONV_END; +conv_xx12_xx21: as_u16(dst) = bswap_16(as_u16c(src)); goto CONV_END; +conv_xx12_x120: as_u32(dst) = sx24((u_int32_t)as_u16c(src) << 8); goto CONV_END; +conv_xx12_021x: as_u32(dst) = sx24s((u_int32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16c(src) << 16; goto CONV_END; +conv_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src)); goto CONV_END; +conv_xx12_xxx9: as_u8(dst) = (as_u16c(src) >> 8) ^ 0x80; goto CONV_END; +conv_xx12_xx92: as_u16(dst) = as_u16c(src) ^ 0x8000; goto CONV_END; +conv_xx12_xx29: as_u16(dst) = bswap_16(as_u16c(src)) ^ 0x80; goto CONV_END; +conv_xx12_x920: as_u32(dst) = sx24((u_int32_t)(as_u16c(src) ^ 0x8000) << 8); goto CONV_END; +conv_xx12_029x: as_u32(dst) = sx24s((u_int32_t)(bswap_16(as_u16c(src)) ^ 0x80) << 8); goto CONV_END; +conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16c(src) ^ 0x8000) << 16; goto CONV_END; +conv_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16c(src)) ^ 0x80); goto CONV_END; +conv_xx12_xxx2: as_u8(dst) = as_u16c(src) & 0xff; goto CONV_END; +conv_xx12_x210: as_u32(dst) = sx24((u_int32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +conv_xx12_012x: as_u32(dst) = sx24s((u_int32_t)as_u16c(src) << 8); goto CONV_END; +conv_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src)) << 16; goto CONV_END; +conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16c(src); goto CONV_END; +conv_xx12_xxxA: as_u8(dst) = (as_u16c(src) ^ 0x80) & 0xff; goto CONV_END; +conv_xx12_xxA1: as_u16(dst) = bswap_16(as_u16c(src) ^ 0x80); goto CONV_END; +conv_xx12_xx1A: as_u16(dst) = as_u16c(src) ^ 0x80; goto CONV_END; +conv_xx12_xA10: as_u32(dst) = sx24((u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +conv_xx12_01Ax: as_u32(dst) = sx24s((u_int32_t)(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +conv_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto CONV_END; +conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16c(src) ^ 0x80); goto CONV_END; +conv_x123_xxx1: as_u8(dst) = as_u32c(src) >> 16; goto CONV_END; +conv_x123_xx12: as_u16(dst) = as_u32c(src) >> 8; goto CONV_END; +conv_x123_xx21: as_u16(dst) = bswap_16(as_u32c(src) >> 8); goto CONV_END; +conv_x123_x123: as_u32(dst) = sx24(as_u32c(src)); goto CONV_END; +conv_x123_321x: as_u32(dst) = sx24s(bswap_32(as_u32c(src))); goto CONV_END; +conv_x123_1230: as_u32(dst) = as_u32c(src) << 8; goto CONV_END; +conv_x123_0321: as_u32(dst) = bswap_32(as_u32c(src)) >> 8; goto CONV_END; +conv_x123_xxx9: as_u8(dst) = (as_u32c(src) >> 16) ^ 0x80; goto CONV_END; +conv_x123_xx92: as_u16(dst) = (as_u32c(src) >> 8) ^ 0x8000; goto CONV_END; +conv_x123_xx29: as_u16(dst) = bswap_16(as_u32c(src) >> 8) ^ 0x80; goto CONV_END; +conv_x123_x923: as_u32(dst) = sx24(as_u32c(src) ^ 0x800000); goto CONV_END; +conv_x123_329x: as_u32(dst) = sx24s(bswap_32(as_u32c(src)) ^ 0x8000); goto CONV_END; +conv_x123_9230: as_u32(dst) = (as_u32c(src) ^ 0x800000) << 8; goto CONV_END; +conv_x123_0329: as_u32(dst) = (bswap_32(as_u32c(src)) >> 8) ^ 0x80; goto CONV_END; +conv_123x_xxx3: as_u8(dst) = (as_u32c(src) >> 8) & 0xff; goto CONV_END; +conv_123x_xx32: as_u16(dst) = bswap_16(as_u32c(src) >> 8); goto CONV_END; +conv_123x_xx23: as_u16(dst) = (as_u32c(src) >> 8) & 0xffff; goto CONV_END; +conv_123x_x321: as_u32(dst) = sx24(bswap_32(as_u32c(src))); goto CONV_END; +conv_123x_123x: as_u32(dst) = sx24s(as_u32c(src)); goto CONV_END; +conv_123x_3210: as_u32(dst) = bswap_32(as_u32c(src)) << 8; goto CONV_END; +conv_123x_0123: as_u32(dst) = as_u32c(src) >> 8; goto CONV_END; +conv_123x_xxxB: as_u8(dst) = ((as_u32c(src) >> 8) & 0xff) ^ 0x80; goto CONV_END; +conv_123x_xxB2: as_u16(dst) = bswap_16((as_u32c(src) >> 8) ^ 0x80); goto CONV_END; +conv_123x_xx2B: as_u16(dst) = ((as_u32c(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END; +conv_123x_xB21: as_u32(dst) = sx24(bswap_32(as_u32c(src)) ^ 0x800000); goto CONV_END; +conv_123x_12Bx: as_u32(dst) = sx24s(as_u32c(src) ^ 0x8000); goto CONV_END; +conv_123x_B210: as_u32(dst) = bswap_32(as_u32c(src) ^ 0x8000) << 8; goto CONV_END; +conv_123x_012B: as_u32(dst) = (as_u32c(src) >> 8) ^ 0x80; goto CONV_END; +conv_1234_xxx1: as_u8(dst) = as_u32c(src) >> 24; goto CONV_END; +conv_1234_xx12: as_u16(dst) = as_u32c(src) >> 16; goto CONV_END; +conv_1234_xx21: as_u16(dst) = bswap_16(as_u32c(src) >> 16); goto CONV_END; +conv_1234_x123: as_u32(dst) = sx24(as_u32c(src) >> 8); goto CONV_END; +conv_1234_321x: as_u32(dst) = sx24s(bswap_32(as_u32c(src)) << 8); goto CONV_END; +conv_1234_1234: as_u32(dst) = as_u32c(src); goto CONV_END; +conv_1234_4321: as_u32(dst) = bswap_32(as_u32c(src)); goto CONV_END; +conv_1234_xxx9: as_u8(dst) = (as_u32c(src) >> 24) ^ 0x80; goto CONV_END; +conv_1234_xx92: as_u16(dst) = (as_u32c(src) >> 16) ^ 0x8000; goto CONV_END; +conv_1234_xx29: as_u16(dst) = bswap_16(as_u32c(src) >> 16) ^ 0x80; goto CONV_END; +conv_1234_x923: as_u32(dst) = sx24((as_u32c(src) >> 8) ^ 0x800000); goto CONV_END; +conv_1234_329x: as_u32(dst) = sx24s((bswap_32(as_u32c(src)) ^ 0x80) << 8); goto CONV_END; +conv_1234_9234: as_u32(dst) = as_u32c(src) ^ 0x80000000; goto CONV_END; +conv_1234_4329: as_u32(dst) = bswap_32(as_u32c(src)) ^ 0x80; goto CONV_END; +conv_1234_xxx4: as_u8(dst) = as_u32c(src) & 0xff; goto CONV_END; +conv_1234_xx43: as_u16(dst) = bswap_16(as_u32c(src)); goto CONV_END; +conv_1234_xx34: as_u16(dst) = as_u32c(src) & 0xffff; goto CONV_END; +conv_1234_x432: as_u32(dst) = sx24(bswap_32(as_u32c(src)) >> 8); goto CONV_END; +conv_1234_234x: as_u32(dst) = sx24s(as_u32c(src) << 8); goto CONV_END; +conv_1234_xxxC: as_u8(dst) = (as_u32c(src) & 0xff) ^ 0x80; goto CONV_END; +conv_1234_xxC3: as_u16(dst) = bswap_16(as_u32c(src) ^ 0x80); goto CONV_END; +conv_1234_xx3C: as_u16(dst) = (as_u32c(src) & 0xffff) ^ 0x80; goto CONV_END; +conv_1234_xC32: as_u32(dst) = sx24((bswap_32(as_u32c(src)) >> 8) ^ 0x800000); goto CONV_END; +conv_1234_23Cx: as_u32(dst) = sx24s((as_u32c(src) ^ 0x80) << 8); goto CONV_END; +conv_1234_C321: as_u32(dst) = bswap_32(as_u32c(src) ^ 0x80); goto CONV_END; +conv_1234_123C: as_u32(dst) = as_u32c(src) ^ 0x80; goto CONV_END; +} +#endif + +#ifdef GET16_LABELS +/* src_wid src_endswap sign_toggle */ +static void *const get16_labels[4 * 2 * 2 + 4 * 3] = { + &&get16_1_10, /* 8h -> 16h */ + &&get16_1_90, /* 8h ^> 16h */ + &&get16_1_10, /* 8s -> 16h */ + &&get16_1_90, /* 8s ^> 16h */ + &&get16_12_12, /* 16h -> 16h */ + &&get16_12_92, /* 16h ^> 16h */ + &&get16_12_21, /* 16s -> 16h */ + &&get16_12_A1, /* 16s ^> 16h */ + &&get16_0123_12, /* 24h -> 16h */ + &&get16_0123_92, /* 24h ^> 16h */ + &&get16_1230_32, /* 24s -> 16h */ + &&get16_1230_B2, /* 24s ^> 16h */ + &&get16_1234_12, /* 32h -> 16h */ + &&get16_1234_92, /* 32h ^> 16h */ + &&get16_1234_43, /* 32s -> 16h */ + &&get16_1234_C3, /* 32s ^> 16h */ + /* 3bytes format */ + &&get16_123_12, /* 24h -> 16h */ + &&get16_123_92, /* 24h ^> 16h */ + &&get16_123_32, /* 24s -> 16h */ + &&get16_123_B2, /* 24s ^> 16h */ + &&get16_123_12_20, /* 20h -> 16h */ + &&get16_123_92_20, /* 20h ^> 16h */ + &&get16_123_32_20, /* 20s -> 16h */ + &&get16_123_B2_20, /* 20s ^> 16h */ + &&get16_123_12_18, /* 18h -> 16h */ + &&get16_123_92_18, /* 18h ^> 16h */ + &&get16_123_32_18, /* 18s -> 16h */ + &&get16_123_B2_18, /* 18s ^> 16h */ +}; +#endif + +#ifdef GET16_END +while(0) { +get16_1_10: sample = (u_int16_t)as_u8c(src) << 8; goto GET16_END; +get16_1_90: sample = (u_int16_t)(as_u8c(src) ^ 0x80) << 8; goto GET16_END; +get16_12_12: sample = as_u16c(src); goto GET16_END; +get16_12_92: sample = as_u16c(src) ^ 0x8000; goto GET16_END; +get16_12_21: sample = bswap_16(as_u16c(src)); goto GET16_END; +get16_12_A1: sample = bswap_16(as_u16c(src) ^ 0x80); goto GET16_END; +get16_0123_12: sample = as_u32c(src) >> 8; goto GET16_END; +get16_0123_92: sample = (as_u32c(src) >> 8) ^ 0x8000; goto GET16_END; +get16_1230_32: sample = bswap_16(as_u32c(src) >> 8); goto GET16_END; +get16_1230_B2: sample = bswap_16((as_u32c(src) >> 8) ^ 0x80); goto GET16_END; +get16_1234_12: sample = as_u32c(src) >> 16; goto GET16_END; +get16_1234_92: sample = (as_u32c(src) >> 16) ^ 0x8000; goto GET16_END; +get16_1234_43: sample = bswap_16(as_u32c(src)); goto GET16_END; +get16_1234_C3: sample = bswap_16(as_u32c(src) ^ 0x80); goto GET16_END; +get16_123_12: sample = _get_triple(src) >> 8; goto GET16_END; +get16_123_92: sample = (_get_triple(src) >> 8) ^ 0x8000; goto GET16_END; +get16_123_32: sample = _get_triple_s(src) >> 8; goto GET16_END; +get16_123_B2: sample = (_get_triple_s(src) >> 8) ^ 0x8000; goto GET16_END; +get16_123_12_20: sample = _get_triple(src) >> 4; goto GET16_END; +get16_123_92_20: sample = (_get_triple(src) >> 4) ^ 0x8000; goto GET16_END; +get16_123_32_20: sample = _get_triple_s(src) >> 4; goto GET16_END; +get16_123_B2_20: sample = (_get_triple_s(src) >> 4) ^ 0x8000; goto GET16_END; +get16_123_12_18: sample = _get_triple(src) >> 2; goto GET16_END; +get16_123_92_18: sample = (_get_triple(src) >> 2) ^ 0x8000; goto GET16_END; +get16_123_32_18: sample = _get_triple_s(src) >> 2; goto GET16_END; +get16_123_B2_18: sample = (_get_triple_s(src) >> 2) ^ 0x8000; goto GET16_END; +} +#endif + +#ifdef PUT16_LABELS +/* dst_wid dst_endswap sign_toggle */ +static void *const put16_labels[4 * 2 * 2 + 4 * 3] = { + &&put16_12_1, /* 16h -> 8h */ + &&put16_12_9, /* 16h ^> 8h */ + &&put16_12_1, /* 16h -> 8s */ + &&put16_12_9, /* 16h ^> 8s */ + &&put16_12_12, /* 16h -> 16h */ + &&put16_12_92, /* 16h ^> 16h */ + &&put16_12_21, /* 16h -> 16s */ + &&put16_12_29, /* 16h ^> 16s */ + &&put16_12_0120, /* 16h -> 24h */ + &&put16_12_0920, /* 16h ^> 24h */ + &&put16_12_0210, /* 16h -> 24s */ + &&put16_12_0290, /* 16h ^> 24s */ + &&put16_12_1200, /* 16h -> 32h */ + &&put16_12_9200, /* 16h ^> 32h */ + &&put16_12_0021, /* 16h -> 32s */ + &&put16_12_0029, /* 16h ^> 32s */ + /* 3bytes format */ + &&put16_12_120, /* 16h -> 24h */ + &&put16_12_920, /* 16h ^> 24h */ + &&put16_12_021, /* 16h -> 24s */ + &&put16_12_029, /* 16h ^> 24s */ + &&put16_12_120_20, /* 16h -> 20h */ + &&put16_12_920_20, /* 16h ^> 20h */ + &&put16_12_021_20, /* 16h -> 20s */ + &&put16_12_029_20, /* 16h ^> 20s */ + &&put16_12_120_18, /* 16h -> 18h */ + &&put16_12_920_18, /* 16h ^> 18h */ + &&put16_12_021_18, /* 16h -> 18s */ + &&put16_12_029_18, /* 16h ^> 18s */ +}; +#endif + +#ifdef PUT16_END +while (0) { +put16_12_1: as_u8(dst) = sample >> 8; goto PUT16_END; +put16_12_9: as_u8(dst) = (sample >> 8) ^ 0x80; goto PUT16_END; +put16_12_12: as_u16(dst) = sample; goto PUT16_END; +put16_12_92: as_u16(dst) = sample ^ 0x8000; goto PUT16_END; +put16_12_21: as_u16(dst) = bswap_16(sample); goto PUT16_END; +put16_12_29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT16_END; +put16_12_0120: as_u32(dst) = sx24((u_int32_t)sample << 8); goto PUT16_END; +put16_12_0920: as_u32(dst) = sx24((u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_0210: as_u32(dst) = sx24s((u_int32_t)bswap_16(sample) << 8); goto PUT16_END; +put16_12_0290: as_u32(dst) = sx24s((u_int32_t)(bswap_16(sample) ^ 0x80) << 8); goto PUT16_END; +put16_12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT16_END; +put16_12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT16_END; +put16_12_0021: as_u32(dst) = (u_int32_t)bswap_16(sample); goto PUT16_END; +put16_12_0029: as_u32(dst) = (u_int32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; +put16_12_120: _put_triple(dst, (u_int32_t)sample << 8); goto PUT16_END; +put16_12_920: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_021: _put_triple_s(dst, (u_int32_t)sample << 8); goto PUT16_END; +put16_12_029: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_120_20: _put_triple(dst, (u_int32_t)sample << 4); goto PUT16_END; +put16_12_920_20: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_021_20: _put_triple_s(dst, (u_int32_t)sample << 4); goto PUT16_END; +put16_12_029_20: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_120_18: _put_triple(dst, (u_int32_t)sample << 2); goto PUT16_END; +put16_12_920_18: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 2); goto PUT16_END; +put16_12_021_18: _put_triple_s(dst, (u_int32_t)sample << 2); goto PUT16_END; +put16_12_029_18: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 2); goto PUT16_END; +} +#endif + +#ifdef CONV24_LABELS +#define GET32_LABELS +#define PUT32_LABELS +#endif + +#ifdef GET32_LABELS +/* src_wid src_endswap sign_toggle */ +static void *const get32_labels[4 * 2 * 2 + 4 * 3] = { + &&get32_1_1000, /* 8h -> 32h */ + &&get32_1_9000, /* 8h ^> 32h */ + &&get32_1_1000, /* 8s -> 32h */ + &&get32_1_9000, /* 8s ^> 32h */ + &&get32_12_1200, /* 16h -> 32h */ + &&get32_12_9200, /* 16h ^> 32h */ + &&get32_12_2100, /* 16s -> 32h */ + &&get32_12_A100, /* 16s ^> 32h */ + &&get32_0123_1230, /* 24h -> 32h */ + &&get32_0123_9230, /* 24h ^> 32h */ + &&get32_1230_3210, /* 24s -> 32h */ + &&get32_1230_B210, /* 24s ^> 32h */ + &&get32_1234_1234, /* 32h -> 32h */ + &&get32_1234_9234, /* 32h ^> 32h */ + &&get32_1234_4321, /* 32s -> 32h */ + &&get32_1234_C321, /* 32s ^> 32h */ + /* 3bytes format */ + &&get32_123_1230, /* 24h -> 32h */ + &&get32_123_9230, /* 24h ^> 32h */ + &&get32_123_3210, /* 24s -> 32h */ + &&get32_123_B210, /* 24s ^> 32h */ + &&get32_123_1230_20, /* 20h -> 32h */ + &&get32_123_9230_20, /* 20h ^> 32h */ + &&get32_123_3210_20, /* 20s -> 32h */ + &&get32_123_B210_20, /* 20s ^> 32h */ + &&get32_123_1230_18, /* 18h -> 32h */ + &&get32_123_9230_18, /* 18h ^> 32h */ + &&get32_123_3210_18, /* 18s -> 32h */ + &&get32_123_B210_18, /* 18s ^> 32h */ +}; +#endif + +#ifdef CONV24_END +#define GET32_END __conv24_get +#endif + +#ifdef GET32_END +while (0) { +get32_1_1000: sample = (u_int32_t)as_u8c(src) << 24; goto GET32_END; +get32_1_9000: sample = (u_int32_t)(as_u8c(src) ^ 0x80) << 24; goto GET32_END; +get32_12_1200: sample = (u_int32_t)as_u16c(src) << 16; goto GET32_END; +get32_12_9200: sample = (u_int32_t)(as_u16c(src) ^ 0x8000) << 16; goto GET32_END; +get32_12_2100: sample = (u_int32_t)bswap_16(as_u16c(src)) << 16; goto GET32_END; +get32_12_A100: sample = (u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto GET32_END; +get32_0123_1230: sample = as_u32c(src) << 8; goto GET32_END; +get32_0123_9230: sample = (as_u32c(src) << 8) ^ 0x80000000; goto GET32_END; +get32_1230_3210: sample = bswap_32(as_u32c(src) >> 8); goto GET32_END; +get32_1230_B210: sample = bswap_32((as_u32c(src) >> 8) ^ 0x80); goto GET32_END; +get32_1234_1234: sample = as_u32c(src); goto GET32_END; +get32_1234_9234: sample = as_u32c(src) ^ 0x80000000; goto GET32_END; +get32_1234_4321: sample = bswap_32(as_u32c(src)); goto GET32_END; +get32_1234_C321: sample = bswap_32(as_u32c(src) ^ 0x80); goto GET32_END; +get32_123_1230: sample = _get_triple(src) << 8; goto GET32_END; +get32_123_9230: sample = (_get_triple(src) << 8) ^ 0x80000000; goto GET32_END; +get32_123_3210: sample = _get_triple_s(src) << 8; goto GET32_END; +get32_123_B210: sample = (_get_triple_s(src) << 8) ^ 0x80000000; goto GET32_END; +get32_123_1230_20: sample = _get_triple(src) << 12; goto GET32_END; +get32_123_9230_20: sample = (_get_triple(src) << 12) ^ 0x80000000; goto GET32_END; +get32_123_3210_20: sample = _get_triple_s(src) << 12; goto GET32_END; +get32_123_B210_20: sample = (_get_triple_s(src) << 12) ^ 0x80000000; goto GET32_END; +get32_123_1230_18: sample = _get_triple(src) << 14; goto GET32_END; +get32_123_9230_18: sample = (_get_triple(src) << 14) ^ 0x80000000; goto GET32_END; +get32_123_3210_18: sample = _get_triple_s(src) << 14; goto GET32_END; +get32_123_B210_18: sample = (_get_triple_s(src) << 14) ^ 0x80000000; goto GET32_END; +} +#endif + +#ifdef CONV24_END +__conv24_get: goto *put; +#define PUT32_END CONV24_END +#endif + +#ifdef PUT32_LABELS +/* dst_wid dst_endswap sign_toggle */ +static void *const put32_labels[4 * 2 * 2 + 4 * 3] = { + &&put32_1234_1, /* 32h -> 8h */ + &&put32_1234_9, /* 32h ^> 8h */ + &&put32_1234_1, /* 32h -> 8s */ + &&put32_1234_9, /* 32h ^> 8s */ + &&put32_1234_12, /* 32h -> 16h */ + &&put32_1234_92, /* 32h ^> 16h */ + &&put32_1234_21, /* 32h -> 16s */ + &&put32_1234_29, /* 32h ^> 16s */ + &&put32_1234_0123, /* 32h -> 24h */ + &&put32_1234_0923, /* 32h ^> 24h */ + &&put32_1234_3210, /* 32h -> 24s */ + &&put32_1234_3290, /* 32h ^> 24s */ + &&put32_1234_1234, /* 32h -> 32h */ + &&put32_1234_9234, /* 32h ^> 32h */ + &&put32_1234_4321, /* 32h -> 32s */ + &&put32_1234_4329, /* 32h ^> 32s */ + /* 3bytes format */ + &&put32_1234_123, /* 32h -> 24h */ + &&put32_1234_923, /* 32h ^> 24h */ + &&put32_1234_321, /* 32h -> 24s */ + &&put32_1234_329, /* 32h ^> 24s */ + &&put32_1234_123_20, /* 32h -> 24h */ + &&put32_1234_923_20, /* 32h ^> 24h */ + &&put32_1234_321_20, /* 32h -> 24s */ + &&put32_1234_329_20, /* 32h ^> 24s */ + &&put32_1234_123_18, /* 32h -> 24h */ + &&put32_1234_923_18, /* 32h ^> 24h */ + &&put32_1234_321_18, /* 32h -> 24s */ + &&put32_1234_329_18, /* 32h ^> 24s */ +}; +#endif + +#ifdef CONV24_LABELS +#undef GET32_LABELS +#undef PUT32_LABELS +#endif + +#ifdef PUT32_END +while (0) { +put32_1234_1: as_u8(dst) = sample >> 24; goto PUT32_END; +put32_1234_9: as_u8(dst) = (sample >> 24) ^ 0x80; goto PUT32_END; +put32_1234_12: as_u16(dst) = sample >> 16; goto PUT32_END; +put32_1234_92: as_u16(dst) = (sample >> 16) ^ 0x8000; goto PUT32_END; +put32_1234_21: as_u16(dst) = bswap_16(sample >> 16); goto PUT32_END; +put32_1234_29: as_u16(dst) = bswap_16(sample >> 16) ^ 0x80; goto PUT32_END; +put32_1234_0123: as_u32(dst) = sx24(sample >> 8); goto PUT32_END; +put32_1234_0923: as_u32(dst) = sx24((sample >> 8) ^ 0x800000); goto PUT32_END; +put32_1234_3210: as_u32(dst) = sx24s(bswap_32(sample) << 8); goto PUT32_END; +put32_1234_3290: as_u32(dst) = sx24s((bswap_32(sample) ^ 0x80) << 8); goto PUT32_END; +put32_1234_1234: as_u32(dst) = sample; goto PUT32_END; +put32_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT32_END; +put32_1234_4321: as_u32(dst) = bswap_32(sample); goto PUT32_END; +put32_1234_4329: as_u32(dst) = bswap_32(sample) ^ 0x80; goto PUT32_END; +put32_1234_123: _put_triple(dst, sample >> 8); goto PUT32_END; +put32_1234_923: _put_triple(dst, (sample ^ 0x80000000) >> 8); goto PUT32_END; +put32_1234_321: _put_triple_s(dst, sample >> 8); goto PUT32_END; +put32_1234_329: _put_triple_s(dst, (sample ^ 0x80000000) >> 8); goto PUT32_END; +put32_1234_123_20: _put_triple(dst, sample >> 12); goto PUT32_END; +put32_1234_923_20: _put_triple(dst, (sample ^ 0x80000000) >> 12); goto PUT32_END; +put32_1234_321_20: _put_triple_s(dst, sample >> 12); goto PUT32_END; +put32_1234_329_20: _put_triple_s(dst, (sample ^ 0x80000000) >> 12); goto PUT32_END; +put32_1234_123_18: _put_triple(dst, sample >> 14); goto PUT32_END; +put32_1234_923_18: _put_triple(dst, (sample ^ 0x80000000) >> 14); goto PUT32_END; +put32_1234_321_18: _put_triple_s(dst, sample >> 14); goto PUT32_END; +put32_1234_329_18: _put_triple_s(dst, (sample ^ 0x80000000) >> 14); goto PUT32_END; +} +#endif + +#ifdef CONV24_END +#undef GET32_END +#undef PUT32_END +#endif + +#ifdef GETU_LABELS +/* width endswap sign_toggle */ +static void *const getu_labels[4 * 2 * 2] = { + &&getu_1_1, /* 8h -> 8h */ + &&getu_1_9, /* 8h ^> 8h */ + &&getu_1_1, /* 8s -> 8h */ + &&getu_1_9, /* 8s ^> 8h */ + &&getu_12_12, /* 16h -> 16h */ + &&getu_12_92, /* 16h ^> 16h */ + &&getu_12_21, /* 16s -> 16h */ + &&getu_12_A1, /* 16s ^> 16h */ + &&getu_0123_0123, /* 24h -> 24h */ + &&getu_0123_0923, /* 24h ^> 24h */ + &&getu_1230_0321, /* 24s -> 24h */ + &&getu_1230_0B21, /* 24s ^> 24h */ + &&getu_1234_1234, /* 32h -> 32h */ + &&getu_1234_9234, /* 32h ^> 32h */ + &&getu_1234_4321, /* 32s -> 32h */ + &&getu_1234_C321, /* 32s ^> 32h */ +}; +#endif + +#ifdef GETU_END +while (0) { +getu_1_1: sample = as_u8c(src); goto GETU_END; +getu_1_9: sample = as_u8c(src) ^ 0x80; goto GETU_END; +getu_12_12: sample = as_u16c(src); goto GETU_END; +getu_12_92: sample = as_u16c(src) ^ 0x8000; goto GETU_END; +getu_12_21: sample = bswap_16(as_u16c(src)); goto GETU_END; +getu_12_A1: sample = bswap_16(as_u16c(src) ^ 0x80); goto GETU_END; +getu_0123_0123: sample = sx24(as_u32c(src)); goto GETU_END; +getu_0123_0923: sample = sx24(as_u32c(src) ^ 0x800000); goto GETU_END; +getu_1230_0321: sample = sx24(bswap_32(as_u32c(src))); goto GETU_END; +getu_1230_0B21: sample = sx24(bswap_32(as_u32c(src) ^ 0x8000)); goto GETU_END; +getu_1234_1234: sample = as_u32c(src); goto GETU_END; +getu_1234_9234: sample = as_u32c(src) ^ 0x80000000; goto GETU_END; +getu_1234_4321: sample = bswap_32(as_u32c(src)); goto GETU_END; +getu_1234_C321: sample = bswap_32(as_u32c(src) ^ 0x80); goto GETU_END; +} +#endif + +#ifdef GETS_LABELS +/* width endswap sign_toggle */ +static void *const gets_labels[4 * 2 * 2] = { + &&gets_1_1, /* 8h -> 8h */ + &&gets_1_9, /* 8h ^> 8h */ + &&gets_1_1, /* 8s -> 8h */ + &&gets_1_9, /* 8s ^> 8h */ + &&gets_12_12, /* 16h -> 16h */ + &&gets_12_92, /* 16h ^> 16h */ + &&gets_12_21, /* 16s -> 16h */ + &&gets_12_A1, /* 16s ^> 16h */ + &&gets_0123_0123, /* 24h -> 24h */ + &&gets_0123_0923, /* 24h ^> 24h */ + &&gets_1230_0321, /* 24s -> 24h */ + &&gets_1230_0B21, /* 24s ^> 24h */ + &&gets_1234_1234, /* 32h -> 32h */ + &&gets_1234_9234, /* 32h ^> 32h */ + &&gets_1234_4321, /* 32s -> 32h */ + &&gets_1234_C321, /* 32s ^> 32h */ +}; +#endif + +#ifdef GETS_END +while (0) { +gets_1_1: sample = as_s8c(src); goto GETS_END; +gets_1_9: sample = (int8_t)(as_s8c(src) ^ 0x80); goto GETS_END; +gets_12_12: sample = as_s16c(src); goto GETS_END; +gets_12_92: sample = (int16_t)(as_s16c(src) ^ 0x8000); goto GETS_END; +gets_12_21: sample = (int16_t)bswap_16(as_s16c(src)); goto GETS_END; +gets_12_A1: sample = (int16_t)bswap_16(as_s16c(src) ^ 0x80); goto GETS_END; +gets_0123_0123: sample = sx24((int32_t)(as_s32c(src) << 8) >> 8); goto GETS_END; +gets_0123_0923: sample = sx24((int32_t)((as_s32c(src) ^ 0x800000) << 8) >> 8); goto GETS_END; +gets_1230_0321: sample = sx24((int32_t)(bswap_32(as_s32c(src)) << 8) >> 8); goto GETS_END; +gets_1230_0B21: sample = sx24((int32_t)(bswap_32(as_s32c(src) ^ 0x8000) << 8) >> 8); goto GETS_END; +gets_1234_1234: sample = as_s32c(src); goto GETS_END; +gets_1234_9234: sample = (int32_t)(as_s32c(src) ^ 0x80000000); goto GETS_END; +gets_1234_4321: sample = (int32_t)bswap_32(as_s32c(src)); goto GETS_END; +gets_1234_C321: sample = (int32_t)bswap_32(as_s32c(src) ^ 0x80); goto GETS_END; +} +#endif + +#ifdef PUT_LABELS +/* width endswap sign_toggle */ +static void *const put_labels[4 * 2 * 2] = { + &&put_1_1, /* 8h -> 8h */ + &&put_1_9, /* 8h ^> 8h */ + &&put_1_1, /* 8h -> 8s */ + &&put_1_9, /* 8h ^> 8s */ + &&put_12_12, /* 16h -> 16h */ + &&put_12_92, /* 16h ^> 16h */ + &&put_12_21, /* 16h -> 16s */ + &&put_12_29, /* 16h ^> 16s */ + &&put_0123_0123, /* 24h -> 24h */ + &&put_0123_0923, /* 24h ^> 24h */ + &&put_0123_3210, /* 24h -> 24s */ + &&put_0123_3290, /* 24h ^> 24s */ + &&put_1234_1234, /* 32h -> 32h */ + &&put_1234_9234, /* 32h ^> 32h */ + &&put_1234_4321, /* 32h -> 32s */ + &&put_1234_4329, /* 32h ^> 32s */ +}; +#endif + +#ifdef PUT_END +put_1_1: as_s8(dst) = sample; goto PUT_END; +put_1_9: as_u8(dst) = sample ^ 0x80; goto PUT_END; +put_12_12: as_s16(dst) = sample; goto PUT_END; +put_12_92: as_u16(dst) = sample ^ 0x8000; goto PUT_END; +put_12_21: as_s16(dst) = bswap_16(sample); goto PUT_END; +put_12_29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT_END; +/* this always writes the unused byte in 24-bit formats as 0x00 */ +put_0123_0123: as_s32(dst) = sx24(sample & 0x00ffffff); goto PUT_END; +put_0123_0923: as_u32(dst) = sx24((sample & 0x00ffffff) ^ 0x800000); goto PUT_END; +put_0123_3210: as_s32(dst) = sx24s(bswap_32(sample) & 0xffffff00); goto PUT_END; +put_0123_3290: as_u32(dst) = sx24s((bswap_32(sample) & 0xffffff00) ^ 0x8000); goto PUT_END; +put_1234_1234: as_s32(dst) = sample; goto PUT_END; +put_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_END; +put_1234_4321: as_s32(dst) = bswap_32(sample); goto PUT_END; +put_1234_4329: as_u32(dst) = bswap_32(sample) ^ 0x80; goto PUT_END; +#endif + +#ifdef PUT32F_LABELS +/* type (0 = float, 1 = float64), endswap */ +static void *const put32float_labels[2 * 2] = { + &&put32f_1234_1234F, /* 32h -> (float)h */ + &&put32f_1234_4321F, /* 32h -> (float)s */ + &&put32f_1234_1234D, /* 32h -> (float64)h */ + &&put32f_1234_4321D, /* 32h -> (float64)s */ +}; +#endif + +#ifdef PUT32F_END +put32f_1234_1234F: as_float(dst) = (float_t)((int32_t)sample) / (float_t)0x80000000UL; goto PUT32F_END; +put32f_1234_4321F: tmp_float.f = (float_t)((int32_t)sample) / (float_t)0x80000000UL; + as_u32(dst) = bswap_32(tmp_float.i); goto PUT32F_END; +put32f_1234_1234D: as_double(dst) = (double_t)((int32_t)sample) / (double_t)0x80000000UL; goto PUT32F_END; +put32f_1234_4321D: tmp_double.d = (double_t)((int32_t)sample) / (double_t)0x80000000UL; + as_u64(dst) = bswap_64(tmp_double.l); goto PUT32F_END; +#endif + +#ifdef GET32F_LABELS +/* type (0 = float, 1 = float64), endswap */ +static void *const get32float_labels[2 * 2] = { + &&get32f_1234F_1234, /* (float)h -> 32h */ + &&get32f_4321F_1234, /* (float)s -> 32h */ + &&get32f_1234D_1234, /* (float64)h -> 32h */ + &&get32f_4321D_1234, /* (float64)s -> 32h */ +}; +#endif + +#ifdef GET32F_END +get32f_1234F_1234: tmp_float.f = as_floatc(src); + if (tmp_float.f >= 1.0) + sample = 0x7fffffff; + else if (tmp_float.f <= -1.0) + sample = 0x80000000; + else + sample = (int32_t)(tmp_float.f * (float_t)0x80000000UL); + goto GET32F_END; +get32f_4321F_1234: tmp_float.i = bswap_32(as_u32c(src)); + if (tmp_float.f >= 1.0) + sample = 0x7fffffff; + else if (tmp_float.f <= -1.0) + sample = 0x80000000; + else + sample = (int32_t)(tmp_float.f * (float_t)0x80000000UL); + goto GET32F_END; +get32f_1234D_1234: tmp_double.d = as_doublec(src); + if (tmp_double.d >= 1.0) + sample = 0x7fffffff; + else if (tmp_double.d <= -1.0) + sample = 0x80000000; + else + sample = (int32_t)(tmp_double.d * (double_t)0x80000000UL); + goto GET32F_END; +get32f_4321D_1234: tmp_double.l = bswap_64(as_u64c(src)); + if (tmp_double.d >= 1.0) + sample = 0x7fffffff; + else if (tmp_double.d <= -1.0) + sample = 0x80000000; + else + sample = (int32_t)(tmp_double.d * (double_t)0x80000000UL); + goto GET32F_END; +#endif + +#ifdef NORMS_LABELS +static inline void _norms(const void *src, void *dst, + int src_wid, + int dst_sign, int dst_wid, int dst_end) +{ + int32_t s; + switch (src_wid) { + case 8: + s = *(int32_t*)src; + if (s >= 0x7f) + goto _max; + else if (s <= -0x80) + goto _min; + break; + case 16: + s = *(int32_t*)src; + if (s >= 0x7fff) + goto _max; + else if (s <= -0x8000) + goto _min; + break; + case 24: + s = *(int32_t*)src; + if (s >= 0x7fffff) + goto _max; + else if (s <= -0x800000) + goto _min; + break; + case 32: + { + int64_t s64; + s64 = *(int64_t*)src; + if (s64 >= 0x7fffffff) + goto _max; + else if (s64 <= -0x80000000) + goto _min; + s = s64; + break; + } + default: + assert(0); + return; + } + if (src_wid < dst_wid) { + unsigned int bits = dst_wid - src_wid; + s *= 1 << bits; + } else if (src_wid > dst_wid) { + unsigned int bits = src_wid - dst_wid; + s = (s + (1 << (bits - 1))) / (1 << bits); + } + if (!dst_sign) + s += (1U << (dst_wid - 1)); + switch (dst_wid) { + case 8: + *(u_int8_t*)dst = s; + break; + case 16: + if (dst_end) + s = bswap_16(s); + *(u_int16_t*)dst = s; + break; + case 24: + case 32: + if (dst_end) + s = bswap_32(s); + *(u_int32_t*)dst = s; + break; + } + return; + + _min: + switch (dst_wid) { + case 8: + if (dst_sign) + *(u_int8_t*)dst = 0x80; + else + *(u_int8_t*)dst = 0; + break; + case 16: + if (dst_sign) + *(u_int16_t*)dst = dst_end ? 0x0080 : 0x8000; + else + *(u_int16_t*)dst = 0; + break; + case 24: + if (dst_sign) + *(u_int32_t*)dst = dst_end ? 0x00008000 : 0x00800000; + else + *(u_int32_t*)dst = 0; + break; + case 32: + if (dst_sign) + *(u_int32_t*)dst = dst_end ? 0x00000080 : 0x80000000; + else + *(u_int32_t*)dst = 0; + break; + default: + assert(0); + break; + } + return; + + _max: + switch (dst_wid) { + case 8: + if (dst_sign) + *(u_int8_t*)dst = 0x7f; + else + *(u_int8_t*)dst = 0xff; + break; + case 16: + if (dst_sign) + *(u_int16_t*)dst = dst_end ? 0xff7f : 0x7fff; + else + *(u_int16_t*)dst = 0; + break; + case 24: + if (dst_sign) + *(u_int32_t*)dst = dst_end ? 0xffff7f00 : 0x007fffff; + else + *(u_int32_t*)dst = 0; + break; + case 32: + if (dst_sign) + *(u_int32_t*)dst = dst_end ? 0xffffff7f : 0x7fffffff; + else + *(u_int32_t*)dst = 0; + break; + default: + assert(0); + break; + } + return; +} + +/* src_wid dst_sign dst_wid dst_end */ +static void *const norms_labels[4 * 2 * 4 * 2] = { + &&norms_8_u8, /* s8 -> u8 */ + &&norms_8_u8, /* s8 -> u8 */ + &&norms_8_u16h, /* s8 -> u16h */ + &&norms_8_u16s, /* s8 -> u16s */ + &&norms_8_u24h, /* s8 -> u24h */ + &&norms_8_u24s, /* s8 -> u24s */ + &&norms_8_u32h, /* s8 -> u32h */ + &&norms_8_u32s, /* s8 -> u32s */ + &&norms_8_s8, /* s8 -> s8 */ + &&norms_8_s8, /* s8 -> s8 */ + &&norms_8_s16h, /* s8 -> s16h */ + &&norms_8_s16s, /* s8 -> s16s */ + &&norms_8_s24h, /* s8 -> s24h */ + &&norms_8_s24s, /* s8 -> s24s */ + &&norms_8_s32h, /* s8 -> s32h */ + &&norms_8_s32s, /* s8 -> s32s */ + &&norms_16_u8, /* s16 -> u8 */ + &&norms_16_u8, /* s16 -> u8 */ + &&norms_16_u16h, /* s16 -> u16h */ + &&norms_16_u16s, /* s16 -> u16s */ + &&norms_16_u24h, /* s16 -> u24h */ + &&norms_16_u24s, /* s16 -> u24s */ + &&norms_16_u32h, /* s16 -> u32h */ + &&norms_16_u32s, /* s16 -> u32s */ + &&norms_16_s8, /* s16 -> s8 h*/ + &&norms_16_s8, /* s16 -> s8 */ + &&norms_16_s16h, /* s16 -> s16h */ + &&norms_16_s16s, /* s16 -> s16s */ + &&norms_16_s24h, /* s16 -> s24h */ + &&norms_16_s24s, /* s16 -> s24s */ + &&norms_16_s32h, /* s16 -> s32h */ + &&norms_16_s32s, /* s16 -> s32s */ + &&norms_24_u8, /* s24 -> u8 */ + &&norms_24_u8, /* s24 -> u8 */ + &&norms_24_u16h, /* s24 -> u16h */ + &&norms_24_u16s, /* s24 -> u16s */ + &&norms_24_u24h, /* s24 -> u24h */ + &&norms_24_u24s, /* s24 -> u24s */ + &&norms_24_u32h, /* s24 -> u32h */ + &&norms_24_u32s, /* s24 -> u32s */ + &&norms_24_s8, /* s24 -> s8 */ + &&norms_24_s8, /* s24 -> s8 */ + &&norms_24_s16h, /* s24 -> s16h */ + &&norms_24_s16s, /* s24 -> s16s */ + &&norms_24_s24h, /* s24 -> s24h */ + &&norms_24_s24s, /* s24 -> s24s */ + &&norms_24_s32h, /* s24 -> s32h */ + &&norms_24_s32s, /* s24 -> s32s */ + &&norms_32_u8, /* s32 -> u8 */ + &&norms_32_u8, /* s32 -> u8 */ + &&norms_32_u16h, /* s32 -> u16h */ + &&norms_32_u16s, /* s32 -> u16s */ + &&norms_32_u24h, /* s32 -> u24h */ + &&norms_32_u24s, /* s32 -> u24s */ + &&norms_32_u32h, /* s32 -> u32h */ + &&norms_32_u32s, /* s32 -> u32s */ + &&norms_32_s8, /* s32 -> s8 */ + &&norms_32_s8, /* s32 -> s8 */ + &&norms_32_s16h, /* s32 -> s16h */ + &&norms_32_s16s, /* s32 -> s16s */ + &&norms_32_s24h, /* s32 -> s24h */ + &&norms_32_s24s, /* s32 -> s24s */ + &&norms_32_s32h, /* s32 -> s32h */ + &&norms_32_s32s, /* s32 -> s32s */ +}; +#endif + +#ifdef NORMS_END +norms_8_u8: _norms(src, dst, 8, 0, 8, 0); goto NORMS_END; +norms_8_u16h: _norms(src, dst, 8, 0, 16, 0); goto NORMS_END; +norms_8_u16s: _norms(src, dst, 8, 0, 16, 1); goto NORMS_END; +norms_8_u24h: _norms(src, dst, 8, 0, 24, 0); goto NORMS_END; +norms_8_u24s: _norms(src, dst, 8, 0, 24, 1); goto NORMS_END; +norms_8_u32h: _norms(src, dst, 8, 0, 32, 0); goto NORMS_END; +norms_8_u32s: _norms(src, dst, 8, 0, 32, 1); goto NORMS_END; +norms_8_s8: _norms(src, dst, 8, 1, 8, 0); goto NORMS_END; +norms_8_s16h: _norms(src, dst, 8, 1, 16, 0); goto NORMS_END; +norms_8_s16s: _norms(src, dst, 8, 1, 16, 1); goto NORMS_END; +norms_8_s24h: _norms(src, dst, 8, 1, 24, 0); goto NORMS_END; +norms_8_s24s: _norms(src, dst, 8, 1, 24, 1); goto NORMS_END; +norms_8_s32h: _norms(src, dst, 8, 1, 32, 0); goto NORMS_END; +norms_8_s32s: _norms(src, dst, 8, 1, 32, 1); goto NORMS_END; +norms_16_u8: _norms(src, dst, 16, 0, 8, 0); goto NORMS_END; +norms_16_u16h: _norms(src, dst, 16, 0, 16, 0); goto NORMS_END; +norms_16_u16s: _norms(src, dst, 16, 0, 16, 1); goto NORMS_END; +norms_16_u24h: _norms(src, dst, 16, 0, 24, 0); goto NORMS_END; +norms_16_u24s: _norms(src, dst, 16, 0, 24, 1); goto NORMS_END; +norms_16_u32h: _norms(src, dst, 16, 0, 32, 0); goto NORMS_END; +norms_16_u32s: _norms(src, dst, 16, 0, 32, 1); goto NORMS_END; +norms_16_s8: _norms(src, dst, 16, 1, 8, 0); goto NORMS_END; +norms_16_s16h: _norms(src, dst, 16, 1, 16, 0); goto NORMS_END; +norms_16_s16s: _norms(src, dst, 16, 1, 16, 1); goto NORMS_END; +norms_16_s24h: _norms(src, dst, 16, 1, 24, 0); goto NORMS_END; +norms_16_s24s: _norms(src, dst, 16, 1, 24, 1); goto NORMS_END; +norms_16_s32h: _norms(src, dst, 16, 1, 32, 0); goto NORMS_END; +norms_16_s32s: _norms(src, dst, 16, 1, 32, 1); goto NORMS_END; +norms_24_u8: _norms(src, dst, 24, 0, 8, 0); goto NORMS_END; +norms_24_u16h: _norms(src, dst, 24, 0, 16, 0); goto NORMS_END; +norms_24_u16s: _norms(src, dst, 24, 0, 16, 1); goto NORMS_END; +norms_24_u24h: _norms(src, dst, 24, 0, 24, 0); goto NORMS_END; +norms_24_u24s: _norms(src, dst, 24, 0, 24, 1); goto NORMS_END; +norms_24_u32h: _norms(src, dst, 24, 0, 32, 0); goto NORMS_END; +norms_24_u32s: _norms(src, dst, 24, 0, 32, 1); goto NORMS_END; +norms_24_s8: _norms(src, dst, 24, 1, 8, 0); goto NORMS_END; +norms_24_s16h: _norms(src, dst, 24, 1, 16, 0); goto NORMS_END; +norms_24_s16s: _norms(src, dst, 24, 1, 16, 1); goto NORMS_END; +norms_24_s24h: _norms(src, dst, 24, 1, 24, 0); goto NORMS_END; +norms_24_s24s: _norms(src, dst, 24, 1, 24, 1); goto NORMS_END; +norms_24_s32h: _norms(src, dst, 24, 1, 32, 0); goto NORMS_END; +norms_24_s32s: _norms(src, dst, 24, 1, 32, 1); goto NORMS_END; +norms_32_u8: _norms(src, dst, 32, 0, 8, 0); goto NORMS_END; +norms_32_u16h: _norms(src, dst, 32, 0, 16, 0); goto NORMS_END; +norms_32_u16s: _norms(src, dst, 32, 0, 16, 1); goto NORMS_END; +norms_32_u24h: _norms(src, dst, 32, 0, 24, 0); goto NORMS_END; +norms_32_u24s: _norms(src, dst, 32, 0, 24, 1); goto NORMS_END; +norms_32_u32h: _norms(src, dst, 32, 0, 32, 0); goto NORMS_END; +norms_32_u32s: _norms(src, dst, 32, 0, 32, 1); goto NORMS_END; +norms_32_s8: _norms(src, dst, 32, 1, 8, 0); goto NORMS_END; +norms_32_s16h: _norms(src, dst, 32, 1, 16, 0); goto NORMS_END; +norms_32_s16s: _norms(src, dst, 32, 1, 16, 1); goto NORMS_END; +norms_32_s24h: _norms(src, dst, 32, 1, 24, 0); goto NORMS_END; +norms_32_s24s: _norms(src, dst, 32, 1, 24, 1); goto NORMS_END; +norms_32_s32h: _norms(src, dst, 32, 1, 32, 0); goto NORMS_END; +norms_32_s32s: _norms(src, dst, 32, 1, 32, 1); goto NORMS_END; +#endif + + +#undef as_u8 +#undef as_u16 +#undef as_u32 +#undef as_s8 +#undef as_s16 +#undef as_s32 +#undef as_float +#undef as_double + +#undef as_u8c +#undef as_u16c +#undef as_u32c +#undef as_s8c +#undef as_s16c +#undef as_s32c +#undef as_floatc +#undef as_doublec + +#undef _get_triple +#undef _get_triple_s +#undef _get_triple_le +#undef _get_triple_be +#undef _put_triple +#undef _put_triple_s +#undef _put_triple_le +#undef _put_triple_be + diff --git a/src/pcm/scopes/Makefile.am b/src/pcm/scopes/Makefile.am new file mode 100644 index 0000000..0ce845d --- /dev/null +++ b/src/pcm/scopes/Makefile.am @@ -0,0 +1,9 @@ +pkglibdir = $(libdir)/@PACKAGE@/scopes + +AM_CFLAGS = -g -O2 -W -Wall + +pkglib_LTLIBRARIES = scope-level.la + +scope_level_la_SOURCES = level.c +scope_level_la_LDFLAGS = -module +scope_level_la_LIBADD = -lncurses diff --git a/src/pcm/scopes/Makefile.in b/src/pcm/scopes/Makefile.in new file mode 100644 index 0000000..ac83b91 --- /dev/null +++ b/src/pcm/scopes/Makefile.in @@ -0,0 +1,551 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/pcm/scopes +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +scope_level_la_DEPENDENCIES = +am_scope_level_la_OBJECTS = level.lo +scope_level_la_OBJECTS = $(am_scope_level_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +scope_level_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(scope_level_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(scope_level_la_SOURCES) +DIST_SOURCES = $(scope_level_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkglibdir = $(libdir)/@PACKAGE@/scopes +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = -g -O2 -W -Wall +pkglib_LTLIBRARIES = scope-level.la +scope_level_la_SOURCES = level.c +scope_level_la_LDFLAGS = -module +scope_level_la_LIBADD = -lncurses +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/pcm/scopes/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/pcm/scopes/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +scope-level.la: $(scope_level_la_OBJECTS) $(scope_level_la_DEPENDENCIES) + $(AM_V_CCLD)$(scope_level_la_LINK) -rpath $(pkglibdir) $(scope_level_la_OBJECTS) $(scope_level_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/level.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/pcm/scopes/level.c b/src/pcm/scopes/level.c new file mode 100644 index 0000000..eea9eac --- /dev/null +++ b/src/pcm/scopes/level.c @@ -0,0 +1,271 @@ +/* + * PCM - Meter level plugin (ncurses) + * Copyright (c) 2001 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#define BAR_WIDTH 70 +/* milliseconds to go from 32767 to 0 */ +#define DECAY_MS 400 +/* milliseconds for peak to disappear */ +#define PEAK_MS 800 + +typedef struct _snd_pcm_scope_level_channel { + int16_t level; + int16_t peak; + unsigned int peak_age; +} snd_pcm_scope_level_channel_t; + +typedef struct _snd_pcm_scope_level { + snd_pcm_t *pcm; + snd_pcm_scope_t *s16; + snd_pcm_scope_level_channel_t *channels; + snd_pcm_uframes_t old; + int top; + WINDOW *win; + unsigned int bar_width; + unsigned int decay_ms; + unsigned int peak_ms; +} snd_pcm_scope_level_t; + +static int level_enable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + int y, x; + level->channels = calloc(snd_pcm_meter_get_channels(level->pcm), sizeof(*level->channels)); + if (!level->channels) { + free(level); + return -ENOMEM; + } + snd_pcm_scope_set_callback_private(scope, level); + level->win = initscr(); + winsdelln(level->win, snd_pcm_meter_get_channels(level->pcm)); + getyx(level->win, y, x); + level->top = y; + return 0; +} + +static void level_disable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + endwin(); + free(level->channels); +} + +static void level_close(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + free(level); +} + +static void level_start(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED) +{ +} + +static void level_stop(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + unsigned int c; + for (c = 0; c < snd_pcm_meter_get_channels(level->pcm); c++) { + move(level->top + c, 0); + clrtoeol(); + } + move(level->top, 0); + refresh(); +} + +static void level_update(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + snd_pcm_t *pcm = level->pcm; + snd_pcm_sframes_t size; + snd_pcm_uframes_t size1, size2; + snd_pcm_uframes_t offset, cont; + unsigned int c, channels; + unsigned int ms; + static char bar[256] = { [0 ... 255] = '#' }; + int max_decay; + size = snd_pcm_meter_get_now(pcm) - level->old; + if (size < 0) + size += snd_pcm_meter_get_boundary(pcm); + offset = level->old % snd_pcm_meter_get_bufsize(pcm); + cont = snd_pcm_meter_get_bufsize(pcm) - offset; + size1 = size; + if (size1 > cont) + size1 = cont; + size2 = size - size1; + ms = size * 1000 / snd_pcm_meter_get_rate(pcm); + max_decay = 32768 * ms / level->decay_ms; + channels = snd_pcm_meter_get_channels(pcm); + for (c = 0; c < channels; c++) { + int16_t *ptr; + int s, lev = 0; + snd_pcm_uframes_t n; + snd_pcm_scope_level_channel_t *l; + unsigned int lev_pos, peak_pos; + l = &level->channels[c]; + ptr = snd_pcm_scope_s16_get_channel_buffer(level->s16, c) + offset; + for (n = size1; n > 0; n--) { + s = *ptr; + if (s < 0) + s = -s; + if (s > lev) + lev = s; + ptr++; + } + ptr = snd_pcm_scope_s16_get_channel_buffer(level->s16, c); + for (n = size2; n > 0; n--) { + s = *ptr; + if (s < 0) + s = -s; + if (s > lev) + lev = s; + ptr++; + } + l->level = lev; + l->peak_age += ms; + if (l->peak_age >= level->peak_ms || + lev >= l->peak) { + l->peak = lev; + l->peak_age = 0; + } + if (lev < l->level - max_decay) + lev = l->level - max_decay; + move(level->top + c, 0); + lev_pos = lev * level->bar_width / 32768; + peak_pos = l->peak * level->bar_width / 32768; + addnstr(bar, lev_pos); + clrtoeol(); + mvaddch(level->top + c, peak_pos - 1, '#'); + } + move(level->top, 0); + refresh(); + level->old = snd_pcm_meter_get_now(pcm); +} + +static void level_reset(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + snd_pcm_t *pcm = level->pcm; + memset(level->channels, 0, snd_pcm_meter_get_channels(pcm) * sizeof(*level->channels)); + level->old = snd_pcm_meter_get_now(pcm); +} + +snd_pcm_scope_ops_t level_ops = { + .enable = level_enable, + .disable = level_disable, + .close = level_close, + .start = level_start, + .stop = level_stop, + .update = level_update, + .reset = level_reset, +}; + +int snd_pcm_scope_level_open(snd_pcm_t *pcm, const char *name, + unsigned int bar_width, unsigned int decay_ms, + unsigned int peak_ms, + snd_pcm_scope_t **scopep) +{ + snd_pcm_scope_t *scope, *s16; + snd_pcm_scope_level_t *level; + int err = snd_pcm_scope_malloc(&scope); + if (err < 0) + return err; + level = calloc(1, sizeof(*level)); + if (!level) { + free(scope); + return -ENOMEM; + } + level->pcm = pcm; + level->bar_width = bar_width; + level->decay_ms = decay_ms; + level->peak_ms = peak_ms; + s16 = snd_pcm_meter_search_scope(pcm, "s16"); + if (!s16) { + err = snd_pcm_scope_s16_open(pcm, "s16", &s16); + if (err < 0) { + free(scope); + free(level); + return err; + } + } + level->s16 = s16; + snd_pcm_scope_set_ops(scope, &level_ops); + snd_pcm_scope_set_callback_private(scope, level); + if (name) + snd_pcm_scope_set_name(scope, strdup(name)); + snd_pcm_meter_add_scope(pcm, scope); + *scopep = scope; + return 0; +} + +int _snd_pcm_scope_level_open(snd_pcm_t *pcm, const char *name, + snd_config_t *root, snd_config_t *conf) +{ + snd_config_iterator_t i, next; + snd_pcm_scope_t *scope; + long bar_width = -1, decay_ms = -1, peak_ms = -1; + int err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "bar_width") == 0) { + err = snd_config_get_integer(n, &bar_width); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "decay_ms") == 0) { + err = snd_config_get_integer(n, &decay_ms); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "peak_ms") == 0) { + err = snd_config_get_integer(n, &peak_ms); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (bar_width < 0) + bar_width = BAR_WIDTH; + if (decay_ms < 0) + decay_ms = DECAY_MS; + if (peak_ms < 0) + peak_ms = PEAK_MS; + return snd_pcm_scope_level_open(pcm, name, bar_width, decay_ms, peak_ms, + &scope); +} diff --git a/src/rawmidi/Makefile.am b/src/rawmidi/Makefile.am new file mode 100644 index 0000000..2470c7a --- /dev/null +++ b/src/rawmidi/Makefile.am @@ -0,0 +1,12 @@ +EXTRA_LTLIBRARIES=librawmidi.la + +librawmidi_la_SOURCES = rawmidi.c rawmidi_hw.c rawmidi_symbols.c +if BUILD_SEQ +librawmidi_la_SOURCES += rawmidi_virt.c +endif +noinst_HEADERS = rawmidi_local.h + +all: librawmidi.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/rawmidi/Makefile.in b/src/rawmidi/Makefile.in new file mode 100644 index 0000000..5f45061 --- /dev/null +++ b/src/rawmidi/Makefile.in @@ -0,0 +1,500 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_SEQ_TRUE@am__append_1 = rawmidi_virt.c +subdir = src/rawmidi +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +librawmidi_la_LIBADD = +am__librawmidi_la_SOURCES_DIST = rawmidi.c rawmidi_hw.c \ + rawmidi_symbols.c rawmidi_virt.c +@BUILD_SEQ_TRUE@am__objects_1 = rawmidi_virt.lo +am_librawmidi_la_OBJECTS = rawmidi.lo rawmidi_hw.lo rawmidi_symbols.lo \ + $(am__objects_1) +librawmidi_la_OBJECTS = $(am_librawmidi_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(librawmidi_la_SOURCES) +DIST_SOURCES = $(am__librawmidi_la_SOURCES_DIST) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = librawmidi.la +librawmidi_la_SOURCES = rawmidi.c rawmidi_hw.c rawmidi_symbols.c \ + $(am__append_1) +noinst_HEADERS = rawmidi_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/rawmidi/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/rawmidi/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +librawmidi.la: $(librawmidi_la_OBJECTS) $(librawmidi_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(librawmidi_la_OBJECTS) $(librawmidi_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi_symbols.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi_virt.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +all: librawmidi.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c new file mode 100644 index 0000000..b28488a --- /dev/null +++ b/src/rawmidi/rawmidi.c @@ -0,0 +1,1006 @@ +/** + * \file rawmidi/rawmidi.c + * \brief RawMidi Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2000-2001 + * + * See the \ref rawmidi page for more details. + */ +/* + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page rawmidi RawMidi interface + +

RawMidi Interface is designed to write or read raw (unchanged) MIDI +data over the MIDI line without any timestamps defined in interface. MIDI +stands Musical Instrument Digital Interface and more information about +this standard can be found at http://www.midi.org. + +\section rawmidi_general_overview General overview + +The rawmidi implementation uses ring buffers to store outgoing and incoming +MIDI stream. The buffer size is tunable and drivers report underruns for incoming +stream as well. + +\section rawmidi_open Open handling + +RawMidi devices are opened exclusively for a selected direction. +While more than one process may not open a given MIDI device in the same +direction simultaneously, separate processes may open a single MIDI device +in different directions (i.e. process one opens a MIDI device in write +direction and process two opens the same device in read direction). + +\subsection rawmidi_open_nonblock Nonblocking open (flag) + +Using #SND_RAWMIDI_NONBLOCK flag for snd_rawmidi_open() or snd_rawmidi_open_lconf() +instruct device driver to return the -EBUSY error when device is already occupied +with another application. This flag also changes behaviour of snd_rawmidi_write() +and snd_rawmidi_read() returning -EAGAIN when no more bytes can be processed. + +Note: In opposite (default) behaviour, application is blocked until device resources +are free. + +\subsection rawmidi_open_append Append open (flag) + +Using #SND_RAWMIDI_APPEND flag (output only) instruct device driver to append +contents of written buffer - passed by snd_rawmidi_write() - atomically +to output ring buffer in the kernel space. This flag also means that device +is not opened exclusively, so more applications can share given rawmidi device. +Note that applications must send the whole MIDI message including the running status, +because another writting application might break the MIDI message in the output +buffer. + +\subsection rawmidi_open_sync Sync open (flag) + +Using #SND_RAWMIDI_SYNC flag (output only) assures that the contents of output +buffer specified using snd_rawmidi_write() is always drained before the function +exits. This behaviour is same like 'snd_rawmidi_write() followed by +snd_rawmidi_drain() immediately'. + +\subsection rawmidi_io I/O handling + +There is only standard read/write access to device internal ring buffer. Use +snd_rawmidi_read() and snd_rawmidi_write() functions to obtain / write MIDI bytes. + +\subsection rawmidi_dev_names RawMidi naming conventions + +The ALSA library uses a generic string representation for names of devices. +The devices might be virtual, physical or a mix of both. The generic string +is passed to \link ::snd_rawmidi_open() \endlink or \link ::snd_rawmidi_open_lconf() \endlink. +It contains two parts: device name and arguments. Devices and arguments are described +in configuration files. The usual place for default definitions is at /usr/share/alsa/alsa.conf. + +\subsection rawmidi_dev_names_default + +The default device is equal to hw device. The defaults are used: + +defaults.rawmidi.card 0 +defaults.rawmidi.device 0 +defaults.rawmidi.subdevice -1 + +These defaults can be freely overwritten in local configuration files. + +Example: + +\code +default +\endcode + +\subsection rawmidi_dev_names_hw HW device + +The hw device description uses the hw plugin. The three arguments (in order: CARD,DEV,SUBDEV) +specify card number or identifier, device number and subdevice number (-1 means any). + +Example: + +\code +hw +hw:0 +hw:0,0 +hw:supersonic,1 +hw:soundwave,1,2 +hw:DEV=1,CARD=soundwave,SUBDEV=2 +\endcode + +\section rawmidi_examples Examples + +The full featured examples with cross-links: + +\par Simple input/output test program +\ref example_test_rawmidi "example code" +\par +This example shows open and read/write rawmidi operations. + +*/ + +/** + * \example ../test/rawmidi.c + * \anchor example_test_rawmidi + */ + +#include +#include +#include +#include +#include +#include "rawmidi_local.h" + +/** + * \brief setup the default parameters + * \param rawmidi RawMidi handle + * \param params pointer to a snd_rawmidi_params_t structure + * \return 0 on success otherwise a negative error code + */ +static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params) +{ + assert(rawmidi); + assert(params); + params->buffer_size = page_size(); + params->avail_min = 1; + params->no_active_sensing = 1; + return 0; +} + +static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, snd_config_t *rawmidi_root, + snd_config_t *rawmidi_conf, int mode) +{ + const char *str; + char buf[256]; + int err; + snd_config_t *conf, *type_conf = NULL; + snd_config_iterator_t i, next; + snd_rawmidi_params_t params; + const char *id; + const char *lib = NULL, *open_name = NULL; + int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **, + const char *, snd_config_t *, snd_config_t *, int) = NULL; +#ifndef PIC + extern void *snd_rawmidi_open_symbols(void); +#endif + void *h = NULL; + if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) { + if (name) + SNDERR("Invalid type for RAWMIDI %s definition", name); + else + SNDERR("Invalid type for RAWMIDI definition"); + return -EINVAL; + } + err = snd_config_search(rawmidi_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(rawmidi_root, "rawmidi_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for RAWMIDI type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + open_name = buf; + snprintf(buf, sizeof(buf), "_snd_rawmidi_%s_open", str); + } +#ifndef PIC + snd_rawmidi_open_symbols(); +#endif + h = snd_dlopen(lib, RTLD_NOW); + if (h) + open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION)); + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + if (err >= 0) + err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode); + if (err < 0) + return err; + if (inputp) { + (*inputp)->dl_handle = h; h = NULL; + snd_rawmidi_params_default(*inputp, ¶ms); + err = snd_rawmidi_params(*inputp, ¶ms); + assert(err >= 0); + } + if (outputp) { + (*outputp)->dl_handle = h; + snd_rawmidi_params_default(*outputp, ¶ms); + err = snd_rawmidi_params(*outputp, ¶ms); + assert(err >= 0); + } + return 0; +} + +static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + snd_config_t *root, const char *name, int mode) +{ + int err; + snd_config_t *rawmidi_conf; + err = snd_config_search_definition(root, "rawmidi", name, &rawmidi_conf); + if (err < 0) { + SNDERR("Unknown RawMidi %s", name); + return err; + } + err = snd_rawmidi_open_conf(inputp, outputp, name, root, rawmidi_conf, mode); + snd_config_delete(rawmidi_conf); + return err; +} + +/** + * \brief Opens a new connection to the RawMidi interface. + * \param inputp Returned input handle (NULL if not wanted) + * \param outputp Returned output handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, int mode) +{ + int err; + assert((inputp || outputp) && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_rawmidi_open_noupdate(inputp, outputp, snd_config, name, mode); +} + +/** + * \brief Opens a new connection to the RawMidi interface using local configuration + * \param inputp Returned input handle (NULL if not wanted) + * \param outputp Returned output handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \param lconf Local configuration + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int snd_rawmidi_open_lconf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, int mode, snd_config_t *lconf) +{ + assert((inputp || outputp) && name && lconf); + return snd_rawmidi_open_noupdate(inputp, outputp, lconf, name, mode); +} + +/** + * \brief close RawMidi handle + * \param rawmidi RawMidi handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified RawMidi handle and frees all associated + * resources. + */ +int snd_rawmidi_close(snd_rawmidi_t *rawmidi) +{ + int err; + assert(rawmidi); + err = rawmidi->ops->close(rawmidi); + free(rawmidi->name); + if (rawmidi->dl_handle) + snd_dlclose(rawmidi->dl_handle); + free(rawmidi); + return err; +} + +/** + * \brief get identifier of RawMidi handle + * \param rawmidi a RawMidi handle + * \return ascii identifier of RawMidi handle + * + * Returns the ASCII identifier of given RawMidi handle. It's the same + * identifier specified in snd_rawmidi_open(). + */ +const char *snd_rawmidi_name(snd_rawmidi_t *rawmidi) +{ + assert(rawmidi); + return rawmidi->name; +} + +/** + * \brief get type of RawMidi handle + * \param rawmidi a RawMidi handle + * \return type of RawMidi handle + * + * Returns the type #snd_rawmidi_type_t of given RawMidi handle. + */ +snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rawmidi) +{ + assert(rawmidi); + return rawmidi->type; +} + +/** + * \brief get stream (direction) of RawMidi handle + * \param rawmidi a RawMidi handle + * \return stream of RawMidi handle + * + * Returns the stream #snd_rawmidi_stream_t of given RawMidi handle. + */ +snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi) +{ + assert(rawmidi); + return rawmidi->stream; +} + +/** + * \brief get count of poll descriptors for RawMidi handle + * \param rawmidi RawMidi handle + * \return count of poll descriptors + */ +int snd_rawmidi_poll_descriptors_count(snd_rawmidi_t *rawmidi) +{ + assert(rawmidi); + return 1; +} + +/** + * \brief get poll descriptors + * \param rawmidi RawMidi handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_rawmidi_poll_descriptors(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int space) +{ + assert(rawmidi); + if (space >= 1) { + pfds->fd = rawmidi->poll_fd; + pfds->events = rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT ? (POLLOUT|POLLERR|POLLNVAL) : (POLLIN|POLLERR|POLLNVAL); + return 1; + } + return 0; +} + +/** + * \brief get returned events from poll descriptors + * \param rawmidi rawmidi RawMidi handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(rawmidi && pfds && revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +/** + * \brief set nonblock mode + * \param rawmidi RawMidi handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + * + * The nonblock mode cannot be used when the stream is in + * #SND_RAWMIDI_APPEND state. + */ +int snd_rawmidi_nonblock(snd_rawmidi_t *rawmidi, int nonblock) +{ + int err; + assert(rawmidi); + assert(!(rawmidi->mode & SND_RAWMIDI_APPEND)); + if ((err = rawmidi->ops->nonblock(rawmidi, nonblock)) < 0) + return err; + if (nonblock) + rawmidi->mode |= SND_RAWMIDI_NONBLOCK; + else + rawmidi->mode &= ~SND_RAWMIDI_NONBLOCK; + return 0; +} + +/** + * \brief get size of the snd_rawmidi_info_t structure in bytes + * \return size of the snd_rawmidi_info_t structure in bytes + */ +size_t snd_rawmidi_info_sizeof() +{ + return sizeof(snd_rawmidi_info_t); +} + +/** + * \brief allocate a new snd_rawmidi_info_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_rawmidi_params_t structure using the standard + * malloc C library function. + */ +int snd_rawmidi_info_malloc(snd_rawmidi_info_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_rawmidi_info_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_rawmidi_info_t structure + * \param info pointer to the snd_rawmidi_info_t structure to free + * + * Frees the given snd_rawmidi_params_t structure using the standard + * free C library function. + */ +void snd_rawmidi_info_free(snd_rawmidi_info_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_rawmidi_info_t structure to another + * \param dst destination snd_rawmidi_info_t structure + * \param src source snd_rawmidi_info_t structure + */ +void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief get rawmidi device number + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi device number + */ +unsigned int snd_rawmidi_info_get_device(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->device; +} + +/** + * \brief get rawmidi subdevice number + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi subdevice number + */ +unsigned int snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->subdevice; +} + +/** + * \brief get rawmidi stream identification + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi stream identification + */ +snd_rawmidi_stream_t snd_rawmidi_info_get_stream(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->stream; +} + +/** + * \brief get rawmidi card number + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi card number + */ +int snd_rawmidi_info_get_card(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->card; +} + +/** + * \brief get rawmidi flags + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi flags + */ +unsigned int snd_rawmidi_info_get_flags(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->flags; +} + +/** + * \brief get rawmidi hardware driver identifier + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi hardware driver identifier + */ +const char *snd_rawmidi_info_get_id(const snd_rawmidi_info_t *info) +{ + assert(info); + return (const char *)info->id; +} + +/** + * \brief get rawmidi hardware driver name + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi hardware driver name + */ +const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *info) +{ + assert(info); + return (const char *)info->name; +} + +/** + * \brief get rawmidi subdevice name + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi subdevice name + */ +const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *info) +{ + assert(info); + return (const char *)info->subname; +} + +/** + * \brief get rawmidi count of subdevices + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi count of subdevices + */ +unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->subdevices_count; +} + +/** + * \brief get rawmidi available count of subdevices + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi available count of subdevices + */ +unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *info) +{ + assert(info); + return info->subdevices_avail; +} + +/** + * \brief set rawmidi device number + * \param info pointer to a snd_rawmidi_info_t structure + * \param val device number + */ +void snd_rawmidi_info_set_device(snd_rawmidi_info_t *info, unsigned int val) +{ + assert(info); + info->device = val; +} + +/** + * \brief set rawmidi subdevice number + * \param info pointer to a snd_rawmidi_info_t structure + * \param val subdevice number + */ +void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *info, unsigned int val) +{ + assert(info); + info->subdevice = val; +} + +/** + * \brief set rawmidi stream identifier + * \param info pointer to a snd_rawmidi_info_t structure + * \param val rawmidi stream identifier + */ +void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *info, snd_rawmidi_stream_t val) +{ + assert(info); + info->stream = val; +} + +/** + * \brief get information about RawMidi handle + * \param rawmidi RawMidi handle + * \param info pointer to a snd_rawmidi_info_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_rawmidi_info(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t * info) +{ + assert(rawmidi); + assert(info); + return rawmidi->ops->info(rawmidi, info); +} + +/** + * \brief get size of the snd_rawmidi_params_t structure in bytes + * \return size of the snd_rawmidi_params_t structure in bytes + */ +size_t snd_rawmidi_params_sizeof() +{ + return sizeof(snd_rawmidi_params_t); +} + +/** + * \brief allocate the snd_rawmidi_params_t structure + * \param params returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_rawmidi_params_t structure using the standard + * malloc C library function. + */ +int snd_rawmidi_params_malloc(snd_rawmidi_params_t **params) +{ + assert(params); + *params = calloc(1, sizeof(snd_rawmidi_params_t)); + if (!*params) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_rawmidi_params_t structure + * \param params pointer to the #snd_rawmidi_params_t structure to free + * + * Frees the given snd_rawmidi_params_t structure using the standard + * free C library function. + */ +void snd_rawmidi_params_free(snd_rawmidi_params_t *params) +{ + assert(params); + free(params); +} + +/** + * \brief copy one snd_rawmidi_params_t structure to another + * \param dst destination snd_rawmidi_params_t structure + * \param src source snd_rawmidi_params_t structure + */ +void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief set rawmidi I/O ring buffer size + * \param rawmidi RawMidi handle + * \param params pointer to a snd_rawmidi_params_t structure + * \param val size in bytes + * \return 0 on success otherwise a negative error code + */ +#ifndef DOXYGEN +int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val) +#else +int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val) +#endif +{ + assert(rawmidi && params); + assert(val > params->avail_min); + params->buffer_size = val; + return 0; +} + +/** + * \brief get rawmidi I/O ring buffer size + * \param params pointer to a snd_rawmidi_params_t structure + * \return size of rawmidi I/O ring buffer in bytes + */ +size_t snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t *params) +{ + assert(params); + return params->buffer_size; +} + +/** + * \brief set minimum available bytes in rawmidi I/O ring buffer for wakeup + * \param rawmidi RawMidi handle + * \param params pointer to a snd_rawmidi_params_t structure + * \param val desired value + */ +#ifndef DOXYGEN +int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, size_t val) +#else +int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, size_t val) +#endif +{ + assert(rawmidi && params); + assert(val < params->buffer_size); + params->avail_min = val; + return 0; +} + +/** + * \brief get minimum available bytes in rawmidi I/O ring buffer for wakeup + * \param params pointer to snd_rawmidi_params_t structure + * \return minimum available bytes + */ +size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params) +{ + assert(params); + return params->avail_min; +} + +/** + * \brief set no-active-sensing action on snd_rawmidi_close() + * \param rawmidi RawMidi handle + * \param params pointer to snd_rawmidi_params_t structure + * \param val value: 0 = enable to send the active sensing message, 1 = disable + * \return 0 on success otherwise a negative error code + */ +#ifndef DOXYGEN +int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi ATTRIBUTE_UNUSED, snd_rawmidi_params_t *params, int val) +#else +int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, int val) +#endif +{ + assert(rawmidi && params); + params->no_active_sensing = val; + return 0; +} + +/** + * \brief get no-active-sensing action status + * \param params pointer to snd_rawmidi_params_t structure + * \return the current status (0 = enable, 1 = disable the active sensing message) + */ +int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params) +{ + assert(params); + return params->no_active_sensing; +} + +/** + * \brief set parameters about rawmidi stream + * \param rawmidi RawMidi handle + * \param params pointer to a snd_rawmidi_params_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_rawmidi_params(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t * params) +{ + int err; + assert(rawmidi); + assert(params); + err = rawmidi->ops->params(rawmidi, params); + if (err < 0) + return err; + rawmidi->buffer_size = params->buffer_size; + rawmidi->avail_min = params->avail_min; + rawmidi->no_active_sensing = params->no_active_sensing; + return 0; +} + +/** + * \brief get current parameters about rawmidi stream + * \param rawmidi RawMidi handle + * \param params pointer to a snd_rawmidi_params_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_rawmidi_params_current(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params) +{ + assert(rawmidi); + assert(params); + params->buffer_size = rawmidi->buffer_size; + params->avail_min = rawmidi->avail_min; + params->no_active_sensing = rawmidi->no_active_sensing; + return 0; +} + +/** + * \brief get size of the snd_rawmidi_status_t structure in bytes + * \return size of the snd_rawmidi_status_t structure in bytes + */ +size_t snd_rawmidi_status_sizeof() +{ + return sizeof(snd_rawmidi_status_t); +} + +/** + * \brief allocate the snd_rawmidi_status_t structure + * \param ptr returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_rawmidi_status_t structure using the standard + * malloc C library function. + */ +int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_rawmidi_status_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_rawmidi_status_t structure + * \param status pointer to the snd_rawmidi_status_t structure to free + * + * Frees the given snd_rawmidi_status_t structure using the standard + * free C library function. + */ +void snd_rawmidi_status_free(snd_rawmidi_status_t *status) +{ + assert(status); + free(status); +} + +/** + * \brief copy one snd_rawmidi_status_t structure to another + * \param dst destination snd_rawmidi_status_t structure + * \param src source snd_rawmidi_status_t structure + */ +void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief get the start timestamp + * \param status pointer to a snd_rawmidi_status_t structure + * \param tstamp returned timestamp value + */ +void snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t *status, snd_htimestamp_t *tstamp) +{ + assert(status && tstamp); + *tstamp = status->tstamp; +} + +/** + * \brief get current available bytes in the rawmidi I/O ring buffer + * \param status pointer to a snd_rawmidi_status_t structure + * \return current available bytes in the rawmidi I/O ring buffer + */ +size_t snd_rawmidi_status_get_avail(const snd_rawmidi_status_t *status) +{ + assert(status); + return status->avail; +} + +/** + * \brief get count of xruns + * \param status pointer to a snd_rawmidi_status_t structure + * \return count of xruns + */ +size_t snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t *status) +{ + assert(status); + return status->xruns; +} + +/** + * \brief get status of rawmidi stream + * \param rawmidi RawMidi handle + * \param status pointer to a snd_rawmidi_status_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_rawmidi_status(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t * status) +{ + assert(rawmidi); + assert(status); + return rawmidi->ops->status(rawmidi, status); +} + +/** + * \brief drop all bytes in the rawmidi I/O ring buffer immediately + * \param rawmidi RawMidi handle + * \return 0 on success otherwise a negative error code + */ +int snd_rawmidi_drop(snd_rawmidi_t *rawmidi) +{ + assert(rawmidi); + return rawmidi->ops->drop(rawmidi); +} + +/** + * \brief drain all bytes in the rawmidi I/O ring buffer + * \param rawmidi RawMidi handle + * \return 0 on success otherwise a negative error code + * + * Waits until all MIDI bytes are not drained (sent) to the + * hardware device. + */ +int snd_rawmidi_drain(snd_rawmidi_t *rawmidi) +{ + assert(rawmidi); + return rawmidi->ops->drain(rawmidi); +} + +/** + * \brief write MIDI bytes to MIDI stream + * \param rawmidi RawMidi handle + * \param buffer buffer containing MIDI bytes + * \param size output buffer size in bytes + */ +ssize_t snd_rawmidi_write(snd_rawmidi_t *rawmidi, const void *buffer, size_t size) +{ + assert(rawmidi); + assert(rawmidi->stream == SND_RAWMIDI_STREAM_OUTPUT); + assert(buffer || size == 0); + return rawmidi->ops->write(rawmidi, buffer, size); +} + +/** + * \brief read MIDI bytes from MIDI stream + * \param rawmidi RawMidi handle + * \param buffer buffer to store the input MIDI bytes + * \param size input buffer size in bytes + */ +ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size) +{ + assert(rawmidi); + assert(rawmidi->stream == SND_RAWMIDI_STREAM_INPUT); + assert(buffer || size == 0); + return (rawmidi->ops->read)(rawmidi, buffer, size); +} + +#ifndef DOC_HIDDEN +int snd_rawmidi_conf_generic_id(const char *id) +{ + static const char ids[][8] = { + "comment", + "type", + "hint", + }; + unsigned int k; + + for (k = 0; k < sizeof ids / sizeof *ids; ++k) { + if (strcmp(id, ids[k]) == 0) + return 1; + } + return 0; +} +#endif diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c new file mode 100644 index 0000000..e08dca7 --- /dev/null +++ b/src/rawmidi/rawmidi_hw.c @@ -0,0 +1,361 @@ +/* + * RawMIDI - Hardware + * Copyright (c) 2000 by Jaroslav Kysela + * Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "../control/control_local.h" +#include "rawmidi_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_rawmidi_hw = ""; +#endif + +#define SNDRV_FILE_RAWMIDI ALSA_DEVICE_DIRECTORY "midiC%iD%i" +#define SNDRV_RAWMIDI_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 0) + +#ifndef DOC_HIDDEN +typedef struct { + int open; + int fd; + int card, device, subdevice; +} snd_rawmidi_hw_t; +#endif + +static int snd_rawmidi_hw_close(snd_rawmidi_t *rmidi) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + int err = 0; + + hw->open--; + if (hw->open) + return 0; + if (close(hw->fd)) { + err = -errno; + SYSERR("close failed\n"); + } + free(hw); + return err; +} + +static int snd_rawmidi_hw_nonblock(snd_rawmidi_t *rmidi, int nonblock) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + long flags; + + if ((flags = fcntl(hw->fd, F_GETFL)) < 0) { + SYSERR("F_GETFL failed"); + return -errno; + } + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(hw->fd, F_SETFL, flags) < 0) { + SYSERR("F_SETFL for O_NONBLOCK failed"); + return -errno; + } + return 0; +} + +static int snd_rawmidi_hw_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + info->stream = rmidi->stream; + if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_INFO, info) < 0) { + SYSERR("SNDRV_RAWMIDI_IOCTL_INFO failed"); + return -errno; + } + return 0; +} + +static int snd_rawmidi_hw_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + params->stream = rmidi->stream; + if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_PARAMS, params) < 0) { + SYSERR("SNDRV_RAWMIDI_IOCTL_PARAMS failed"); + return -errno; + } + return 0; +} + +static int snd_rawmidi_hw_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + status->stream = rmidi->stream; + if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_STATUS, status) < 0) { + SYSERR("SNDRV_RAWMIDI_IOCTL_STATUS failed"); + return -errno; + } + return 0; +} + +static int snd_rawmidi_hw_drop(snd_rawmidi_t *rmidi) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + int str = rmidi->stream; + if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_DROP, &str) < 0) { + SYSERR("SNDRV_RAWMIDI_IOCTL_DROP failed"); + return -errno; + } + return 0; +} + +static int snd_rawmidi_hw_drain(snd_rawmidi_t *rmidi) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + int str = rmidi->stream; + if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_DRAIN, &str) < 0) { + SYSERR("SNDRV_RAWMIDI_IOCTL_DRAIN failed"); + return -errno; + } + return 0; +} + +static ssize_t snd_rawmidi_hw_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + ssize_t result; + result = write(hw->fd, buffer, size); + if (result < 0) + return -errno; + return result; +} + +static ssize_t snd_rawmidi_hw_read(snd_rawmidi_t *rmidi, void *buffer, size_t size) +{ + snd_rawmidi_hw_t *hw = rmidi->private_data; + ssize_t result; + result = read(hw->fd, buffer, size); + if (result < 0) + return -errno; + return result; +} + +static const snd_rawmidi_ops_t snd_rawmidi_hw_ops = { + .close = snd_rawmidi_hw_close, + .nonblock = snd_rawmidi_hw_nonblock, + .info = snd_rawmidi_hw_info, + .params = snd_rawmidi_hw_params, + .status = snd_rawmidi_hw_status, + .drop = snd_rawmidi_hw_drop, + .drain = snd_rawmidi_hw_drain, + .write = snd_rawmidi_hw_write, + .read = snd_rawmidi_hw_read, +}; + + +int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, int card, int device, int subdevice, + int mode) +{ + int fd, ver, ret; + int attempt = 0; + char filename[sizeof(SNDRV_FILE_RAWMIDI) + 20]; + snd_ctl_t *ctl; + snd_rawmidi_t *rmidi; + snd_rawmidi_hw_t *hw = NULL; + snd_rawmidi_info_t info; + int fmode; + + if (inputp) + *inputp = NULL; + if (outputp) + *outputp = NULL; + + if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0) + return ret; + sprintf(filename, SNDRV_FILE_RAWMIDI, card, device); + + __again: + if (attempt++ > 3) { + snd_ctl_close(ctl); + return -EBUSY; + } + ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice); + if (ret < 0) { + snd_ctl_close(ctl); + return ret; + } + + if (!inputp) + fmode = O_WRONLY; + else if (!outputp) + fmode = O_RDONLY; + else + fmode = O_RDWR; + + if (mode & SND_RAWMIDI_APPEND) { + assert(outputp); + fmode |= O_APPEND; + } + + if (mode & SND_RAWMIDI_NONBLOCK) { + fmode |= O_NONBLOCK; + } + + if (mode & SND_RAWMIDI_SYNC) { + fmode |= O_SYNC; + } + + assert(!(mode & ~(SND_RAWMIDI_APPEND|SND_RAWMIDI_NONBLOCK|SND_RAWMIDI_SYNC))); + + fd = snd_open_device(filename, fmode); + if (fd < 0) { + snd_card_load(card); + fd = snd_open_device(filename, fmode); + if (fd < 0) { + snd_ctl_close(ctl); + SYSERR("open %s failed", filename); + return -errno; + } + } + if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_PVERSION, &ver) < 0) { + ret = -errno; + SYSERR("SNDRV_RAWMIDI_IOCTL_PVERSION failed"); + close(fd); + snd_ctl_close(ctl); + return ret; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_RAWMIDI_VERSION_MAX)) { + close(fd); + snd_ctl_close(ctl); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } + if (subdevice >= 0) { + memset(&info, 0, sizeof(info)); + info.stream = outputp ? SNDRV_RAWMIDI_STREAM_OUTPUT : SNDRV_RAWMIDI_STREAM_INPUT; + if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_INFO, &info) < 0) { + SYSERR("SNDRV_RAWMIDI_IOCTL_INFO failed"); + ret = -errno; + close(fd); + snd_ctl_close(ctl); + return ret; + } + if (info.subdevice != (unsigned int) subdevice) { + close(fd); + goto __again; + } + } + snd_ctl_close(ctl); + + hw = calloc(1, sizeof(snd_rawmidi_hw_t)); + if (hw == NULL) + goto _nomem; + hw->card = card; + hw->device = device; + hw->subdevice = subdevice; + hw->fd = fd; + + if (inputp) { + rmidi = calloc(1, sizeof(snd_rawmidi_t)); + if (rmidi == NULL) + goto _nomem; + if (name) + rmidi->name = strdup(name); + rmidi->type = SND_RAWMIDI_TYPE_HW; + rmidi->stream = SND_RAWMIDI_STREAM_INPUT; + rmidi->mode = mode; + rmidi->poll_fd = fd; + rmidi->ops = &snd_rawmidi_hw_ops; + rmidi->private_data = hw; + hw->open++; + *inputp = rmidi; + } + if (outputp) { + rmidi = calloc(1, sizeof(snd_rawmidi_t)); + if (rmidi == NULL) + goto _nomem; + if (name) + rmidi->name = strdup(name); + rmidi->type = SND_RAWMIDI_TYPE_HW; + rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT; + rmidi->mode = mode; + rmidi->poll_fd = fd; + rmidi->ops = &snd_rawmidi_hw_ops; + rmidi->private_data = hw; + hw->open++; + *outputp = rmidi; + } + return 0; + + _nomem: + close(fd); + free(hw); + if (inputp) + free(*inputp); + if (outputp) + free(*outputp); + return -ENOMEM; +} + +int _snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + char *name, snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + long card = -1, device = 0, subdevice = -1; + const char *str; + int err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_rawmidi_conf_generic_id(id)) + continue; + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_get_index(str); + if (card < 0) + return card; + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "subdevice") == 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) + return err; + continue; + } + return -EINVAL; + } + if (card < 0) + return -EINVAL; + return snd_rawmidi_hw_open(inputp, outputp, name, card, device, subdevice, mode); +} +SND_DLSYM_BUILD_VERSION(_snd_rawmidi_hw_open, SND_RAWMIDI_DLSYM_VERSION); diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h new file mode 100644 index 0000000..3388502 --- /dev/null +++ b/src/rawmidi/rawmidi_local.h @@ -0,0 +1,61 @@ +/* + * Rawmidi interface - local header file + * Copyright (c) 2000 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "local.h" + +typedef struct { + int (*close)(snd_rawmidi_t *rawmidi); + int (*nonblock)(snd_rawmidi_t *rawmidi, int nonblock); + int (*info)(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t *info); + int (*params)(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params); + int (*status)(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t *status); + int (*drop)(snd_rawmidi_t *rawmidi); + int (*drain)(snd_rawmidi_t *rawmidi); + ssize_t (*write)(snd_rawmidi_t *rawmidi, const void *buffer, size_t size); + ssize_t (*read)(snd_rawmidi_t *rawmidi, void *buffer, size_t size); +} snd_rawmidi_ops_t; + +struct _snd_rawmidi { + void *dl_handle; + char *name; + snd_rawmidi_type_t type; + snd_rawmidi_stream_t stream; + int mode; + int poll_fd; + const snd_rawmidi_ops_t *ops; + void *private_data; + size_t buffer_size; + size_t avail_min; + unsigned int no_active_sensing: 1; +}; + +int snd_rawmidi_hw_open(snd_rawmidi_t **input, snd_rawmidi_t **output, + const char *name, int card, int device, int subdevice, + int mode); + +int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, snd_seq_t *seq_handle, int port, + int merge, int mode); + +int snd_rawmidi_conf_generic_id(const char *id); diff --git a/src/rawmidi/rawmidi_symbols.c b/src/rawmidi/rawmidi_symbols.c new file mode 100644 index 0000000..cdc06d7 --- /dev/null +++ b/src/rawmidi/rawmidi_symbols.c @@ -0,0 +1,36 @@ +/* + * RawMidi Symbols + * Copyright (c) 2001 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +extern const char *_snd_module_rawmidi_hw; +extern const char *_snd_module_rawmidi_virt; + +static const char **snd_rawmidi_open_objects[] = { + &_snd_module_rawmidi_hw, + &_snd_module_rawmidi_virt +}; + +void *snd_rawmidi_open_symbols(void) +{ + return snd_rawmidi_open_objects; +} + +#endif /* !PIC */ diff --git a/src/rawmidi/rawmidi_virt.c b/src/rawmidi/rawmidi_virt.c new file mode 100644 index 0000000..52b8984 --- /dev/null +++ b/src/rawmidi/rawmidi_virt.c @@ -0,0 +1,469 @@ +/* + * RawMIDI - Virtual (sequencer mode) + * Copyright (c) 2003 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "rawmidi_local.h" +#include "seq.h" +#include "seq_midi_event.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_rawmidi_virt = ""; +#endif + + +#ifndef DOC_HIDDEN +typedef struct { + int open; + + snd_seq_t *handle; + int port; + + snd_midi_event_t *midi_event; + + snd_seq_event_t *in_event; + int in_buf_size; + int in_buf_ofs; + char *in_buf_ptr; + char in_tmp_buf[16]; + + snd_seq_event_t out_event; + int pending; +} snd_rawmidi_virtual_t; + +int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name, + int streams, int mode, snd_config_t *lconf, + snd_config_t *parent_conf); +#endif + +static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + virt->open--; + if (virt->open) + return 0; + snd_seq_close(virt->handle); + if (virt->midi_event) + snd_midi_event_free(virt->midi_event); + free(virt); + return 0; +} + +static int snd_rawmidi_virtual_nonblock(snd_rawmidi_t *rmidi, int nonblock) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + + return snd_seq_nonblock(virt->handle, nonblock); +} + +static int snd_rawmidi_virtual_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info) +{ + // snd_rawmidi_virtual_t *virt = rmidi->private_data; + + info->stream = rmidi->stream; + /* FIXME: what values should be there? */ + info->card = 0; + info->device = 0; + info->subdevice = 0; + info->flags = 0; + strcpy((char *)info->id, "Virtual"); + strcpy((char *)info->name, "Virtual RawMIDI"); + strcpy((char *)info->subname, "Virtual RawMIDI"); + info->subdevices_count = 1; + info->subdevices_avail = 0; + return 0; +} + +static int snd_rawmidi_virtual_input_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params) +{ + int err; + + // snd_rawmidi_drain_input(substream); + if (params->buffer_size < sizeof(snd_seq_event_t) || + params->buffer_size > 1024L * 1024L) { + return -EINVAL; + } + if (params->buffer_size != snd_seq_get_input_buffer_size(virt->handle)) { + err = snd_seq_set_input_buffer_size(virt->handle, params->buffer_size); + if (err < 0) + return err; + params->buffer_size = snd_seq_get_input_buffer_size(virt->handle); + /* FIXME: input pool size? */ + } + return 0; +} + + +static int snd_rawmidi_virtual_output_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params) +{ + int err; + + // snd_rawmidi_drain_output(substream); + if (params->buffer_size < sizeof(snd_seq_event_t) || + params->buffer_size > 1024L * 1024L) { + return -EINVAL; + } + if (params->buffer_size != snd_seq_get_output_buffer_size(virt->handle)) { + err = snd_seq_set_output_buffer_size(virt->handle, params->buffer_size); + if (err < 0) + return err; + params->buffer_size = snd_seq_get_output_buffer_size(virt->handle); + } + return 0; +} + + +static int snd_rawmidi_virtual_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + params->stream = rmidi->stream; + + if (rmidi->stream == SND_RAWMIDI_STREAM_INPUT) + return snd_rawmidi_virtual_input_params(virt, params); + else + return snd_rawmidi_virtual_output_params(virt, params); +} + +static int snd_rawmidi_virtual_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status) +{ + // snd_rawmidi_virtual_t *virt = rmidi->private_data; + memset(status, 0, sizeof(*status)); + status->stream = rmidi->stream; + return 0; +} + +static int snd_rawmidi_virtual_drop(snd_rawmidi_t *rmidi) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) { + snd_seq_drop_output(virt->handle); + snd_midi_event_reset_encode(virt->midi_event); + virt->pending = 0; + } else { + snd_seq_drop_input(virt->handle); + snd_midi_event_reset_decode(virt->midi_event); + virt->in_buf_ofs = 0; + } + return 0; +} + +static int snd_rawmidi_virtual_drain(snd_rawmidi_t *rmidi) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + int err; + + if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) { + if (virt->pending) { + err = snd_seq_event_output(virt->handle, &virt->out_event); + if (err < 0) + return err; + virt->pending = 0; + } + snd_seq_drain_output(virt->handle); + snd_seq_sync_output_queue(virt->handle); + } + return snd_rawmidi_virtual_drop(rmidi); +} + +static ssize_t snd_rawmidi_virtual_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + ssize_t result = 0; + ssize_t size1; + int err; + + if (virt->pending) { + err = snd_seq_event_output(virt->handle, &virt->out_event); + if (err < 0) { + if (err != -EAGAIN) + /* we got some fatal error. removing this event + * at the next time + */ + virt->pending = 0; + return err; + } + virt->pending = 0; + } + + while (size > 0) { + size1 = snd_midi_event_encode(virt->midi_event, buffer, size, &virt->out_event); + if (size1 <= 0) + break; + size -= size1; + result += size1; + buffer += size1; + if (virt->out_event.type == SND_SEQ_EVENT_NONE) + continue; + snd_seq_ev_set_subs(&virt->out_event); + snd_seq_ev_set_source(&virt->out_event, virt->port); + snd_seq_ev_set_direct(&virt->out_event); + err = snd_seq_event_output(virt->handle, &virt->out_event); + if (err < 0) { + virt->pending = 1; + return result > 0 ? result : err; + } + } + + if (result > 0) + snd_seq_drain_output(virt->handle); + + return result; +} + +static ssize_t snd_rawmidi_virtual_read(snd_rawmidi_t *rmidi, void *buffer, size_t size) +{ + snd_rawmidi_virtual_t *virt = rmidi->private_data; + ssize_t result = 0; + int size1, err; + + while (size > 0) { + if (! virt->in_buf_ofs) { + err = snd_seq_event_input_pending(virt->handle, 1); + if (err <= 0 && result > 0) + return result; + err = snd_seq_event_input(virt->handle, &virt->in_event); + if (err < 0) + return result > 0 ? result : err; + + if (virt->in_event->type == SND_SEQ_EVENT_SYSEX) { + virt->in_buf_ptr = virt->in_event->data.ext.ptr; + virt->in_buf_size = virt->in_event->data.ext.len; + } else { + virt->in_buf_ptr = virt->in_tmp_buf; + virt->in_buf_size = snd_midi_event_decode(virt->midi_event, + (unsigned char *)virt->in_tmp_buf, + sizeof(virt->in_tmp_buf), + virt->in_event); + } + if (virt->in_buf_size <= 0) + continue; + } + size1 = virt->in_buf_size - virt->in_buf_ofs; + if ((size_t)size1 > size) { + virt->in_buf_ofs += size1 - size; + memcpy(buffer, virt->in_buf_ptr, size); + result += size; + break; + } + memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size1); + size -= size1; + result += size1; + buffer += size1; + virt->in_buf_ofs = 0; + } + + return result; +} + +static const snd_rawmidi_ops_t snd_rawmidi_virtual_ops = { + .close = snd_rawmidi_virtual_close, + .nonblock = snd_rawmidi_virtual_nonblock, + .info = snd_rawmidi_virtual_info, + .params = snd_rawmidi_virtual_params, + .status = snd_rawmidi_virtual_status, + .drop = snd_rawmidi_virtual_drop, + .drain = snd_rawmidi_virtual_drain, + .write = snd_rawmidi_virtual_write, + .read = snd_rawmidi_virtual_read, +}; + + +/*! \page rawmidi RawMidi interface + +\section rawmidi_virt Virtual RawMidi interface + +The "virtual" plugin creates a virtual RawMidi instance on the ALSA +sequencer, which can be accessed through the connection of the sequencer +ports. +There is no connection established as default. + +For creating a virtual RawMidi instance, pass "virtual" as its name at +creation. + +Example: +\code +snd_rawmidi_open(&read_handle, &write_handle, "virtual", 0); +\endcode + +*/ + +int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + const char *name, snd_seq_t *seq_handle, int port, + int merge, int mode) +{ + int err; + snd_rawmidi_t *rmidi; + snd_rawmidi_virtual_t *virt = NULL; + struct pollfd pfd; + + if (inputp) + *inputp = 0; + if (outputp) + *outputp = 0; + + virt = calloc(1, sizeof(*virt)); + if (virt == NULL) { + err = -ENOMEM; + goto _err; + } + virt->handle = seq_handle; + virt->port = port; + err = snd_midi_event_new(256, &virt->midi_event); + if (err < 0) + goto _err; + snd_midi_event_init(virt->midi_event); + snd_midi_event_no_status(virt->midi_event, !merge); + + if (inputp) { + rmidi = calloc(1, sizeof(*rmidi)); + if (rmidi == NULL) { + err = -ENOMEM; + goto _err; + } + if (name) + rmidi->name = strdup(name); + rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL; + rmidi->stream = SND_RAWMIDI_STREAM_INPUT; + rmidi->mode = mode; + err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLIN); + if (err < 0) + goto _err; + rmidi->poll_fd = pfd.fd; + rmidi->ops = &snd_rawmidi_virtual_ops; + rmidi->private_data = virt; + virt->open++; + *inputp = rmidi; + } + if (outputp) { + rmidi = calloc(1, sizeof(*rmidi)); + if (rmidi == NULL) { + err = -ENOMEM; + goto _err; + } + if (name) + rmidi->name = strdup(name); + rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL; + rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT; + rmidi->mode = mode; + err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLOUT); + if (err < 0) + goto _err; + rmidi->poll_fd = pfd.fd; + rmidi->ops = &snd_rawmidi_virtual_ops; + rmidi->private_data = virt; + virt->open++; + *outputp = rmidi; + } + + return 0; + + _err: + if (seq_handle) + snd_seq_close(seq_handle); + if (virt->midi_event) + snd_midi_event_free(virt->midi_event); + free(virt); + if (inputp) + free(*inputp); + if (outputp) + free(*outputp); + return err; +} + +int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + char *name, snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + const char *slave_str = NULL; + int err; + int streams, seq_mode; + int merge = 1; + int port; + unsigned int caps; + snd_seq_t *seq_handle; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_rawmidi_conf_generic_id(id)) + continue; + if (strcmp(id, "slave") == 0) { + err = snd_config_get_string(n, &slave_str); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "merge") == 0) { + merge = snd_config_get_bool(n); + continue; + } + return -EINVAL; + } + + streams = 0; + if (inputp) + streams |= SND_SEQ_OPEN_INPUT; + if (outputp) + streams |= SND_SEQ_OPEN_OUTPUT; + if (! streams) + return -EINVAL; + + seq_mode = 0; + if (mode & SND_RAWMIDI_NONBLOCK) + seq_mode |= SND_SEQ_NONBLOCK; + + if (! slave_str) + slave_str = "default"; + err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, + root, conf); + if (err < 0) + return err; + + caps = 0; + if (inputp) + caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SYNC_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; + if (outputp) + caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SYNC_READ | SND_SEQ_PORT_CAP_SUBS_READ; + if (inputp && outputp) + caps |= SNDRV_SEQ_PORT_CAP_DUPLEX; + + port = snd_seq_create_simple_port(seq_handle, "Virtual RawMIDI", + caps, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC); + if (port < 0) { + snd_seq_close(seq_handle); + return port; + } + + return snd_rawmidi_virtual_open(inputp, outputp, name, seq_handle, port, + merge, mode); +} + +#ifndef DOC_HIDDEN +SND_DLSYM_BUILD_VERSION(_snd_rawmidi_virtual_open, SND_RAWMIDI_DLSYM_VERSION); +#endif diff --git a/src/seq/Makefile.am b/src/seq/Makefile.am new file mode 100644 index 0000000..1ea92f0 --- /dev/null +++ b/src/seq/Makefile.am @@ -0,0 +1,13 @@ +EXTRA_LTLIBRARIES=libseq.la + +libseq_la_SOURCES = seq_hw.c seq.c seq_event.c seqmid.c seq_midi_event.c \ + seq_symbols.c +if KEEP_OLD_SYMBOLS +libseq_la_SOURCES += seq_old.c +endif +noinst_HEADERS = seq_local.h + +all: libseq.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/seq/Makefile.in b/src/seq/Makefile.in new file mode 100644 index 0000000..e10851f --- /dev/null +++ b/src/seq/Makefile.in @@ -0,0 +1,503 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@KEEP_OLD_SYMBOLS_TRUE@am__append_1 = seq_old.c +subdir = src/seq +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libseq_la_LIBADD = +am__libseq_la_SOURCES_DIST = seq_hw.c seq.c seq_event.c seqmid.c \ + seq_midi_event.c seq_symbols.c seq_old.c +@KEEP_OLD_SYMBOLS_TRUE@am__objects_1 = seq_old.lo +am_libseq_la_OBJECTS = seq_hw.lo seq.lo seq_event.lo seqmid.lo \ + seq_midi_event.lo seq_symbols.lo $(am__objects_1) +libseq_la_OBJECTS = $(am_libseq_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libseq_la_SOURCES) +DIST_SOURCES = $(am__libseq_la_SOURCES_DIST) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libseq.la +libseq_la_SOURCES = seq_hw.c seq.c seq_event.c seqmid.c \ + seq_midi_event.c seq_symbols.c $(am__append_1) +noinst_HEADERS = seq_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/seq/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/seq/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libseq.la: $(libseq_la_OBJECTS) $(libseq_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libseq_la_OBJECTS) $(libseq_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_event.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_midi_event.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_old.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_symbols.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seqmid.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +all: libseq.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/seq/seq.c b/src/seq/seq.c new file mode 100644 index 0000000..f5dfe9c --- /dev/null +++ b/src/seq/seq.c @@ -0,0 +1,4783 @@ +/** + * \file seq/seq.c + * \brief Sequencer Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 2000-2001 + * + * See \ref seq page for more details. + */ + +/* + * Sequencer Interface - main file + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page seq Sequencer interface + +\section seq_general General + +The ALSA sequencer interface is designed to deliver the MIDI-like +events between clients/ports. +A typical usage is the MIDI patch-bay. A MIDI application can be +connected arbitrarily from/to the other MIDI clients. +The routing between clients can be changed dynamically, so the +application can handle incoming or outgoing MIDI events regardless of +the devices or the application connections. + +The sequencer core stuff only takes care of two things: +scheduling events and dispatching them to the destination at the +right time. All processing of MIDI events has to be done within the clients. +The event can be dispatched immediately without queueing, too. +The event scheduling can be done either on a MIDI tempo queue or +on a wallclock-time queue. + +\section seq_client Client and Port + +A client is created at each time #snd_seq_open() is called. +Later on, the attributes of client such as its name string can be changed +via #snd_seq_set_client_info(). There are helper functions for ease of use, +e.g. #snd_seq_set_client_name() and #snd_seq_set_client_event_filter(). +A typical code would be like below: +\code +// create a new client +snd_seq_t *open_client() +{ + snd_seq_t *handle; + int err; + err = snd_seq_open(&handle, "default", SND_SEQ_OPEN_INPUT, 0); + if (err < 0) + return NULL; + snd_seq_set_client_name(handle, "My Client"); + return handle; +} +\endcode + +You'll need to know the id number of the client eventually, for example, +when accessing to a certain port (see the section \ref seq_subs). +The client id can be obtained by #snd_seq_client_id() function. + +A client can have one or more ports to communicate between other +clients. A port is corresponding to the MIDI port in the case of MIDI device, +but in general it is nothing but the access point between other clients. +Each port may have capability flags, which specify the read/write +accessibility and subscription permissions of the port. +For creation of a port, call #snd_seq_create_port() +with the appropriate port attribute specified in #snd_seq_port_info_t +record. + +For creating a port for the normal use, there is a helper function +#snd_seq_create_simple_port(). An example with this function is like below. +\code +// create a new port; return the port id +// port will be writable and accept the write-subscription. +int my_new_port(snd_seq_t *handle) +{ + return snd_seq_create_simple_port(handle, "my port", + SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, + SND_SEQ_PORT_TYPE_MIDI_GENERIC); +} +\endcode + +\section seq_memory Memory Pool + +Each client owns memory pools on kernel space +for each input and output events. +Here, input and output mean +input (read) from other clients and output (write) to others, respectively. +Since memory pool of each client is independent from others, +it avoids such a situation that a client eats the whole events pool +and interfere other clients' response. + +The all scheduled output events or input events from dispatcher are stored +on these pools until delivered to other clients or extracted to user space. +The size of input/output pools can be changed independently. +The output pool has also a room size, which is used to wake up the +thread when it falls into sleep in blocking write mode. + +Note that ports on the same client share the same memory pool. +If a port fills the memory pool, another can't use it any more. +For avoiding this, multiple clients can be used. + +For chancing the pool size and the condition, access to #snd_seq_client_pool_t +record. There are helper functions, #snd_seq_set_client_pool_output(), +#snd_seq_set_client_pool_output_room() and #snd_seq_set_client_pool_input(), +for setting the total output-pool size, the output-room size and the input-pool +size, respectively. + +\section seq_subs Subscription + +One of the new features in ALSA sequencer system is subscription of ports. +In general, subscription is a connection between two sequencer ports. +Even though an event can be delivered to a port without subscription +using an explicit destination address, +the subscription mechanism provides us more abstraction. + +Suppose a MIDI input device which sends events from a keyboard. +The port associated with this device has READ capability - which means +this port is readable from other ports. +If a user program wants to capture events from keyboard and store them +as MIDI stream, this program must subscribe itself to the MIDI port +for read. +Then, a connection from MIDI input port to this program is established. +From this time, events from keyboard are automatically sent to this program. +Timestamps will be updated according to the subscribed queue. +\code + MIDI input port (keyboard) + | + V + ALSA sequencer - update timestamp + | + V + application port +\endcode + +There is another subscription type for opposite direction: +Suppose a MIDI sequencer program which sends events to a MIDI output device. +In ALSA system, MIDI device is not opened until the associated MIDI port +is accessed. Thus, in order to activate MIDI device, we have to subscribe +to MIDI port for write. +After this connection is established, events will be properly sent +to MIDI output device. +\code + application port + | + V + ALSA sequencer - events are scheduled + | + V + MIDI output port (WaveTable etc.) +\endcode + +From the viewpoint of subscription, the examples above are special cases. +Basically, subscription means the connection between two arbitrary ports. +For example, imagine a filter application which modifies +the MIDI events like program, velocity or chorus effects. +This application can accept arbitrary MIDI input +and send to arbitrary port, just like a Unix pipe application using +stdin and stdout files. +We can even connect several filter applications which work individually +in order to process the MIDI events. +Subscription can be used for this purpose. +The connection between ports can be done also by the "third" client. +Thus, filter applications have to manage +only input and output events regardless of receiver/sender addresses. +\code + sequencer port #1 + | + V + ALSA sequencer (scheduled or real-time) + | + V + sequencer port #2 +\endcode + +For the detail about subscription, see the section \ref seq_subs_more. + +\section seq_events Sequencer Events + +Messaging between clients is performed by sending events from one client to +another. These events contain high-level MIDI oriented messages or sequencer +specific messages. + +All the sequencer events are stored in a sequencer event record, +#snd_seq_event_t type. +Application can send and receive these event records to/from other +clients via sequencer. +An event has several storage types according to its usage. +For example, a SYSEX message is stored on the variable length event, +and a large synth sample data is delivered using a user-space data pointer. + + +\subsection seq_ev_struct Structure of an event + +An event consists of the following items: +

    +
  • The type of the event +
  • Event flags. It describes various conditions: +
      +
    • time stamp; "real time" / "song ticks" +
    • time mode; "absolute" / "relative to current time" +
    +
  • Timestamp of the event. +
  • Scheduling queue id. +
  • Source address of the event, given by the combination + of client id and port id numbers. +
  • Destination address of the event. +
  • The actual event data. (up to 12 bytes) +
+ +The actual record is shown in #snd_seq_event_t. +The type field contains the type of the event +(1 byte). +The flags field consists of bit flags which +describe several conditions of the event (1 byte). +It includes the time-stamp mode, data storage type, and scheduling priority. +The tag field is an arbitrary tag. +This tag can used for removing a distinct event from the event queue +via #snd_seq_remove_events(). +The queue field is the queue id for scheduling. +The source and dest fields are source and destination addresses. +The data field is a union of event data. + +\subsection seq_ev_queue Scheduling queue + +An event can be delivered either on scheduled or direct dispatch mode. +On the scheduling mode, an event is once stored on the priority queue +and delivered later (or even immediately) to the destination, +whereas on the direct dispatch mode, an event is passed to the destination +without any queue. + +For a scheduled delivery, a queue to process the event must exist. +Usually, a client creates its own queue by +#snd_seq_alloc_queue() function. +Alternatively, a queue may be shared among several clients. +For scheduling an event on the specified queue, +a client needs to fill queue field +with the preferred queue id. + +Meanwhile, for dispatching an event directly, just +use #SND_SEQ_QUEUE_DIRECT as the target queue id. +A macro #snd_seq_ev_set_direct() is provided for ease +and compatibility. + +Note that scheduling at the current or earlier time is different +from the direct dispatch mode even though the event is delivered immediately. +On the former scheme, an event is once stored on priority queue, then +delivered actually. Thus, it acquires a space from memory pool. +On the other hand, the latter is passed without using memory pool. +Although the direct dispatched event needs less memory, it means also +that the event cannot be resent if the destination is unable to receive it +momentarily. + +\subsection seq_ev_time Time stamp + +The timestamp of the event can either specified in +real time or in song ticks. +The former means the wallclock time while the latter corresponds to +the MIDI ticks. +Which format is used is determined by the event flags. + +The resolution of real-time value is in nano second. +Since 64 bit length is required for the actual time calculation, +it is represented by +a structure of pair of second and nano second +defined as #snd_seq_real_time_t type. +The song tick is defined simply as a 32 bit integer, +defined as #snd_seq_tick_time_t type. +The time stored in an event record is a union of these two different +time values. + +Note that the time format used for real time events is very similar to +timeval struct used for Unix system time. +The absurd resolution of the timestamps allows us to perform very accurate +conversions between songposition and real time. Round-off errors can be +neglected. + +If a timestamp with a +relative timestamp is delivered to ALSA, the +specified timestamp will be used as an offset to the current time of the +queue the event is sent into. +An absolute timestamp is on the contrary the time +counted from the moment when the queue started. + +An client that relies on these relative timestamps is the MIDI input port. +As each sequencer queue has it's own clock the only way to deliver events at +the right time is by using the relative timestamp format. When the event +arrives at the queue it is normalized to absolute format. + +The timestamp format is specified in the flag bitfield masked by +#SND_SEQ_TIME_STAMP_MASK. +To schedule the event in a real-time queue or in a tick queue, +macros #snd_seq_ev_schedule_real() and +#snd_seq_ev_schedule_tick() are provided, respectively. + +\subsection seq_ev_addr Source and destination addresses + +To identify the source and destination of an event, the addressing field +contains a combination of client id and port id numbers, defined as +#snd_seq_addr_t type. +When an event is passed to sequencer from a client, sequencer fills +source.client field +with the sender's id automatically. +It is the responsibility of sender client to +fill the port id of source.port and +both client and port of dest field. + +If an existing address is set to the destination, +the event is simply delivered to it. +When #SND_SEQ_ADDRESS_SUBSCRIBERS is set to the destination client id, +the event is delivered to all the clients connected to the source port. + + +A sequencer core has two pre-defined system ports on the system client +#SND_SEQ_CLIENT_SYSTEM: #SND_SEQ_PORT_SYSTEM_TIMER and #SND_SEQ_PORT_SYSTEM_ANNOUNCE. +The #SND_SEQ_PORT_SYSTEM_TIMER is the system timer port, +and #SND_SEQ_PORT_SYSTEM_ANNOUNCE is the system +announce port. +In order to control a queue from a client, client should send a +queue-control event +like start, stop and continue queue, change tempo, etc. +to the system timer port. +Then the sequencer system handles the queue according to the received event. +This port supports subscription. The received timer events are +broadcasted to all subscribed clients. + +The latter port does not receive messages but supports subscription. +When each client or port is attached, detached or modified, +an announcement is sent to subscribers from this port. + +\subsection seq_ev_data Data storage type + +Some events like SYSEX message, however, need larger data space +than the standard data. +For such events, ALSA sequencer provides several different data storage types. +The data type is specified in the flag bits masked by #SND_SEQ_EVENT_LENGTH_MASK. +The following data types are available: + +\par Fixed size data +Normal events stores their parameters on +data field (12 byte). +The flag-bit type is #SND_SEQ_EVENT_LENGTH_FIXED. +A macro #snd_seq_ev_set_fixed() is provided to set this type. + +\par Variable length data +SYSEX or a returned error use this type. +The actual data is stored on an extra allocated space. +On sequencer kernel, the whole extra-data is duplicated, so that the event +can be scheduled on queue. +The data contains only the length and the +pointer of extra-data. +The flag-bit type is #SND_SEQ_EVENT_LENGTH_VARIABLE. +A macro #snd_seq_ev_set_variable() is provided to set this type. + +\par User-space data +This type refers also an extra data space like variable length data, +but the extra-data is not duplicated but +but referred as a user-space data on kernel, +so that it reduces the time and resource for transferring +large bulk of data like synth sample wave. +This data type, however, can be used only for direct dispatch mode, +and supposed to be used only for a special purpose like a bulk data +transfer. +The data length and pointer are stored also in +data.ext field as well as variable length data. +The flag-bit type is #SND_SEQ_EVENT_LENGTH_VARUSR. +A macro #snd_seq_ev_set_varusr() is provided to set this type. + +\subsection seq_ev_sched Scheduling priority + +There are two priorities for scheduling: +\par Normal priority +If an event with the same scheduling time is already present on the queue, +the new event is appended to the older. +\par High priority +If an event with the same scheduling time is already present on the queue, +the new event is inserted before others. + +The scheduling priority is set in the flag bitfeld masked by #SND_SEQ_PRIORITY_MASK. +A macro #snd_seq_ev_set_priority() is provided to set the mode type. + +\section seq_queue Event Queues +\subsection seq_ev_control Creation of a queue + +Creating a queue is done usually by calling #snd_seq_alloc_queue. +You can create a queue with a certain name by #snd_seq_alloc_named_queue(), too. +\code +// create a queue and return its id +int my_queue(snd_seq_t *handle) +{ + return snd_seq_alloc_named_queue(handle, "my queue"); +} +\endcode +These functions are the wrapper to the function #snd_seq_create_queue(). +For releasing the allocated queue, call #snd_seq_free_queue() with the +obtained queue id. + +Once when a queue is created, the two queues are associated to that +queue record in fact: one is the realtime queue and another is the +tick queue. These two queues are bound together to work +synchronously. Hence, when you schedule an event, you have to choose +which queue type is used as described in the section \ref +seq_ev_time. + +\subsection seq_ev_tempo Setting queue tempo + +The tempo (or the speed) of the scheduling queue is variable. +In the case of tick queue, the tempo is controlled +in the manner of MIDI. There are two parameters to define the +actual tempo, PPQ (pulse per quarter note) and MIDI tempo. +The former defines the base resolution of the ticks, while +the latter defines the beat tempo in microseconds. +As default, 96 PPQ and 120 BPM are used, respectively. +That is, the tempo is set to 500000 (= 60 * 1000000 / 120). +Note that PPQ cannot be changed while the queue is running. +It must be set before the queue is started. + +On the other hand, in the case of realtime queue, the +time resolution is fixed to nanoseconds. There is, however, +a parameter to change the speed of this queue, called skew. +You can make the queue faster or slower by setting the skew value +bigger or smaller. In the API, the skew is defined by two values, +the skew base and the skew value. The actual skew is the fraction +of them, value/base. As default, the skew base is set to 16bit +(0x10000) and the skew value is the identical, so that the queue is +processed as well as in the real world. + +When the tempo of realtime queue is changed, the tempo of +the associated tick queue is changed together, too. +That's the reason why two queues are created always. +This feature can be used to synchronize the event queue with +the external synchronization source like SMPTE. In such a case, +the realtime queue is skewed to match with the external source, +so that both the realtime timestamp and the MIDI timestamp are +synchronized. + +For setting these tempo parameters, use #snd_seq_queue_tempo_t record. +For example, to set the tempo of the queue q to +48 PPQ, 60 BPM, +\code +void set_tempo(snd_seq_t *handle) +{ + snd_seq_queue_tempo_t *tempo; + snd_seq_queue_tempo_alloca(&tempo); + snd_seq_queue_tempo_set_tempo(tempo, 1000000); // 60 BPM + snd_seq_queue_tempo_set_ppq(tempo, 48); // 48 PPQ + snd_seq_set_queue_tempo(handle, tempo); +} +\endcode + +For changing the (running) queue's tempo on the fly, you can either +set the tempo via #snd_seq_set_queue_tempo() or send a MIDI tempo event +to the system timer port. For example, +\code +int change_tempo(snd_seq_t *handle, int q, unsigned int tempo) +{ + snd_seq_event_t ev; + snd_seq_ev_clear(&ev); + ev.dest.client = SND_SEQ_CLIENT_SYSTEM; + ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; + ev.source.client = my_client_id; + ev.source.port = my_port_id; + ev.queue = SND_SEQ_QUEUE_DIRECT; // no scheduling + ev.data.queue.queue = q; // affected queue id + ev.data.queue.value = tempo; // new tempo in microsec. + return snd_seq_event_output(handle, &ev); +} +\endcode +There is a helper function to do this easily, +#snd_seq_change_queue_tempo(). +Set NULL to the last argument, if you don't need any +special settings. + +In the above example, the tempo is changed immediately after +the buffer is flushed by #snd_seq_drain_output() call. +You can schedule the event in a certain queue so that the tempo +change happens at the scheduled time, too. + +\subsection seq_ev_start Starting and stopping a queue + +To start, stop, or continue a queue, you need to send a queue-control +event to the system timer port as well. There are helper functions, +#snd_seq_start_queue(), #snd_seq_stop_queue() and +#snd_seq_continue_queue(). +Note that if the last argument of these functions is NULL, the +event is sent (i.e. operated) immediately after the buffer flush. +If you want to schedule the event at the certain time, set up +the event record and provide the pointer of that event record as the +argument. + +Only calling these functions doesn't deliver the event to the +sequencer core but only put to the output buffer. You'll need to +call #snd_seq_drain_output() eventually. + + +\section seq_subs_more More inside the subscription + +\subsection seq_subs_perm Permissions + +Each ALSA port can have capability flags. +The most basic capability flags are +#SND_SEQ_PORT_CAP_READ and #SND_SEQ_PORT_CAP_WRITE. +The former means that the port allows to send events to other ports, +whereas the latter capability means +that the port allows to receive events from other ports. +You may have noticed that meanings of \c READ and \c WRITE +are permissions of the port from the viewpoint of other ports. + +For allowing subscription from/to other clients, another capability +flags must be set together with read/write capabilities above. +For allowing read and write subscriptions, +#SND_SEQ_PORT_CAP_SUBS_READ and +#SND_SEQ_PORT_CAP_SUBS_WRITE are used, +respectively. +For example, the port with MIDI input device always has +#SND_SEQ_PORT_CAP_SUBS_READ capability, +and the port with MIDI output device always has +#SND_SEQ_PORT_CAP_SUBS_WRITE capability together with +#SND_SEQ_PORT_CAP_READ and #SND_SEQ_PORT_CAP_WRITE capabilities, +respectively. +Obviously, these flags have no influence +if \c READ or \c WRITE> capability is not set. + +Note that these flags are not necessary if the client subscribes itself +to the specified port. +For example, when a port makes READ subscription +to MIDI input port, this port must have #SND_SEQ_PORT_CAP_WRITE capability, +but no #SND_SEQ_PORT_CAP_SUBS_WRITE capability is required. +Only MIDI input port must have #SND_SEQ_PORT_CAP_SUBS_READ capability. + +As default, the connection of ports via the third client is always allowed +if proper read and write (subscription) capabilities are set both to the +source and destination ports. +For prohibiting this behavior, set a capability +#SND_SEQ_PORT_CAP_NO_EXPORT to the port. +If this flag is set, subscription must be done by sender or receiver +client itself. +It is useful to avoid unexpected disconnection. +The ports which won't accept subscription should have this capability +for better security. + +\subsection seq_subs_handle Subscription handlers + +In ALSA library, subscription is done via +#snd_seq_subscribe_port() function. +It takes the argument of #snd_seq_port_subscribe_t record pointer. +Suppose that you have a client which will receive data from +a MIDI input device. The source and destination addresses +are like the below; +\code +snd_seq_addr_t sender, dest; +sender.client = MIDI_input_client; +sender.port = MIDI_input_port; +dest.client = my_client; +dest.port = my_port; +\endcode +To set these values as the connection call like this. +\code +snd_seq_port_subscribe_t *subs; +snd_seq_port_subscribe_alloca(&subs); +snd_seq_port_subscribe_set_sender(subs, &sender); +snd_seq_port_subscribe_set_dest(subs, &dest); +snd_seq_subscribe_port(handle, subs); +\endcode + +When the connection should be exclusively done only between +a certain pair, set exclusive attribute to the subscription +record before calling #snd_seq_subscribe_port. +\code +snd_seq_port_subscribe_set_exclusive(subs, 1); +\endcode +The succeeding subscriptions will be refused. + +The timestamp can be updated independently on each connection. +When set up, the timestamp of incoming queue to the destination port +is updated automatically to the time of the specified queue. +\code +snd_seq_port_subscribe_set_time_update(subs, 1); +snd_seq_port_subscribe_set_queue(subs, q); +\endcode +For getting the wallclock time (sec/nsec pair), set real attribute: +\code +snd_seq_port_subscribe_set_time_real(subs, 1); +\endcode +Otherwise, the timestamp is stored in tick unit. +This feature is useful when receiving events from MIDI input device. +The event time is automatically set in the event record. + +Note that an outsider client may connect other ports. +In this case, however, the subscription may be refused +if #SND_SEQ_PORT_CAP_NO_EXPORT capability is set in either sender or receiver port. + +\section seq_subs_ex Examples of subscription + +\subsection seq_subs_ex_capt Capture from keyboard + +Assume MIDI input port = 64:0, application port = 128:0, and +queue for timestamp = 1 with real-time stamp. +The application port must have capability #SND_SEQ_PORT_CAP_WRITE. +\code +void capture_keyboard(snd_seq_t *seq) +{ + snd_seq_addr_t sender, dest; + snd_seq_port_subscribe_t *subs; + sender.client = 64; + sender.port = 0; + dest.client = 128; + dest.port = 0; + snd_seq_port_subscribe_alloca(&subs); + snd_seq_port_subscribe_set_sender(subs, &sender); + snd_seq_port_subscribe_set_dest(subs, &dest); + snd_seq_port_subscribe_set_queue(subs, 1); + snd_seq_port_subscribe_set_time_update(subs, 1); + snd_seq_port_subscribe_set_time_real(subs, 1); + snd_seq_subscribe_port(seq, subs); +} +\endcode + +\subsection seq_subs_ex_out Output to MIDI device + +Assume MIDI output port = 65:1 and application port = 128:0. +The application port must have capability #SND_SEQ_PORT_CAP_READ. +\code +void subscribe_output(snd_seq_t *seq) +{ + snd_seq_addr_t sender, dest; + snd_seq_port_subscribe_t *subs; + sender.client = 128; + sender.port = 0; + dest.client = 65; + dest.port = 1; + snd_seq_port_subscribe_alloca(&subs); + snd_seq_port_subscribe_set_sender(subs, &sender); + snd_seq_port_subscribe_set_dest(subs, &dest); + snd_seq_subscribe_port(seq, subs); +} +\endcode +This example can be simplified by using #snd_seq_connect_to() function. +\code +void subscribe_output(snd_seq_t *seq) +{ + snd_seq_connect_to(seq, 0, 65, 1); +} +\endcode + +\subsection seq_subs_ex_arbit Arbitrary connection + +Assume connection from application 128:0 to 129:0, +and that subscription is done by the third application (130:0). +The sender must have capabilities both +#SND_SEQ_PORT_CAP_READ and +#SND_SEQ_PORT_CAP_SUBS_READ, +and the receiver +#SND_SEQ_PORT_CAP_WRITE and +#SND_SEQ_PORT_CAP_SUBS_WRITE, respectively. +\code +// ..in the third application (130:0) .. +void coupling(snd_seq_t *seq) +{ + snd_seq_addr_t sender, dest; + snd_seq_port_subscribe_t *subs; + sender.client = 128; + sender.port = 0; + dest.client = 129; + dest.port = 0; + snd_seq_port_subscribe_alloca(&subs); + snd_seq_port_subscribe_set_sender(subs, &sender); + snd_seq_port_subscribe_set_dest(subs, &dest); + snd_seq_subscribe_port(seq, subs); +} +\endcode + +\section seq_ex_event Event Processing + +\subsection seq_ex_address Addressing + +Now, two ports are connected by subscription. Then how to send events? + +The subscribed port doesn't have to know the exact sender address. +Instead, there is a special address for subscribers, +#SND_SEQ_ADDRESS_SUBSCRIBERS. +The sender must set this value as the destination client. +Destination port is ignored. + +The other values in source and destination addresses are identical with +the normal event record. +If the event is scheduled, proper queue and timestamp values must be set. + +There is a convenient function to set the address in an event record. +In order to set destination as subscribers, use +#snd_seq_ev_set_subs(). + +\subsection Scheduled Delivery + +If we send an event at the scheduled time t (tick) +on the queue Q, +the sender must set both schedule queue and time in the +event record. +The program appears like this: +\code +void schedule_event(snd_seq_t *seq) +{ + snd_seq_event_t ev; + + snd_seq_ev_clear(&ev); + snd_seq_ev_set_source(&ev, my_port); + snd_seq_ev_set_subs(&ev); + snd_seq_ev_schedule_tick(&ev, Q, 0, t); + ... // set event type, data, so on.. + + snd_seq_event_output(seq, &ev); + ... + snd_seq_drain_output(seq); // if necessary +} +\endcode +Of course, you can use realtime stamp, too. + +\subsection seq_ex_direct Direct Delivery + +If the event is sent immediately without enqueued, the sender doesn't take +care of queue and timestamp. +As well as the case above, there is a function to set the direct delivery, +#snd_seq_ev_set_direct(). +The program can be more simplified as follows: +\code +void direct_delivery(snd_seq_t *seq) +{ + snd_seq_event_t ev; + + snd_seq_ev_clear(&ev); + snd_seq_ev_set_source(&ev, port); + snd_seq_ev_set_subs(&ev); + snd_seq_ev_set_direct(&ev); + ... // set event type, data, so on.. + + snd_seq_event_output(seq, &ev); + snd_seq_drain_output(seq); +} +\endcode +You should flush event soon after output event. +Otherwise, the event is enqueued on output queue of ALSA library +(not in the kernel!), and will be never processed until +this queue becomes full. + +\subsection seq_ex_filter Filter Application + +A typical filter program, which receives an event and sends it immediately +after some modification, will appear as following: +\code +void event_filter(snd_seq_t *seq, snd_seq_event_t *ev) +{ + while (snd_seq_event_input(seq, &ev) >= 0) { + //.. modify input event .. + + snd_seq_ev_set_source(ev, my_port); + snd_seq_ev_set_subs(ev); + snd_seq_ev_set_direct(ev); + snd_seq_event_output(seq, ev); + snd_seq_drain_output(seq); + } +} +\endcode + +*/ + +#include +#include "seq_local.h" + +/**************************************************************************** + * * + * seq.h * + * Sequencer * + * * + ****************************************************************************/ + +/** + * \brief get identifier of sequencer handle + * \param seq sequencer handle + * \return ASCII identifier of sequencer handle + * + * Returns the ASCII identifier of the given sequencer handle. It's the same + * identifier specified in snd_seq_open(). + * + * \sa snd_seq_open() + */ +const char *snd_seq_name(snd_seq_t *seq) +{ + assert(seq); + return seq->name; +} + +/** + * \brief get type of sequencer handle + * \param seq sequencer handle + * \return type of sequencer handle + * + * Returns the type #snd_seq_type_t of the given sequencer handle. + * + * \sa snd_seq_open() + */ +snd_seq_type_t snd_seq_type(snd_seq_t *seq) +{ + assert(seq); + return seq->type; +} + +static int snd_seq_open_conf(snd_seq_t **seqp, const char *name, + snd_config_t *seq_root, snd_config_t *seq_conf, + int streams, int mode) +{ + const char *str; + char buf[256]; + int err; + snd_config_t *conf, *type_conf = NULL; + snd_config_iterator_t i, next; + const char *id; + const char *lib = NULL, *open_name = NULL; + int (*open_func)(snd_seq_t **, const char *, + snd_config_t *, snd_config_t *, + int, int) = NULL; +#ifndef PIC + extern void *snd_seq_open_symbols(void); +#endif + void *h = NULL; + if (snd_config_get_type(seq_conf) != SND_CONFIG_TYPE_COMPOUND) { + if (name) + SNDERR("Invalid type for SEQ %s definition", name); + else + SNDERR("Invalid type for SEQ definition"); + return -EINVAL; + } + err = snd_config_search(seq_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(seq_root, "seq_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for SEQ type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + open_name = buf; + snprintf(buf, sizeof(buf), "_snd_seq_%s_open", str); + } +#ifndef PIC + snd_seq_open_symbols(); +#endif + h = snd_dlopen(lib, RTLD_NOW); + if (h) + open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_SEQ_DLSYM_VERSION)); + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + if (! err) { + err = open_func(seqp, name, seq_root, seq_conf, streams, mode); + if (err < 0) + snd_dlclose(h); + else + (*seqp)->dl_handle = h; + } + return err; +} + +static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root, + const char *name, int streams, int mode, + int hop) +{ + int err; + snd_config_t *seq_conf; + err = snd_config_search_definition(root, "seq", name, &seq_conf); + if (err < 0) { + SNDERR("Unknown SEQ %s", name); + return err; + } + snd_config_set_hop(seq_conf, hop); + err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode); + snd_config_delete(seq_conf); + return err; +} + + +/** + * \brief Open the ALSA sequencer + * + * \param seqp Pointer to a snd_seq_t pointer. This pointer must be + * kept and passed to most of the other sequencer functions. + * \param name The sequencer's "name". This is \em not a name you make + * up for your own purposes; it has special significance to the ALSA + * library. Usually you need to pass \c "default" here. + * \param streams The read/write mode of the sequencer. Can be one of + * three values: + * - #SND_SEQ_OPEN_OUTPUT - open the sequencer for output only + * - #SND_SEQ_OPEN_INPUT - open the sequencer for input only + * - #SND_SEQ_OPEN_DUPLEX - open the sequencer for output and input + * \note Internally, these are translated to \c O_WRONLY, \c O_RDONLY and + * \c O_RDWR respectively and used as the second argument to the C library + * open() call. + * \param mode Optional modifier. Can be either 0, or + * #SND_SEQ_NONBLOCK, which will make read/write operations + * non-blocking. This can also be set later using #snd_seq_nonblock(). + * \return 0 on success otherwise a negative error code + * + * Creates a new handle and opens a connection to the kernel + * sequencer interface. + * After a client is created successfully, an event + * with #SND_SEQ_EVENT_CLIENT_START is broadcast to announce port. + * + * \sa snd_seq_open_lconf(), snd_seq_close(), snd_seq_type(), snd_seq_name(), + * snd_seq_nonblock(), snd_seq_client_id() + */ +int snd_seq_open(snd_seq_t **seqp, const char *name, + int streams, int mode) +{ + int err; + assert(seqp && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0); +} + +/** + * \brief Open the ALSA sequencer using local configuration + * + * \param seqp Pointer to a snd_seq_t pointer. + * \param name The name to open + * \param streams The read/write mode of the sequencer. + * \param mode Optional modifier + * \param lconf Local configuration + * \return 0 on success otherwise a negative error code + * + * See the snd_seq_open() function for further details. The extension + * is that the given configuration is used to resolve abstract name. + * + * \sa snd_seq_open() + */ +int snd_seq_open_lconf(snd_seq_t **seqp, const char *name, + int streams, int mode, snd_config_t *lconf) +{ + assert(seqp && name && lconf); + return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, 0); +} + +#ifndef DOC_HIDDEN +int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name, + int streams, int mode, snd_config_t *lconf, + snd_config_t *parent_conf) +{ + int hop; + assert(seqp && name && lconf); + if ((hop = snd_config_check_hop(parent_conf)) < 0) + return hop; + return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, hop + 1); +} +#endif + +/** + * \brief Close the sequencer + * \param seq Handle returned from #snd_seq_open() + * \return 0 on success otherwise a negative error code + * + * Closes the sequencer client and releases its resources. + * After a client is closed, an event with + * #SND_SEQ_EVENT_CLIENT_EXIT is broadcast to announce port. + * The connection between other clients are disconnected. + * Call this just before exiting your program. + * + * \sa snd_seq_close() + */ +int snd_seq_close(snd_seq_t *seq) +{ + int err; + assert(seq); + err = seq->ops->close(seq); + if (seq->dl_handle) + snd_dlclose(seq->dl_handle); + free(seq->obuf); + free(seq->ibuf); + free(seq->tmpbuf); + free(seq->name); + free(seq); + return err; +} + +/** + * \brief Returns the number of poll descriptors + * \param seq sequencer handle + * \param events the poll events to be checked (\c POLLIN and \c POLLOUT) + * \return the number of poll descriptors. + * + * Get the number of poll descriptors. The polling events to be checked + * can be specified by the second argument. When both input and output + * are checked, pass \c POLLIN|POLLOUT + * + * \sa snd_seq_poll_descriptors() + */ +int snd_seq_poll_descriptors_count(snd_seq_t *seq, short events) +{ + int result = 0; + assert(seq); + if (events & POLLIN) { + assert(seq->streams & SND_SEQ_OPEN_INPUT); + result++; + } + if (events & POLLOUT) { + assert(seq->streams & SND_SEQ_OPEN_OUTPUT); + result++; + } + return result ? 1 : 0; +} + +/** + * \brief Get poll descriptors + * \param seq sequencer handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \param events polling events to be checked (\c POLLIN and \c POLLOUT) + * \return count of filled descriptors + * + * Get poll descriptors assigned to the sequencer handle. + * Since a sequencer handle can duplex streams, you need to set which direction(s) + * is/are polled in \a events argument. When \c POLLIN bit is specified, + * the incoming events to the ports are checked. + * + * To check the returned poll-events, call #snd_seq_poll_descriptors_revents() + * instead of reading the pollfd structs directly. + * + * \sa snd_seq_poll_descriptors_count(), snd_seq_poll_descriptors_revents() + */ +int snd_seq_poll_descriptors(snd_seq_t *seq, struct pollfd *pfds, unsigned int space, short events) +{ + short revents = 0; + + assert(seq); + if ((events & POLLIN) && space >= 1) { + assert(seq->streams & SND_SEQ_OPEN_INPUT); + revents |= POLLIN|POLLERR|POLLNVAL; + } + if ((events & POLLOUT) && space >= 1) { + assert(seq->streams & SND_SEQ_OPEN_OUTPUT); + revents |= POLLOUT|POLLERR|POLLNVAL; + } + if (!revents) + return 0; + pfds->fd = seq->poll_fd; + pfds->events = revents; + return 1; +} + +/** + * \brief get returned events from poll descriptors + * \param seq sequencer handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + * + * \sa snd_seq_poll_descriptors() + */ +int snd_seq_poll_descriptors_revents(snd_seq_t *seq, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(seq && pfds && revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +/** + * \brief Set nonblock mode + * \param seq sequencer handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + * + * Change the blocking mode of the given client. + * In block mode, the client falls into sleep when it fills the + * output memory pool with full events. The client will be woken up + * after a certain amount of free space becomes available. + * + * \sa snd_seq_open() + */ +int snd_seq_nonblock(snd_seq_t *seq, int nonblock) +{ + int err; + assert(seq); + err = seq->ops->nonblock(seq, nonblock); + if (err < 0) + return err; + if (nonblock) + seq->mode |= SND_SEQ_NONBLOCK; + else + seq->mode &= ~SND_SEQ_NONBLOCK; + return 0; +} + +/** + * \brief Get the client id + * \param seq sequencer handle + * \return the client id + * + * Returns the id of the specified client. + * If an error occurs, function returns the negative error code. + * A client id is necessary to inquiry or to set the client information. + * A user client is assigned from 128 to 191. + * + * \sa snd_seq_open() + */ +int snd_seq_client_id(snd_seq_t *seq) +{ + assert(seq); + return seq->client; +} + +/** + * \brief Return the size of output buffer + * \param seq sequencer handle + * \return the size of output buffer in bytes + * + * Obtains the size of output buffer. + * This buffer is used to store decoded byte-stream of output events + * before transferring to sequencer. + * + * \sa snd_seq_set_output_buffer_size() + */ +size_t snd_seq_get_output_buffer_size(snd_seq_t *seq) +{ + assert(seq); + if (!seq->obuf) + return 0; + return seq->obufsize; +} + +/** + * \brief Return the size of input buffer + * \param seq sequencer handle + * \return the size of input buffer in bytes + * + * Obtains the size of input buffer. + * This buffer is used to read byte-stream of input events from sequencer. + * + * \sa snd_seq_set_input_buffer_size() + */ +size_t snd_seq_get_input_buffer_size(snd_seq_t *seq) +{ + assert(seq); + if (!seq->ibuf) + return 0; + return seq->ibufsize * sizeof(snd_seq_event_t); +} + +/** + * \brief Change the size of output buffer + * \param seq sequencer handle + * \param size the size of output buffer to be changed in bytes + * \return 0 on success otherwise a negative error code + * + * Changes the size of output buffer. + * + * \sa snd_seq_get_output_buffer_size() + */ +int snd_seq_set_output_buffer_size(snd_seq_t *seq, size_t size) +{ + assert(seq && seq->obuf); + assert(size >= sizeof(snd_seq_event_t)); + snd_seq_drop_output(seq); + if (size != seq->obufsize) { + char *newbuf; + newbuf = calloc(1, size); + if (newbuf == NULL) + return -ENOMEM; + free(seq->obuf); + seq->obuf = newbuf; + seq->obufsize = size; + } + return 0; +} + +/** + * \brief Resize the input buffer + * \param seq sequencer handle + * \param size the size of input buffer to be changed in bytes + * \return 0 on success otherwise a negative error code + * + * Changes the size of input buffer. + * + * \sa snd_seq_get_input_buffer_size() + */ +int snd_seq_set_input_buffer_size(snd_seq_t *seq, size_t size) +{ + assert(seq && seq->ibuf); + assert(size >= sizeof(snd_seq_event_t)); + snd_seq_drop_input(seq); + size = (size + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t); + if (size != seq->ibufsize) { + snd_seq_event_t *newbuf; + newbuf = calloc(sizeof(snd_seq_event_t), size); + if (newbuf == NULL) + return -ENOMEM; + free(seq->ibuf); + seq->ibuf = newbuf; + seq->ibufsize = size; + } + return 0; +} + + +/** + * \brief Get size of #snd_seq_system_info_t + * \return size in bytes + */ +size_t snd_seq_system_info_sizeof() +{ + return sizeof(snd_seq_system_info_t); +} + +/** + * \brief Allocate an empty #snd_seq_system_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_system_info_malloc(snd_seq_system_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_system_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief Frees a previously allocated #snd_seq_system_info_t + * \param obj pointer to object to free + */ +void snd_seq_system_info_free(snd_seq_system_info_t *obj) +{ + free(obj); +} + +/** + * \brief Copy one #snd_seq_system_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_system_info_copy(snd_seq_system_info_t *dst, const snd_seq_system_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get maximum number of queues + * \param info #snd_seq_system_info_t container + * \return maximum number of queues + * + * \sa snd_seq_system_info() + */ +int snd_seq_system_info_get_queues(const snd_seq_system_info_t *info) +{ + assert(info); + return info->queues; +} + +/** + * \brief Get maximum number of clients + * \param info #snd_seq_system_info_t container + * \return maximum number of clients + * + * \sa snd_seq_system_info() + */ +int snd_seq_system_info_get_clients(const snd_seq_system_info_t *info) +{ + assert(info); + return info->clients; +} + +/** + * \brief Get maximum number of ports + * \param info #snd_seq_system_info_t container + * \return maximum number of ports + * + * \sa snd_seq_system_info() + */ +int snd_seq_system_info_get_ports(const snd_seq_system_info_t *info) +{ + assert(info); + return info->ports; +} + +/** + * \brief Get maximum number of channels + * \param info #snd_seq_system_info_t container + * \return maximum number of channels + * + * \sa snd_seq_system_info() + */ +int snd_seq_system_info_get_channels(const snd_seq_system_info_t *info) +{ + assert(info); + return info->channels; +} + +/** + * \brief Get the current number of clients + * \param info #snd_seq_system_info_t container + * \return current number of clients + * + * \sa snd_seq_system_info() + */ +int snd_seq_system_info_get_cur_clients(const snd_seq_system_info_t *info) +{ + assert(info); + return info->cur_clients; +} + +/** + * \brief Get the current number of queues + * \param info #snd_seq_system_info_t container + * \return current number of queues + * + * \sa snd_seq_system_info() + */ +int snd_seq_system_info_get_cur_queues(const snd_seq_system_info_t *info) +{ + assert(info); + return info->cur_queues; +} + +/** + * \brief obtain the sequencer system information + * \param seq sequencer handle + * \param info the pointer to be stored + * \return 0 on success otherwise a negative error code + * + * Stores the global system information of ALSA sequencer system. + * The returned data contains + * the maximum available numbers of queues, clients, ports and channels. + */ +int snd_seq_system_info(snd_seq_t *seq, snd_seq_system_info_t * info) +{ + assert(seq && info); + return seq->ops->system_info(seq, info); +} + + +/*----------------------------------------------------------------*/ + +/** + * \brief get size of #snd_seq_client_info_t + * \return size in bytes + */ +size_t snd_seq_client_info_sizeof() +{ + return sizeof(snd_seq_client_info_t); +} + +/** + * \brief allocate an empty #snd_seq_client_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_client_info_malloc(snd_seq_client_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_client_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_client_info_t + * \param obj pointer to object to free + */ +void snd_seq_client_info_free(snd_seq_client_info_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_client_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_client_info_copy(snd_seq_client_info_t *dst, const snd_seq_client_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get client id of a client_info container + * \param info client_info container + * \return client id + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_set_client(), snd_seq_client_id() + */ +int snd_seq_client_info_get_client(const snd_seq_client_info_t *info) +{ + assert(info); + return info->client; +} + +/** + * \brief Get client type of a client_info container + * \param info client_info container + * \return client type + * + * The client type is either #SND_SEQ_KERNEL_CLIENT or #SND_SEQ_USER_CLIENT + * for kernel or user client respectively. + * + * \sa snd_seq_get_client_info() + */ +snd_seq_client_type_t snd_seq_client_info_get_type(const snd_seq_client_info_t *info) +{ + assert(info); + return info->type; +} + +/** + * \brief Get the name of a client_info container + * \param info client_info container + * \return name string + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_set_name() + */ +const char *snd_seq_client_info_get_name(snd_seq_client_info_t *info) +{ + assert(info); + return info->name; +} + +/** + * \brief Get the broadcast filter usage of a client_info container + * \param info client_info container + * \return 1 if broadcast is accepted + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_set_broadcast_filter() + */ +int snd_seq_client_info_get_broadcast_filter(const snd_seq_client_info_t *info) +{ + assert(info); + return (info->filter & SNDRV_SEQ_FILTER_BROADCAST) ? 1 : 0; +} + +/** + * \brief Get the error-bounce usage of a client_info container + * \param info client_info container + * \return 1 if error-bounce is enabled + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_set_error_bounce() + */ +int snd_seq_client_info_get_error_bounce(const snd_seq_client_info_t *info) +{ + assert(info); + return (info->filter & SNDRV_SEQ_FILTER_BOUNCE) ? 1 : 0; +} + +/** + * \brief (DEPRECATED) Get the event filter bitmap of a client_info container + * \param info client_info container + * \return NULL if no event filter, or pointer to event filter bitmap + * + * Use #snd_seq_client_info_event_filter_check() instead. + * + * \sa snd_seq_client_info_event_filter_add(), + * snd_seq_client_info_event_filter_del(), + * snd_seq_client_info_event_filter_check(), + * snd_seq_client_info_event_filter_clear(), + * snd_seq_get_client_info() + */ +const unsigned char *snd_seq_client_info_get_event_filter(const snd_seq_client_info_t *info) +{ + assert(info); + if (info->filter & SNDRV_SEQ_FILTER_USE_EVENT) + return info->event_filter; + else + return NULL; +} + +/** + * \brief Disable event filtering of a client_info container + * \param info client_info container + * + * Remove all event types added with #snd_seq_client_info_event_filter_add and clear + * the event filtering flag of this client_info container. + * + * \sa snd_seq_client_info_event_filter_add(), + * snd_seq_client_info_event_filter_del(), + * snd_seq_client_info_event_filter_check(), + * snd_seq_get_client_info(), + * snd_seq_set_client_info() + */ +void snd_seq_client_info_event_filter_clear(snd_seq_client_info_t *info) +{ + assert(info); + info->filter &= ~SNDRV_SEQ_FILTER_USE_EVENT; + memset(info->event_filter, 0, sizeof(info->event_filter)); +} + +/** + * \brief Add an event type to the event filtering of a client_info container + * \param info client_info container + * \param event_type event type to be added + * + * Set the event filtering flag of this client_info and add the specified event type to the + * filter bitmap of this client_info container. + * + * \sa snd_seq_get_client_info(), + * snd_seq_set_client_info(), + * snd_seq_client_info_event_filter_del(), + * snd_seq_client_info_event_filter_check(), + * snd_seq_client_info_event_filter_clear() + */ +void snd_seq_client_info_event_filter_add(snd_seq_client_info_t *info, int event_type) +{ + assert(info); + info->filter |= SNDRV_SEQ_FILTER_USE_EVENT; + snd_seq_set_bit(event_type, info->event_filter); +} + +/** + * \brief Remove an event type from the event filtering of a client_info container + * \param info client_info container + * \param event_type event type to be removed + * + * Removes the specified event from the filter bitmap of this client_info container. It will + * not clear the event filtering flag, use #snd_seq_client_info_event_filter_clear instead. + * + * \sa snd_seq_get_client_info(), + * snd_seq_set_client_info(), + * snd_seq_client_info_event_filter_add(), + * snd_seq_client_info_event_filter_check(), + * snd_seq_client_info_event_filter_clear() + */ +void snd_seq_client_info_event_filter_del(snd_seq_client_info_t *info, int event_type) +{ + assert(info); + snd_seq_unset_bit(event_type, info->event_filter); +} + +/** + * \brief Check if an event type is present in the event filtering of a client_info container + * \param info client_info container + * \param event_type event type to be checked + * \return 1 if the event type is present, 0 otherwise + * + * Test if the event type is in the filter bitmap of this client_info container. + * + * \sa snd_seq_get_client_info(), + * snd_seq_set_client_info(), + * snd_seq_client_info_event_filter_add(), + * snd_seq_client_info_event_filter_del(), + * snd_seq_client_info_event_filter_clear() + */ +int snd_seq_client_info_event_filter_check(snd_seq_client_info_t *info, int event_type) +{ + assert(info); + return snd_seq_get_bit(event_type, info->event_filter); +} + +/** + * \brief Get the number of opened ports of a client_info container + * \param info client_info container + * \return number of opened ports + * + * \sa snd_seq_get_client_info() + */ +int snd_seq_client_info_get_num_ports(const snd_seq_client_info_t *info) +{ + assert(info); + return info->num_ports; +} + +/** + * \brief Get the number of lost events of a client_info container + * \param info client_info container + * \return number of lost events + * + * \sa snd_seq_get_client_info() + */ +int snd_seq_client_info_get_event_lost(const snd_seq_client_info_t *info) +{ + assert(info); + return info->event_lost; +} + +/** + * \brief Set the client id of a client_info container + * \param info client_info container + * \param client client id + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_get_client() + */ +void snd_seq_client_info_set_client(snd_seq_client_info_t *info, int client) +{ + assert(info); + info->client = client; +} + +/** + * \brief Set the name of a client_info container + * \param info client_info container + * \param name name string + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_get_name(), + * snd_seq_set_client_name() + */ +void snd_seq_client_info_set_name(snd_seq_client_info_t *info, const char *name) +{ + assert(info && name); + strncpy(info->name, name, sizeof(info->name)); +} + +/** + * \brief Set the broadcast filter usage of a client_info container + * \param info client_info container + * \param val non-zero if broadcast is accepted + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_get_broadcast_filter() + */ +void snd_seq_client_info_set_broadcast_filter(snd_seq_client_info_t *info, int val) +{ + assert(info); + if (val) + info->filter |= SNDRV_SEQ_FILTER_BROADCAST; + else + info->filter &= ~SNDRV_SEQ_FILTER_BROADCAST; +} + +/** + * \brief Set the error-bounce usage of a client_info container + * \param info client_info container + * \param val non-zero if error is bounced + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_get_error_bounce() + */ +void snd_seq_client_info_set_error_bounce(snd_seq_client_info_t *info, int val) +{ + assert(info); + if (val) + info->filter |= SNDRV_SEQ_FILTER_BOUNCE; + else + info->filter &= ~SNDRV_SEQ_FILTER_BOUNCE; +} + +/** + * \brief (DEPRECATED) Set the event filter bitmap of a client_info container + * \param info client_info container + * \param filter event filter bitmap, pass NULL for no event filtering + * + * Use #snd_seq_client_info_event_filter_add instead. + * + * \sa snd_seq_client_info_event_filter_add(), + * snd_seq_client_info_event_filter_del(), + * snd_seq_client_info_event_filter_check(), + * snd_seq_client_info_event_filter_clear(), + * snd_seq_set_client_info() + */ +void snd_seq_client_info_set_event_filter(snd_seq_client_info_t *info, unsigned char *filter) +{ + assert(info); + if (! filter) + info->filter &= ~SNDRV_SEQ_FILTER_USE_EVENT; + else { + info->filter |= SNDRV_SEQ_FILTER_USE_EVENT; + memcpy(info->event_filter, filter, sizeof(info->event_filter)); + } +} + + +/** + * \brief obtain the information of the given client + * \param seq sequencer handle + * \param client client id + * \param info the pointer to be stored + * \return 0 on success otherwise a negative error code + * + * Obtains the information of the client with a client id specified by + * info argument. + * The obtained information is written on info parameter. + * + * \sa snd_seq_get_client_info() + */ +int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_t *info) +{ + assert(seq && info && client >= 0); + memset(info, 0, sizeof(snd_seq_client_info_t)); + info->client = client; + return seq->ops->get_client_info(seq, info); +} + +/** + * \brief obtain the current client information + * \param seq sequencer handle + * \param info the pointer to be stored + * \return 0 on success otherwise a negative error code + * + * Obtains the information of the current client stored on info. + * client and type fields are ignored. + * + * \sa snd_seq_get_any_client_info(), snd_seq_set_client_info(), + * snd_seq_query_next_client() + */ +int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t *info) +{ + return snd_seq_get_any_client_info(seq, seq->client, info); +} + +/** + * \brief set the current client information + * \param seq sequencer handle + * \param info the client info data to set + * \return 0 on success otherwise a negative error code + * + * Obtains the information of the current client stored on info. + * client and type fields are ignored. + * + * \sa snd_seq_get_client_info() + */ +int snd_seq_set_client_info(snd_seq_t *seq, snd_seq_client_info_t *info) +{ + assert(seq && info); + info->client = seq->client; + info->type = USER_CLIENT; + return seq->ops->set_client_info(seq, info); +} + +/** + * \brief query the next client + * \param seq sequencer handle + * \param info query pattern and result + * + * Queries the next client. + * The search begins at the client with an id one greater than + * client field in info. + * If a client is found, its attributes are stored in info, + * and zero is returned. + * Otherwise returns a negative error code. + * + * \sa snd_seq_get_any_client_info() + */ +int snd_seq_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info) +{ + assert(seq && info); + return seq->ops->query_next_client(seq, info); +} + + +/*----------------------------------------------------------------*/ + + +/* + * Port + */ + +/** + * \brief get size of #snd_seq_port_info_t + * \return size in bytes + */ +size_t snd_seq_port_info_sizeof() +{ + return sizeof(snd_seq_port_info_t); +} + +/** + * \brief allocate an empty #snd_seq_port_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_port_info_malloc(snd_seq_port_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_port_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_port_info_t + * \param obj pointer to object to free + */ +void snd_seq_port_info_free(snd_seq_port_info_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_port_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_port_info_copy(snd_seq_port_info_t *dst, const snd_seq_port_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get client id of a port_info container + * \param info port_info container + * \return client id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_client() + */ +int snd_seq_port_info_get_client(const snd_seq_port_info_t *info) +{ + assert(info); + return info->addr.client; +} + +/** + * \brief Get port id of a port_info container + * \param info port_info container + * \return port id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_port() + */ +int snd_seq_port_info_get_port(const snd_seq_port_info_t *info) +{ + assert(info); + return info->addr.port; +} + +/** + * \brief Get client/port address of a port_info container + * \param info port_info container + * \return client/port address pointer + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_addr() + */ +const snd_seq_addr_t *snd_seq_port_info_get_addr(const snd_seq_port_info_t *info) +{ + assert(info); + return &info->addr; +} + +/** + * \brief Get the name of a port_info container + * \param info port_info container + * \return name string + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_name() + */ +const char *snd_seq_port_info_get_name(const snd_seq_port_info_t *info) +{ + assert(info); + return info->name; +} + +/** + * \brief Get the capability bits of a port_info container + * \param info port_info container + * \return capability bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_capability() + */ +unsigned int snd_seq_port_info_get_capability(const snd_seq_port_info_t *info) +{ + assert(info); + return info->capability; +} + +/** + * \brief Get the type bits of a port_info container + * \param info port_info container + * \return port type bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_type() + */ +unsigned int snd_seq_port_info_get_type(const snd_seq_port_info_t *info) +{ + assert(info); + return info->type; +} + +/** + * \brief Get the number of read subscriptions of a port_info container + * \param info port_info container + * \return number of read subscriptions + * + * \sa snd_seq_get_port_info() + */ +int snd_seq_port_info_get_read_use(const snd_seq_port_info_t *info) +{ + assert(info); + return info->read_use; +} + +/** + * \brief Get the number of write subscriptions of a port_info container + * \param info port_info container + * \return number of write subscriptions + * + * \sa snd_seq_get_port_info() + */ +int snd_seq_port_info_get_write_use(const snd_seq_port_info_t *info) +{ + assert(info); + return info->write_use; +} + +/** + * \brief Get the midi channels of a port_info container + * \param info port_info container + * \return number of midi channels (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_midi_channels() + */ +int snd_seq_port_info_get_midi_channels(const snd_seq_port_info_t *info) +{ + assert(info); + return info->midi_channels; +} + +/** + * \brief Get the midi voices of a port_info container + * \param info port_info container + * \return number of midi voices (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_midi_voices() + */ +int snd_seq_port_info_get_midi_voices(const snd_seq_port_info_t *info) +{ + assert(info); + return info->midi_voices; +} + +/** + * \brief Get the synth voices of a port_info container + * \param info port_info container + * \return number of synth voices (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_synth_voices() + */ +int snd_seq_port_info_get_synth_voices(const snd_seq_port_info_t *info) +{ + assert(info); + return info->synth_voices; +} + +/** + * \brief Get the port-specified mode of a port_info container + * \param info port_info container + * \return 1 if port id is specified at creation + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_port_specified() + */ +int snd_seq_port_info_get_port_specified(const snd_seq_port_info_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? 1 : 0; +} + +/** + * \brief Get the time-stamping mode of the given port in a port_info container + * \param info port_info container + * \return 1 if the port updates timestamps of incoming events + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamping() + */ +int snd_seq_port_info_get_timestamping(const snd_seq_port_info_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0; +} + +/** + * \brief Get whether the time-stamping of the given port is real-time mode + * \param info port_info container + * \return 1 if the time-stamping is in the real-time mode + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamp_real() + */ +int snd_seq_port_info_get_timestamp_real(const snd_seq_port_info_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0; +} + +/** + * \brief Get the queue id to update timestamps + * \param info port_info container + * \return the queue id to get the timestamps + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamp_queue() + */ +int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info) +{ + assert(info); + return info->time_queue; +} + +/** + * \brief Set the client id of a port_info container + * \param info port_info container + * \param client client id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_client() + */ +void snd_seq_port_info_set_client(snd_seq_port_info_t *info, int client) +{ + assert(info); + info->addr.client = client; +} + +/** + * \brief Set the port id of a port_info container + * \param info port_info container + * \param port port id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_port() + */ +void snd_seq_port_info_set_port(snd_seq_port_info_t *info, int port) +{ + assert(info); + info->addr.port = port; +} + +/** + * \brief Set the client/port address of a port_info container + * \param info port_info container + * \param addr client/port address + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_addr() + */ +void snd_seq_port_info_set_addr(snd_seq_port_info_t *info, const snd_seq_addr_t *addr) +{ + assert(info); + info->addr = *addr; +} + +/** + * \brief Set the name of a port_info container + * \param info port_info container + * \param name name string + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_name() + */ +void snd_seq_port_info_set_name(snd_seq_port_info_t *info, const char *name) +{ + assert(info && name); + strncpy(info->name, name, sizeof(info->name)); +} + +/** + * \brief set the capability bits of a port_info container + * \param info port_info container + * \param capability capability bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_capability() + */ +void snd_seq_port_info_set_capability(snd_seq_port_info_t *info, unsigned int capability) +{ + assert(info); + info->capability = capability; +} + +/** + * \brief Get the type bits of a port_info container + * \param info port_info container + * \param type port type bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_type() + */ +void snd_seq_port_info_set_type(snd_seq_port_info_t *info, unsigned int type) +{ + assert(info); + info->type = type; +} + +/** + * \brief set the midi channels of a port_info container + * \param info port_info container + * \param channels midi channels (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_midi_channels() + */ +void snd_seq_port_info_set_midi_channels(snd_seq_port_info_t *info, int channels) +{ + assert(info); + info->midi_channels = channels; +} + +/** + * \brief set the midi voices of a port_info container + * \param info port_info container + * \param voices midi voices (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_midi_voices() + */ +void snd_seq_port_info_set_midi_voices(snd_seq_port_info_t *info, int voices) +{ + assert(info); + info->midi_voices = voices; +} + +/** + * \brief set the synth voices of a port_info container + * \param info port_info container + * \param voices synth voices (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_synth_voice() + */ +void snd_seq_port_info_set_synth_voices(snd_seq_port_info_t *info, int voices) +{ + assert(info); + info->synth_voices = voices; +} + +/** + * \brief Set the port-specified mode of a port_info container + * \param info port_info container + * \param val non-zero if specifying the port id at creation + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_port_specified() + */ +void snd_seq_port_info_set_port_specified(snd_seq_port_info_t *info, int val) +{ + assert(info); + if (val) + info->flags |= SNDRV_SEQ_PORT_FLG_GIVEN_PORT; + else + info->flags &= ~SNDRV_SEQ_PORT_FLG_GIVEN_PORT; +} + +/** + * \brief Set the time-stamping mode of the given port + * \param info port_info container + * \param enable non-zero if updating the timestamps of incoming events + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamping() + */ +void snd_seq_port_info_set_timestamping(snd_seq_port_info_t *info, int enable) +{ + assert(info); + if (enable) + info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP; + else + info->flags &= ~SNDRV_SEQ_PORT_FLG_TIMESTAMP; +} + +/** + * \brief Set whether the timestime is updated in the real-time mode + * \param info port_info container + * \param enable non-zero if updating the timestamps in real-time mode + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamp_real() + */ +void snd_seq_port_info_set_timestamp_real(snd_seq_port_info_t *info, int enable) +{ + assert(info); + if (enable) + info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL; + else + info->flags &= ~SNDRV_SEQ_PORT_FLG_TIME_REAL; +} + +/** + * \brief Set the queue id for timestamping + * \param info port_info container + * \param queue the queue id to get timestamps + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamp_queue() + */ +void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue) +{ + assert(info); + info->time_queue = queue; +} + + +/** + * \brief create a sequencer port on the current client + * \param seq sequencer handle + * \param port port information for the new port + * \return 0 on success otherwise a negative error code + * + * Creates a sequencer port on the current client. + * The attributes of created port is specified in \a info argument. + * + * The client field in \a info argument is overwritten with the current client id. + * The port id to be created can be specified via #snd_seq_port_info_set_port_specified. + * You can get the created port id by reading the port pointer via #snd_seq_port_info_get_port. + * + * Each port has the capability bit-masks to specify the access capability + * of the port from other clients. + * The capability bit flags are defined as follows: + * - #SND_SEQ_PORT_CAP_READ Readable from this port + * - #SND_SEQ_PORT_CAP_WRITE Writable to this port. + * - #SND_SEQ_PORT_CAP_SYNC_READ For synchronization (not implemented) + * - #SND_SEQ_PORT_CAP_SYNC_WRITE For synchronization (not implemented) + * - #SND_SEQ_PORT_CAP_DUPLEX Read/write duplex access is supported + * - #SND_SEQ_PORT_CAP_SUBS_READ Read subscription is allowed + * - #SND_SEQ_PORT_CAP_SUBS_WRITE Write subscription is allowed + * - #SND_SEQ_PORT_CAP_NO_EXPORT Subscription management from 3rd client is disallowed + * + * Each port has also the type bitmasks defined as follows: + * - #SND_SEQ_PORT_TYPE_SPECIFIC Hardware specific port + * - #SND_SEQ_PORT_TYPE_MIDI_GENERIC Generic MIDI device + * - #SND_SEQ_PORT_TYPE_MIDI_GM General MIDI compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_GM2 General MIDI 2 compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_GS GS compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_XG XG compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_MT32 MT-32 compatible device + * - #SND_SEQ_PORT_TYPE_HARDWARE Implemented in hardware + * - #SND_SEQ_PORT_TYPE_SOFTWARE Implemented in software + * - #SND_SEQ_PORT_TYPE_SYNTHESIZER Generates sound + * - #SND_SEQ_PORT_TYPE_PORT Connects to other device(s) + * - #SND_SEQ_PORT_TYPE_APPLICATION Application (sequencer/editor) + * + * A port may contain specific midi channels, midi voices and synth voices. + * These values could be zero as default. + * + * \sa snd_seq_delete_port(), snd_seq_get_port_info(), + * snd_seq_create_simple_port() + */ +int snd_seq_create_port(snd_seq_t *seq, snd_seq_port_info_t * port) +{ + assert(seq && port); + port->addr.client = seq->client; + return seq->ops->create_port(seq, port); +} + +/** + * \brief delete a sequencer port on the current client + * \param seq sequencer handle + * \param port port to be deleted + * \return 0 on success otherwise a negative error code + * + * Deletes the existing sequencer port on the current client. + * + * \sa snd_seq_create_port(), snd_seq_delete_simple_port() + */ +int snd_seq_delete_port(snd_seq_t *seq, int port) +{ + snd_seq_port_info_t pinfo; + assert(seq); + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.addr.client = seq->client; + pinfo.addr.port = port; + return seq->ops->delete_port(seq, &pinfo); +} + +/** + * \brief obtain the information of a port on an arbitrary client + * \param seq sequencer handle + * \param client client id to get + * \param port port id to get + * \param info pointer information returns + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_port_info() + */ +int snd_seq_get_any_port_info(snd_seq_t *seq, int client, int port, snd_seq_port_info_t * info) +{ + assert(seq && info && client >= 0 && port >= 0); + memset(info, 0, sizeof(snd_seq_port_info_t)); + info->addr.client = client; + info->addr.port = port; + return seq->ops->get_port_info(seq, info); +} + +/** + * \brief obtain the information of a port on the current client + * \param seq sequencer handle + * \param port port id to get + * \param info pointer information returns + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_create_port(), snd_seq_get_any_port_info(), snd_seq_set_port_info(), + * snd_seq_query_next_port() + */ +int snd_seq_get_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info) +{ + return snd_seq_get_any_port_info(seq, seq->client, port, info); +} + +/** + * \brief set the information of a port on the current client + * \param seq sequencer handle + * \param port port to be set + * \param info port information to be set + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_set_port_info() + */ +int snd_seq_set_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info) +{ + assert(seq && info && port >= 0); + info->addr.client = seq->client; + info->addr.port = port; + return seq->ops->set_port_info(seq, info); +} + +/** + * \brief query the next matching port + * \param seq sequencer handle + * \param info query pattern and result + + * Queries the next matching port on the client specified in + * \a info argument. + * The search begins at the next port specified in + * port field of \a info argument. + * For finding the first port at a certain client, give -1. + * + * If a matching port is found, its attributes are stored on + * \a info and function returns zero. + * Otherwise, a negative error code is returned. + * + * \sa snd_seq_get_port_info() + */ +int snd_seq_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info) +{ + assert(seq && info); + return seq->ops->query_next_port(seq, info); +} + + +/*----------------------------------------------------------------*/ + +/* + * subscription + */ + + +/** + * \brief get size of #snd_seq_port_subscribe_t + * \return size in bytes + */ +size_t snd_seq_port_subscribe_sizeof() +{ + return sizeof(snd_seq_port_subscribe_t); +} + +/** + * \brief allocate an empty #snd_seq_port_subscribe_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_port_subscribe_malloc(snd_seq_port_subscribe_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_port_subscribe_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_port_subscribe_t + * \param obj pointer to object to free + */ +void snd_seq_port_subscribe_free(snd_seq_port_subscribe_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_port_subscribe_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_port_subscribe_copy(snd_seq_port_subscribe_t *dst, const snd_seq_port_subscribe_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get sender address of a port_subscribe container + * \param info port_subscribe container + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_set_sender() + */ +const snd_seq_addr_t *snd_seq_port_subscribe_get_sender(const snd_seq_port_subscribe_t *info) +{ + assert(info); + return &info->sender; +} + +/** + * \brief Get destination address of a port_subscribe container + * \param info port_subscribe container + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_set_dest() + */ +const snd_seq_addr_t *snd_seq_port_subscribe_get_dest(const snd_seq_port_subscribe_t *info) +{ + assert(info); + return &info->dest; +} + +/** + * \brief Get the queue id of a port_subscribe container + * \param info port_subscribe container + * \return queue id + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_set_queue() + */ +int snd_seq_port_subscribe_get_queue(const snd_seq_port_subscribe_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the exclusive mode of a port_subscribe container + * \param info port_subscribe container + * \return 1 if exclusive mode + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_set_exclusive() + */ +int snd_seq_port_subscribe_get_exclusive(const snd_seq_port_subscribe_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE) ? 1 : 0; +} + +/** + * \brief Get the time-update mode of a port_subscribe container + * \param info port_subscribe container + * \return 1 if update timestamp + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_set_time_update() + */ +int snd_seq_port_subscribe_get_time_update(const snd_seq_port_subscribe_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) ? 1 : 0; +} + +/** + * \brief Get the real-time update mode of a port_subscribe container + * \param info port_subscribe container + * \return 1 if real-time update mode + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_set_time_real() + */ +int snd_seq_port_subscribe_get_time_real(const snd_seq_port_subscribe_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) ? 1 : 0; +} + +/** + * \brief Set sender address of a port_subscribe container + * \param info port_subscribe container + * \param addr sender address + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_sender() + */ +void snd_seq_port_subscribe_set_sender(snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr) +{ + assert(info); + memcpy(&info->sender, addr, sizeof(*addr)); +} + +/** + * \brief Set destination address of a port_subscribe container + * \param info port_subscribe container + * \param addr destination address + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_dest() + */ +void snd_seq_port_subscribe_set_dest(snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr) +{ + assert(info); + memcpy(&info->dest, addr, sizeof(*addr)); +} + +/** + * \brief Set the queue id of a port_subscribe container + * \param info port_subscribe container + * \param q queue id + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_queue() + */ +void snd_seq_port_subscribe_set_queue(snd_seq_port_subscribe_t *info, int q) +{ + assert(info); + info->queue = q; +} + +/** + * \brief Set the exclusive mode of a port_subscribe container + * \param info port_subscribe container + * \param val non-zero to enable + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_exclusive() + */ +void snd_seq_port_subscribe_set_exclusive(snd_seq_port_subscribe_t *info, int val) +{ + assert(info); + if (val) + info->flags |= SNDRV_SEQ_PORT_SUBS_EXCLUSIVE; + else + info->flags &= ~SNDRV_SEQ_PORT_SUBS_EXCLUSIVE; +} + +/** + * \brief Set the time-update mode of a port_subscribe container + * \param info port_subscribe container + * \param val non-zero to enable + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_time_update() + */ +void snd_seq_port_subscribe_set_time_update(snd_seq_port_subscribe_t *info, int val) +{ + assert(info); + if (val) + info->flags |= SNDRV_SEQ_PORT_SUBS_TIMESTAMP; + else + info->flags &= ~SNDRV_SEQ_PORT_SUBS_TIMESTAMP; +} + +/** + * \brief Set the real-time mode of a port_subscribe container + * \param info port_subscribe container + * \param val non-zero to enable + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_time_real() + */ +void snd_seq_port_subscribe_set_time_real(snd_seq_port_subscribe_t *info, int val) +{ + assert(info); + if (val) + info->flags |= SNDRV_SEQ_PORT_SUBS_TIME_REAL; + else + info->flags &= ~SNDRV_SEQ_PORT_SUBS_TIME_REAL; +} + + +/** + * \brief obtain subscription information + * \param seq sequencer handle + * \param sub pointer to return the subscription information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_subscribe_port(), snd_seq_query_port_subscribers() + */ +int snd_seq_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) +{ + assert(seq && sub); + return seq->ops->get_port_subscription(seq, sub); +} + +/** + * \brief subscribe a port connection + * \param seq sequencer handle + * \param sub subscription information + * \return 0 on success otherwise a negative error code + * + * Subscribes a connection between two ports. + * The subscription information is stored in sub argument. + * + * \sa snd_seq_get_port_subscription(), snd_seq_unsubscribe_port(), + * snd_seq_connect_from(), snd_seq_connect_to() + */ +int snd_seq_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) +{ + assert(seq && sub); + return seq->ops->subscribe_port(seq, sub); +} + +/** + * \brief unsubscribe a connection between ports + * \param seq sequencer handle + * \param sub subscription information to disconnect + * \return 0 on success otherwise a negative error code + * + * Unsubscribes a connection between two ports, + * described in sender and dest fields in sub argument. + * + * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from(), snd_seq_disconnect_to() + */ +int snd_seq_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) +{ + assert(seq && sub); + return seq->ops->unsubscribe_port(seq, sub); +} + + +/** + * \brief get size of #snd_seq_query_subscribe_t + * \return size in bytes + */ +size_t snd_seq_query_subscribe_sizeof() +{ + return sizeof(snd_seq_query_subscribe_t); +} + +/** + * \brief allocate an empty #snd_seq_query_subscribe_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_query_subscribe_malloc(snd_seq_query_subscribe_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_query_subscribe_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_query_subscribe_t + * \param obj pointer to object to free + */ +void snd_seq_query_subscribe_free(snd_seq_query_subscribe_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_query_subscribe_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_query_subscribe_copy(snd_seq_query_subscribe_t *dst, const snd_seq_query_subscribe_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the client id of a query_subscribe container + * \param info query_subscribe container + * \return client id + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_client() + */ +int snd_seq_query_subscribe_get_client(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return info->root.client; +} + +/** + * \brief Get the port id of a query_subscribe container + * \param info query_subscribe container + * \return port id + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_port() + */ +int snd_seq_query_subscribe_get_port(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return info->root.port; +} + +/** + * \brief Get the client/port address of a query_subscribe container + * \param info query_subscribe container + * \return client/port address pointer + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_root() + */ +const snd_seq_addr_t *snd_seq_query_subscribe_get_root(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return &info->root; +} + +/** + * \brief Get the query type of a query_subscribe container + * \param info query_subscribe container + * \return query type + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_type() + */ +snd_seq_query_subs_type_t snd_seq_query_subscribe_get_type(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return info->type; +} + +/** + * \brief Get the index of subscriber of a query_subscribe container + * \param info query_subscribe container + * \return subscriber's index + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_index() + */ +int snd_seq_query_subscribe_get_index(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return info->index; +} + +/** + * \brief Get the number of subscriptions of a query_subscribe container + * \param info query_subscribe container + * \return number of subscriptions + * + * \sa snd_seq_query_port_subscribers() + */ +int snd_seq_query_subscribe_get_num_subs(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return info->num_subs; +} + +/** + * \brief Get the address of subscriber of a query_subscribe container + * \param info query_subscribe container + * \return subscriber's address pointer + * + * \sa snd_seq_query_port_subscribers() + */ +const snd_seq_addr_t *snd_seq_query_subscribe_get_addr(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return &info->addr; +} + +/** + * \brief Get the queue id of subscriber of a query_subscribe container + * \param info query_subscribe container + * \return subscriber's queue id + * + * \sa snd_seq_query_port_subscribers() + */ +int snd_seq_query_subscribe_get_queue(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the exclusive mode of a query_subscribe container + * \param info query_subscribe container + * \return 1 if exclusive mode + * + * \sa snd_seq_query_port_subscribers() + */ +int snd_seq_query_subscribe_get_exclusive(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE) ? 1 : 0; +} + +/** + * \brief Get the time-update mode of a query_subscribe container + * \param info query_subscribe container + * \return 1 if update timestamp + * + * \sa snd_seq_query_port_subscribers() + */ +int snd_seq_query_subscribe_get_time_update(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) ? 1 : 0; +} + +/** + * \brief Get the real-time update mode of a query_subscribe container + * \param info query_subscribe container + * \return 1 if real-time update mode + * + * \sa snd_seq_query_port_subscribers() + */ +int snd_seq_query_subscribe_get_time_real(const snd_seq_query_subscribe_t *info) +{ + assert(info); + return (info->flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) ? 1 : 0; +} + +/** + * \brief Set the client id of a query_subscribe container + * \param info query_subscribe container + * \param client client id + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_client() + */ +void snd_seq_query_subscribe_set_client(snd_seq_query_subscribe_t *info, int client) +{ + assert(info); + info->root.client = client; +} + +/** + * \brief Set the port id of a query_subscribe container + * \param info query_subscribe container + * \param port port id + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_port() + */ +void snd_seq_query_subscribe_set_port(snd_seq_query_subscribe_t *info, int port) +{ + assert(info); + info->root.port = port; +} + +/** + * \brief Set the client/port address of a query_subscribe container + * \param info query_subscribe container + * \param addr client/port address pointer + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_root() + */ +void snd_seq_query_subscribe_set_root(snd_seq_query_subscribe_t *info, const snd_seq_addr_t *addr) +{ + assert(info); + info->root = *addr; +} + +/** + * \brief Set the query type of a query_subscribe container + * \param info query_subscribe container + * \param type query type + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_type() + */ +void snd_seq_query_subscribe_set_type(snd_seq_query_subscribe_t *info, snd_seq_query_subs_type_t type) +{ + assert(info); + info->type = type; +} + +/** + * \brief Set the subscriber's index to be queried + * \param info query_subscribe container + * \param index index to be queried + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_index() + */ +void snd_seq_query_subscribe_set_index(snd_seq_query_subscribe_t *info, int index) +{ + assert(info); + info->index = index; +} + + +/** + * \brief query port subscriber list + * \param seq sequencer handle + * \param subs subscription to query + * \return 0 on success otherwise a negative error code + * + * Queries the subscribers accessing to a port. + * The query information is specified in subs argument. + * + * At least, the client id, the port id, the index number and + * the query type must be set to perform a proper query. + * As the query type, #SND_SEQ_QUERY_SUBS_READ or #SND_SEQ_QUERY_SUBS_WRITE + * can be specified to check whether the readers or the writers to the port. + * To query the first subscription, set 0 to the index number. To list up + * all the subscriptions, call this function with the index numbers from 0 + * until this returns a negative value. + * + * \sa snd_seq_get_port_subscription() + */ +int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subscribe_t * subs) +{ + assert(seq && subs); + return seq->ops->query_port_subscribers(seq, subs); +} + +/*----------------------------------------------------------------*/ + +/* + * queue handlers + */ + +/** + * \brief get size of #snd_seq_queue_info_t + * \return size in bytes + */ +size_t snd_seq_queue_info_sizeof() +{ + return sizeof(snd_seq_queue_info_t); +} + +/** + * \brief allocate an empty #snd_seq_queue_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_queue_info_malloc(snd_seq_queue_info_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_queue_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_queue_info_t + * \param obj pointer to object to free + */ +void snd_seq_queue_info_free(snd_seq_queue_info_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_queue_info_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_queue_info_copy(snd_seq_queue_info_t *dst, const snd_seq_queue_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the queue id of a queue_info container + * \param info queue_info container + * \return queue id + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_set_queue() + */ +int snd_seq_queue_info_get_queue(const snd_seq_queue_info_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the name of a queue_info container + * \param info queue_info container + * \return name string + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_set_name() + */ +const char *snd_seq_queue_info_get_name(const snd_seq_queue_info_t *info) +{ + assert(info); + return info->name; +} + +/** + * \brief Get the owner client id of a queue_info container + * \param info queue_info container + * \return owner client id + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_set_owner() + */ +int snd_seq_queue_info_get_owner(const snd_seq_queue_info_t *info) +{ + assert(info); + return info->owner; +} + +/** + * \brief Get the lock status of a queue_info container + * \param info queue_info container + * \return lock status --- non-zero = locked + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_set_locked() + */ +int snd_seq_queue_info_get_locked(const snd_seq_queue_info_t *info) +{ + assert(info); + return info->locked; +} + +/** + * \brief Get the conditional bit flags of a queue_info container + * \param info queue_info container + * \return conditional bit flags + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_set_flags() + */ +unsigned int snd_seq_queue_info_get_flags(const snd_seq_queue_info_t *info) +{ + assert(info); + return info->flags; +} + +/** + * \brief Set the name of a queue_info container + * \param info queue_info container + * \param name name string + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_get_name() + */ +void snd_seq_queue_info_set_name(snd_seq_queue_info_t *info, const char *name) +{ + assert(info && name); + strncpy(info->name, name, sizeof(info->name)); +} + +/** + * \brief Set the owner client id of a queue_info container + * \param info queue_info container + * \param owner client id + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_get_owner() + */ +void snd_seq_queue_info_set_owner(snd_seq_queue_info_t *info, int owner) +{ + assert(info); + info->owner = owner; +} + +/** + * \brief Set the lock status of a queue_info container + * \param info queue_info container + * \param locked lock status + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_get_locked() + */ +void snd_seq_queue_info_set_locked(snd_seq_queue_info_t *info, int locked) +{ + assert(info); + info->locked = locked; +} + +/** + * \brief Set the conditional bit flags of a queue_info container + * \param info queue_info container + * \param flags conditional bit flags + * + * \sa snd_seq_get_queue_info(), snd_seq_queue_info_get_flags() + */ +void snd_seq_queue_info_set_flags(snd_seq_queue_info_t *info, unsigned int flags) +{ + assert(info); + info->flags = flags; +} + + +/** + * \brief create a queue + * \param seq sequencer handle + * \param info queue information to initialize + * \return the queue id (zero or positive) on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue() + */ +int snd_seq_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) +{ + int err; + assert(seq && info); + info->owner = seq->client; + err = seq->ops->create_queue(seq, info); + if (err < 0) + return err; + return info->queue; +} + +/** + * \brief allocate a queue with the specified name + * \param seq sequencer handle + * \param name the name of the new queue + * \return the queue id (zero or positive) on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue() + */ +int snd_seq_alloc_named_queue(snd_seq_t *seq, const char *name) +{ + snd_seq_queue_info_t info; + memset(&info, 0, sizeof(info)); + info.locked = 1; + if (name) + strncpy(info.name, name, sizeof(info.name) - 1); + return snd_seq_create_queue(seq, &info); +} + +/** + * \brief allocate a queue + * \param seq sequencer handle + * \return the queue id (zero or positive) on success otherwise a negative error code + * + * \sa snd_seq_alloc_named_queue(), snd_seq_create_queue(), snd_seq_free_queue(), + * snd_seq_get_queue_info() + */ +int snd_seq_alloc_queue(snd_seq_t *seq) +{ + return snd_seq_alloc_named_queue(seq, NULL); +} + +/** + * \brief delete the specified queue + * \param seq sequencer handle + * \param q queue id to delete + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue() + */ +int snd_seq_free_queue(snd_seq_t *seq, int q) +{ + snd_seq_queue_info_t info; + assert(seq); + memset(&info, 0, sizeof(info)); + info.queue = q; + return seq->ops->delete_queue(seq, &info); +} + +/** + * \brief obtain queue attributes + * \param seq sequencer handle + * \param q queue id to query + * \param info information returned + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue(), snd_seq_set_queue_info(), snd_seq_query_named_queue() + */ +int snd_seq_get_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info) +{ + assert(seq && info); + info->queue = q; + return seq->ops->get_queue_info(seq, info); +} + +/** + * \brief change the queue attributes + * \param seq sequencer handle + * \param q queue id to change + * \param info information changed + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_queue_info() + */ +int snd_seq_set_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info) +{ + assert(seq && info); + info->queue = q; + return seq->ops->set_queue_info(seq, info); +} + +/** + * \brief query the matching queue with the specified name + * \param seq sequencer handle + * \param name the name string to query + * \return the queue id if found or negative error code + * + * Searches the matching queue with the specified name string. + * + * \sa snd_seq_get_queue_info() + */ +int snd_seq_query_named_queue(snd_seq_t *seq, const char *name) +{ + int err; + snd_seq_queue_info_t info; + assert(seq && name); + strncpy(info.name, name, sizeof(info.name)); + err = seq->ops->get_named_queue(seq, &info); + if (err < 0) + return err; + return info.queue; +} + +/** + * \brief Get the queue usage flag to the client + * \param seq sequencer handle + * \param q queue id + * \return 1 = client is allowed to access the queue, 0 = not allowed, + * otherwise a negative error code + * + * \sa snd_seq_get_queue_info(), snd_seq_set_queue_usage() + */ +int snd_seq_get_queue_usage(snd_seq_t *seq, int q) +{ + struct sndrv_seq_queue_client info; + int err; + assert(seq); + memset(&info, 0, sizeof(info)); + info.queue = q; + info.client = seq->client; + if ((err = seq->ops->get_queue_client(seq, &info)) < 0) + return err; + return info.used; +} + +/** + * \brief Set the queue usage flag to the client + * \param seq sequencer handle + * \param q queue id + * \param used non-zero if the client is allowed + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_queue_info(), snd_seq_set_queue_usage() + */ +int snd_seq_set_queue_usage(snd_seq_t *seq, int q, int used) +{ + struct sndrv_seq_queue_client info; + assert(seq); + memset(&info, 0, sizeof(info)); + info.queue = q; + info.client = seq->client; + info.used = used ? 1 : 0; + return seq->ops->set_queue_client(seq, &info); +} + + +/** + * \brief get size of #snd_seq_queue_status_t + * \return size in bytes + */ +size_t snd_seq_queue_status_sizeof() +{ + return sizeof(snd_seq_queue_status_t); +} + +/** + * \brief allocate an empty #snd_seq_queue_status_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_queue_status_malloc(snd_seq_queue_status_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_queue_status_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_queue_status_t + * \param obj pointer to object to free + */ +void snd_seq_queue_status_free(snd_seq_queue_status_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_queue_status_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_queue_status_copy(snd_seq_queue_status_t *dst, const snd_seq_queue_status_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the queue id of a queue_status container + * \param info queue_status container + * \return queue id + * + * \sa snd_seq_get_queue_status() + */ +int snd_seq_queue_status_get_queue(const snd_seq_queue_status_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the number of events of a queue_status container + * \param info queue_status container + * \return number of events + * + * \sa snd_seq_get_queue_status() + */ +int snd_seq_queue_status_get_events(const snd_seq_queue_status_t *info) +{ + assert(info); + return info->events; +} + +/** + * \brief Get the tick time of a queue_status container + * \param info queue_status container + * \return tick time + * + * \sa snd_seq_get_queue_status() + */ +snd_seq_tick_time_t snd_seq_queue_status_get_tick_time(const snd_seq_queue_status_t *info) +{ + assert(info); + return info->tick; +} + +/** + * \brief Get the real time of a queue_status container + * \param info queue_status container + * + * \sa snd_seq_get_queue_status() + */ +const snd_seq_real_time_t *snd_seq_queue_status_get_real_time(const snd_seq_queue_status_t *info) +{ + assert(info); + return &info->time; +} + +/** + * \brief Get the running status bits of a queue_status container + * \param info queue_status container + * \return running status bits + * + * \sa snd_seq_get_queue_status() + */ +unsigned int snd_seq_queue_status_get_status(const snd_seq_queue_status_t *info) +{ + assert(info); + return info->running; +} + + +/** + * \brief obtain the running state of the queue + * \param seq sequencer handle + * \param q queue id to query + * \param status pointer to store the current status + * \return 0 on success otherwise a negative error code + * + * Obtains the running state of the specified queue q. + */ +int snd_seq_get_queue_status(snd_seq_t *seq, int q, snd_seq_queue_status_t * status) +{ + assert(seq && status); + memset(status, 0, sizeof(snd_seq_queue_status_t)); + status->queue = q; + return seq->ops->get_queue_status(seq, status); +} + + +/** + * \brief get size of #snd_seq_queue_tempo_t + * \return size in bytes + */ +size_t snd_seq_queue_tempo_sizeof() +{ + return sizeof(snd_seq_queue_tempo_t); +} + +/** + * \brief allocate an empty #snd_seq_queue_tempo_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_queue_tempo_malloc(snd_seq_queue_tempo_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_queue_tempo_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_queue_tempo_t + * \param obj pointer to object to free + */ +void snd_seq_queue_tempo_free(snd_seq_queue_tempo_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_queue_tempo_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_queue_tempo_copy(snd_seq_queue_tempo_t *dst, const snd_seq_queue_tempo_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the queue id of a queue_status container + * \param info queue_status container + * \return queue id + * + * \sa snd_seq_get_queue_tempo() + */ +int snd_seq_queue_tempo_get_queue(const snd_seq_queue_tempo_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the tempo of a queue_status container + * \param info queue_status container + * \return tempo value + * + * \sa snd_seq_get_queue_tempo() + */ +unsigned int snd_seq_queue_tempo_get_tempo(const snd_seq_queue_tempo_t *info) +{ + assert(info); + return info->tempo; +} + +/** + * \brief Get the ppq of a queue_status container + * \param info queue_status container + * \return ppq value + * + * \sa snd_seq_get_queue_tempo() + */ +int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info) +{ + assert(info); + return info->ppq; +} + +/** + * \brief Get the timer skew value of a queue_status container + * \param info queue_status container + * \return timer skew value + * + * \sa snd_seq_get_queue_tempo() + */ +unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info) +{ + assert(info); + return info->skew_value; +} + +/** + * \brief Get the timer skew base value of a queue_status container + * \param info queue_status container + * \return timer skew base value + * + * \sa snd_seq_get_queue_tempo() + */ +unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info) +{ + assert(info); + return info->skew_base; +} + +/** + * \brief Set the tempo of a queue_status container + * \param info queue_status container + * \param tempo tempo value + * + * \sa snd_seq_get_queue_tempo() + */ +void snd_seq_queue_tempo_set_tempo(snd_seq_queue_tempo_t *info, unsigned int tempo) +{ + assert(info); + info->tempo = tempo; +} + +/** + * \brief Set the ppq of a queue_status container + * \param info queue_status container + * \param ppq ppq value + * + * \sa snd_seq_get_queue_tempo() + */ +void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq) +{ + assert(info); + info->ppq = ppq; +} + +/** + * \brief Set the timer skew value of a queue_status container + * \param info queue_status container + * \param skew timer skew value + * + * The skew of timer is calculated as skew / base. + * For example, to play with double speed, pass base * 2 as the skew value. + * + * \sa snd_seq_get_queue_tempo() + */ +void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew) +{ + assert(info); + info->skew_value = skew; +} + +/** + * \brief Set the timer skew base value of a queue_status container + * \param info queue_status container + * \param base timer skew base value + * + * \sa snd_seq_get_queue_tempo() + */ +void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base) +{ + assert(info); + info->skew_base = base; +} + +/** + * \brief obtain the current tempo of the queue + * \param seq sequencer handle + * \param q queue id to be queried + * \param tempo pointer to store the current tempo + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_set_queue_tempo() + */ +int snd_seq_get_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo) +{ + assert(seq && tempo); + memset(tempo, 0, sizeof(snd_seq_queue_tempo_t)); + tempo->queue = q; + return seq->ops->get_queue_tempo(seq, tempo); +} + +/** + * \brief set the tempo of the queue + * \param seq sequencer handle + * \param q queue id to change the tempo + * \param tempo tempo information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_queue_tempo() + */ +int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo) +{ + assert(seq && tempo); + tempo->queue = q; + return seq->ops->set_queue_tempo(seq, tempo); +} + + +/*----------------------------------------------------------------*/ + +/** + * \brief get size of #snd_seq_queue_timer_t + * \return size in bytes + */ +size_t snd_seq_queue_timer_sizeof() +{ + return sizeof(snd_seq_queue_timer_t); +} + +/** + * \brief allocate an empty #snd_seq_queue_timer_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_queue_timer_malloc(snd_seq_queue_timer_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_queue_timer_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_queue_timer_t + * \param obj pointer to object to free + */ +void snd_seq_queue_timer_free(snd_seq_queue_timer_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_queue_timer_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_queue_timer_copy(snd_seq_queue_timer_t *dst, const snd_seq_queue_timer_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the queue id of a queue_timer container + * \param info queue_timer container + * \return queue id + * + * \sa snd_seq_get_queue_timer() + */ +int snd_seq_queue_timer_get_queue(const snd_seq_queue_timer_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the timer type of a queue_timer container + * \param info queue_timer container + * \return timer type + * + * \sa snd_seq_get_queue_timer() + */ +snd_seq_queue_timer_type_t snd_seq_queue_timer_get_type(const snd_seq_queue_timer_t *info) +{ + assert(info); + return (snd_seq_queue_timer_type_t)info->type; +} + +/** + * \brief Get the timer id of a queue_timer container + * \param info queue_timer container + * \return timer id pointer + * + * \sa snd_seq_get_queue_timer() + */ +const snd_timer_id_t *snd_seq_queue_timer_get_id(const snd_seq_queue_timer_t *info) +{ + assert(info); + return &info->u.alsa.id; +} + +/** + * \brief Get the timer resolution of a queue_timer container + * \param info queue_timer container + * \return timer resolution + * + * \sa snd_seq_get_queue_timer() + */ +unsigned int snd_seq_queue_timer_get_resolution(const snd_seq_queue_timer_t *info) +{ + assert(info); + return info->u.alsa.resolution; +} + +/** + * \brief Set the timer type of a queue_timer container + * \param info queue_timer container + * \param type timer type + * + * \sa snd_seq_get_queue_timer() + */ +void snd_seq_queue_timer_set_type(snd_seq_queue_timer_t *info, snd_seq_queue_timer_type_t type) +{ + assert(info); + info->type = (int)type; +} + +/** + * \brief Set the timer id of a queue_timer container + * \param info queue_timer container + * \param id timer id pointer + * + * \sa snd_seq_get_queue_timer() + */ +void snd_seq_queue_timer_set_id(snd_seq_queue_timer_t *info, const snd_timer_id_t *id) +{ + assert(info && id); + info->u.alsa.id = *id; +} + +/** + * \brief Set the timer resolution of a queue_timer container + * \param info queue_timer container + * \param resolution timer resolution + * + * \sa snd_seq_get_queue_timer() + */ +void snd_seq_queue_timer_set_resolution(snd_seq_queue_timer_t *info, unsigned int resolution) +{ + assert(info); + info->u.alsa.resolution = resolution; +} + + +/** + * \brief obtain the queue timer information + * \param seq sequencer handle + * \param q queue id to query + * \param timer pointer to store the timer information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_set_queue_timer() + */ +int snd_seq_get_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer) +{ + assert(seq && timer); + memset(timer, 0, sizeof(snd_seq_queue_timer_t)); + timer->queue = q; + return seq->ops->get_queue_timer(seq, timer); +} + +/** + * \brief set the queue timer information + * \param seq sequencer handle + * \param q queue id to change the timer + * \param timer timer information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_queue_timer() + */ +int snd_seq_set_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer) +{ + assert(seq && timer); + timer->queue = q; + return seq->ops->set_queue_timer(seq, timer); +} + +/*----------------------------------------------------------------*/ + +#ifndef DOC_HIDDEN +/** + * \brief (DEPRECATED) create an event cell + * \return the cell pointer allocated + * + * create an event cell via malloc. the returned pointer must be released + * by the application itself via normal free() call, + * not via snd_seq_free_event(). + */ +snd_seq_event_t *snd_seq_create_event(void) +{ + return (snd_seq_event_t *) calloc(1, sizeof(snd_seq_event_t)); +} +#endif + +/** + * \brief (DEPRECATED) free an event + * + * In the former version, this function was used to + * release the event pointer which was allocated by snd_seq_event_input(). + * In the current version, the event record is not allocated, so + * you don't have to call this function any more. + */ +#ifndef DOXYGEN +int snd_seq_free_event(snd_seq_event_t *ev ATTRIBUTE_UNUSED) +#else +int snd_seq_free_event(snd_seq_event_t *ev) +#endif +{ + return 0; +} + +/** + * \brief calculates the (encoded) byte-stream size of the event + * \param ev the event + * \return the size of decoded bytes + */ +ssize_t snd_seq_event_length(snd_seq_event_t *ev) +{ + ssize_t len = sizeof(snd_seq_event_t); + assert(ev); + if (snd_seq_ev_is_variable(ev)) + len += ev->data.ext.len; + return len; +} + +/*----------------------------------------------------------------*/ + +/* + * output to sequencer + */ + +/** + * \brief output an event + * \param seq sequencer handle + * \param ev event to be output + * \return the number of remaining events or a negative error code + * + * An event is once expanded on the output buffer. + * The output buffer will be drained automatically if it becomes full. + * + * If events remain unprocessed on output buffer before drained, + * the size of total byte data on output buffer is returned. + * If the output buffer is empty, this returns zero. + * + * \sa snd_seq_event_output_direct(), snd_seq_event_output_buffer(), + * snd_seq_event_output_pending(), snd_seq_drain_output(), + * snd_seq_drop_output(), snd_seq_extract_output(), + * snd_seq_remove_events() + */ +int snd_seq_event_output(snd_seq_t *seq, snd_seq_event_t *ev) +{ + int result; + + result = snd_seq_event_output_buffer(seq, ev); + if (result == -EAGAIN) { + result = snd_seq_drain_output(seq); + if (result < 0) + return result; + return snd_seq_event_output_buffer(seq, ev); + } + return result; +} + +/** + * \brief output an event onto the lib buffer without draining buffer + * \param seq sequencer handle + * \param ev event to be output + * \return the byte size of remaining events. \c -EAGAIN if the buffer becomes full. + * + * This function doesn't drain buffer unlike snd_seq_event_output(). + * + * \sa snd_seq_event_output() + */ +int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev) +{ + int len; + assert(seq && ev); + len = snd_seq_event_length(ev); + if (len < 0) + return -EINVAL; + if ((size_t) len >= seq->obufsize) + return -EINVAL; + if ((seq->obufsize - seq->obufused) < (size_t) len) + return -EAGAIN; + memcpy(seq->obuf + seq->obufused, ev, sizeof(snd_seq_event_t)); + seq->obufused += sizeof(snd_seq_event_t); + if (snd_seq_ev_is_variable(ev)) { + memcpy(seq->obuf + seq->obufused, ev->data.ext.ptr, ev->data.ext.len); + seq->obufused += ev->data.ext.len; + } + return seq->obufused; +} + +/* + * allocate the temporary buffer + */ +static int alloc_tmpbuf(snd_seq_t *seq, size_t len) +{ + size_t size = ((len + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t)); + if (seq->tmpbuf == NULL) { + if (size > DEFAULT_TMPBUF_SIZE) + seq->tmpbufsize = size; + else + seq->tmpbufsize = DEFAULT_TMPBUF_SIZE; + seq->tmpbuf = malloc(seq->tmpbufsize * sizeof(snd_seq_event_t)); + if (seq->tmpbuf == NULL) + return -ENOMEM; + } else if (len > seq->tmpbufsize) { + seq->tmpbuf = realloc(seq->tmpbuf, size * sizeof(snd_seq_event_t)); + if (seq->tmpbuf == NULL) + return -ENOMEM; + seq->tmpbufsize = size; + } + return 0; +} + +/** + * \brief output an event directly to the sequencer NOT through output buffer + * \param seq sequencer handle + * \param ev event to be output + * \return the byte size sent to sequencer or a negative error code + * + * This function sends an event to the sequencer directly not through the + * output buffer. When the event is a variable length event, a temporary + * buffer is allocated inside alsa-lib and the data is copied there before + * actually sent. + * + * \sa snd_seq_event_output() + */ +int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev) +{ + ssize_t len; + void *buf; + + len = snd_seq_event_length(ev); + if (len < 0) + return len; + else if (len == sizeof(*ev)) { + buf = ev; + } else { + if (alloc_tmpbuf(seq, (size_t)len) < 0) + return -ENOMEM; + *seq->tmpbuf = *ev; + memcpy(seq->tmpbuf + 1, ev->data.ext.ptr, ev->data.ext.len); + buf = seq->tmpbuf; + } + return seq->ops->write(seq, buf, (size_t) len); +} + +/** + * \brief return the size of pending events on output buffer + * \param seq sequencer handle + * \return the byte size of total of pending events + * + * \sa snd_seq_event_output() + */ +int snd_seq_event_output_pending(snd_seq_t *seq) +{ + assert(seq); + return seq->obufused; +} + +/** + * \brief drain output buffer to sequencer + * \param seq sequencer handle + * \return 0 when all events are drained and sent to sequencer. + * When events still remain on the buffer, the byte size of remaining + * events are returned. On error a negative error code is returned. + * + * This function drains all pending events on the output buffer. + * The function returns immediately after the events are sent to the queues + * regardless whether the events are processed or not. + * To get synchronization with the all event processes, use + * #snd_seq_sync_output_queue() after calling this function. + * + * \sa snd_seq_event_output(), snd_seq_sync_output_queue() + */ +int snd_seq_drain_output(snd_seq_t *seq) +{ + ssize_t result, processed = 0; + assert(seq); + while (seq->obufused > 0) { + result = seq->ops->write(seq, seq->obuf, seq->obufused); + if (result < 0) { + if (result == -EAGAIN && processed) + return seq->obufused; + return result; + } + if ((size_t)result < seq->obufused) + memmove(seq->obuf, seq->obuf + result, seq->obufused - result); + seq->obufused -= result; + } + return 0; +} + +/** + * \brief extract the first event in output buffer + * \param seq sequencer handle + * \param ev_res event pointer to be extracted + * \return 0 on success otherwise a negative error code + * + * Extracts the first event in output buffer. + * If ev_res is NULL, just remove the event. + * + * \sa snd_seq_event_output() + */ +int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res) +{ + size_t len, olen; + snd_seq_event_t ev; + assert(seq); + if (ev_res) + *ev_res = NULL; + if ((olen = seq->obufused) < sizeof(snd_seq_event_t)) + return -ENOENT; + memcpy(&ev, seq->obuf, sizeof(snd_seq_event_t)); + len = snd_seq_event_length(&ev); + if (ev_res) { + /* extract the event */ + if (alloc_tmpbuf(seq, len) < 0) + return -ENOMEM; + memcpy(seq->tmpbuf, seq->obuf, len); + *ev_res = seq->tmpbuf; + } + seq->obufused = olen - len; + memmove(seq->obuf, seq->obuf + len, seq->obufused); + return 0; +} + +/*----------------------------------------------------------------*/ + +/* + * input from sequencer + */ + +/* + * read from sequencer to input buffer + */ +static ssize_t snd_seq_event_read_buffer(snd_seq_t *seq) +{ + ssize_t len; + len = (seq->ops->read)(seq, seq->ibuf, seq->ibufsize * sizeof(snd_seq_event_t)); + if (len < 0) + return len; + seq->ibuflen = len / sizeof(snd_seq_event_t); + seq->ibufptr = 0; + return seq->ibuflen; +} + +static int snd_seq_event_retrieve_buffer(snd_seq_t *seq, snd_seq_event_t **retp) +{ + size_t ncells; + snd_seq_event_t *ev; + + *retp = ev = &seq->ibuf[seq->ibufptr]; + seq->ibufptr++; + seq->ibuflen--; + if (! snd_seq_ev_is_variable(ev)) + return 1; + ncells = (ev->data.ext.len + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t); + if (seq->ibuflen < ncells) { + seq->ibuflen = 0; /* clear buffer */ + *retp = NULL; + return -EINVAL; + } + ev->data.ext.ptr = ev + 1; + seq->ibuflen -= ncells; + seq->ibufptr += ncells; + return 1; +} + +/** + * \brief retrieve an event from sequencer + * \param seq sequencer handle + * \param ev event pointer to be stored + * \return + * + * Obtains an input event from sequencer. + * The event is created via snd_seq_create_event(), and its pointer is stored on + * ev argument. + * + * This function firstly receives the event byte-stream data from sequencer + * as much as possible at once. Then it retrieves the first event record + * and store the pointer on ev. + * By calling this function sequentially, events are extracted from the input buffer. + * + * If there is no input from sequencer, function falls into sleep + * in blocking mode until an event is received, + * or returns \c -EAGAIN error in non-blocking mode. + * Occasionally, this function may return \c -ENOSPC error. + * This means that the input FIFO of sequencer overran, and some events are + * lost. + * Once this error is returned, the input FIFO is cleared automatically. + * + * Function returns the byte size of remaining events on the input buffer + * if an event is successfully received. + * Application can determine from the returned value whether to call + * input once more or not. + * + * \sa snd_seq_event_input_pending(), snd_seq_drop_input() + */ +int snd_seq_event_input(snd_seq_t *seq, snd_seq_event_t **ev) +{ + int err; + assert(seq); + *ev = NULL; + if (seq->ibuflen <= 0) { + if ((err = snd_seq_event_read_buffer(seq)) < 0) + return err; + } + + return snd_seq_event_retrieve_buffer(seq, ev); +} + +/* + * read input data from sequencer if available + */ +static int snd_seq_event_input_feed(snd_seq_t *seq, int timeout) +{ + struct pollfd pfd; + int err; + pfd.fd = seq->poll_fd; + pfd.events = POLLIN; + err = poll(&pfd, 1, timeout); + if (err < 0) { + SYSERR("poll"); + return -errno; + } + if (pfd.revents & POLLIN) + return snd_seq_event_read_buffer(seq); + return seq->ibuflen; +} + +/** + * \brief check events in input buffer + * \return the byte size of remaining input events on input buffer. + * + * If events remain on the input buffer of user-space, function returns + * the total byte size of events on it. + * If fetch_sequencer argument is non-zero, + * this function checks the presence of events on sequencer FIFO + * When events exist, they are transferred to the input buffer, + * and the number of received events are returned. + * If fetch_sequencer argument is zero and + * no events remain on the input buffer, function simply returns zero. + * + * \sa snd_seq_event_input() + */ +int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer) +{ + if (seq->ibuflen == 0 && fetch_sequencer) { + return snd_seq_event_input_feed(seq, 0); + } + return seq->ibuflen; +} + +/*----------------------------------------------------------------*/ + +/* + * clear event buffers + */ + +/** + * \brief remove all events on user-space output buffer + * \param seq sequencer handle + * + * Removes all events on user-space output buffer. + * Unlike snd_seq_drain_output(), this function doesn't remove + * events on output memory pool of sequencer. + * + * \sa snd_seq_drop_output() + */ +int snd_seq_drop_output_buffer(snd_seq_t *seq) +{ + assert(seq); + seq->obufused = 0; + return 0; +} + +/** + * \brief remove all events on user-space input FIFO + * \param seq sequencer handle + * + * \sa snd_seq_drop_input() + */ +int snd_seq_drop_input_buffer(snd_seq_t *seq) +{ + assert(seq); + seq->ibufptr = 0; + seq->ibuflen = 0; + return 0; +} + +/** + * \brief remove all events on output buffer + * \param seq sequencer handle + * + * Removes all events on both user-space output buffer and + * output memory pool on kernel. + * + * \sa snd_seq_drain_output(), snd_seq_drop_output_buffer(), snd_seq_remove_events() + */ +int snd_seq_drop_output(snd_seq_t *seq) +{ + snd_seq_remove_events_t rminfo; + assert(seq); + + memset(&rminfo, 0, sizeof(rminfo)); + rminfo.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; + + return snd_seq_remove_events(seq, &rminfo); +} + +/** + * \brief clear input buffer and and remove events in sequencer queue + * \param seq sequencer handle + * + * \sa snd_seq_drop_input_buffer(), snd_seq_remove_events() + */ +int snd_seq_drop_input(snd_seq_t *seq) +{ + snd_seq_remove_events_t rminfo; + assert(seq); + + memset(&rminfo, 0, sizeof(rminfo)); + rminfo.remove_mode = SNDRV_SEQ_REMOVE_INPUT; + + return snd_seq_remove_events(seq, &rminfo); +} + + +/** + * \brief get size of #snd_seq_remove_events_t + * \return size in bytes + */ +size_t snd_seq_remove_events_sizeof() +{ + return sizeof(snd_seq_remove_events_t); +} + +/** + * \brief allocate an empty #snd_seq_remove_events_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_remove_events_malloc(snd_seq_remove_events_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_remove_events_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_remove_events_t + * \param obj pointer to object to free + */ +void snd_seq_remove_events_free(snd_seq_remove_events_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_remove_events_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_remove_events_copy(snd_seq_remove_events_t *dst, const snd_seq_remove_events_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the removal condition bits + * \param info remove_events container + * \return removal condition bits + * + * \sa snd_seq_remove_events() + */ +unsigned int snd_seq_remove_events_get_condition(const snd_seq_remove_events_t *info) +{ + assert(info); + return info->remove_mode; +} + +/** + * \brief Get the queue as removal condition + * \param info remove_events container + * \return queue id + * + * \sa snd_seq_remove_events() + */ +int snd_seq_remove_events_get_queue(const snd_seq_remove_events_t *info) +{ + assert(info); + return info->queue; +} + +/** + * \brief Get the event timestamp as removal condition + * \param info remove_events container + * \return time stamp + * + * \sa snd_seq_remove_events() + */ +const snd_seq_timestamp_t *snd_seq_remove_events_get_time(const snd_seq_remove_events_t *info) +{ + assert(info); + return &info->time; +} + +/** + * \brief Get the event destination address as removal condition + * \param info remove_events container + * \return destination address + * + * \sa snd_seq_remove_events() + */ +const snd_seq_addr_t *snd_seq_remove_events_get_dest(const snd_seq_remove_events_t *info) +{ + assert(info); + return &info->dest; +} + +/** + * \brief Get the event channel as removal condition + * \param info remove_events container + * \return channel number + * + * \sa snd_seq_remove_events() + */ +int snd_seq_remove_events_get_channel(const snd_seq_remove_events_t *info) +{ + assert(info); + return info->channel; +} + +/** + * \brief Get the event type as removal condition + * \param info remove_events container + * \return event type + * + * \sa snd_seq_remove_events() + */ +int snd_seq_remove_events_get_event_type(const snd_seq_remove_events_t *info) +{ + assert(info); + return info->type; +} + +/** + * \brief Get the event tag id as removal condition + * \param info remove_events container + * \return tag id + * + * \sa snd_seq_remove_events() + */ +int snd_seq_remove_events_get_tag(const snd_seq_remove_events_t *info) +{ + assert(info); + return info->tag; +} + +/** + * \brief Set the removal condition bits + * \param info remove_events container + * \param flags removal condition bits + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_condition(snd_seq_remove_events_t *info, unsigned int flags) +{ + assert(info); + info->remove_mode = flags; +} + +/** + * \brief Set the queue as removal condition + * \param info remove_events container + * \param queue queue id + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_queue(snd_seq_remove_events_t *info, int queue) +{ + assert(info); + info->queue = queue; +} + +/** + * \brief Set the timestamp as removal condition + * \param info remove_events container + * \param time timestamp pointer + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_time(snd_seq_remove_events_t *info, const snd_seq_timestamp_t *time) +{ + assert(info); + info->time = *time; +} + +/** + * \brief Set the destination address as removal condition + * \param info remove_events container + * \param addr destination address + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_dest(snd_seq_remove_events_t *info, const snd_seq_addr_t *addr) +{ + assert(info); + info->dest = *addr; +} + +/** + * \brief Set the channel as removal condition + * \param info remove_events container + * \param channel channel number + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_channel(snd_seq_remove_events_t *info, int channel) +{ + assert(info); + info->channel = channel; +} + +/** + * \brief Set the event type as removal condition + * \param info remove_events container + * \param type event type + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_event_type(snd_seq_remove_events_t *info, int type) +{ + assert(info); + info->type = type; +} + +/** + * \brief Set the event tag as removal condition + * \param info remove_events container + * \param tag tag id + * + * \sa snd_seq_remove_events() + */ +void snd_seq_remove_events_set_tag(snd_seq_remove_events_t *info, int tag) +{ + assert(info); + info->tag = tag; +} + + +/* compare timestamp between events */ +/* return 1 if a >= b; otherwise return 0 */ +static inline int snd_seq_compare_tick_time(snd_seq_tick_time_t *a, snd_seq_tick_time_t *b) +{ + /* compare ticks */ + return (*a >= *b); +} + +static inline int snd_seq_compare_real_time(snd_seq_real_time_t *a, snd_seq_real_time_t *b) +{ + /* compare real time */ + if (a->tv_sec > b->tv_sec) + return 1; + if ((a->tv_sec == b->tv_sec) && (a->tv_nsec >= b->tv_nsec)) + return 1; + return 0; +} + +/* Routine to match events to be removed */ +static int remove_match(snd_seq_remove_events_t *info, snd_seq_event_t *ev) +{ + int res; + + if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) { + if (ev->dest.client != info->dest.client || + ev->dest.port != info->dest.port) + return 0; + } + if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) { + if (! snd_seq_ev_is_channel_type(ev)) + return 0; + /* data.note.channel and data.control.channel are identical */ + if (ev->data.note.channel != info->channel) + return 0; + } + if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) { + if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) + res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick); + else + res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); + if (!res) + return 0; + } + if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) { + if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) + res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick); + else + res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); + if (res) + return 0; + } + if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) { + if (ev->type != info->type) + return 0; + } + if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) { + /* Do not remove off events */ + switch (ev->type) { + case SND_SEQ_EVENT_NOTEOFF: + /* case SND_SEQ_EVENT_SAMPLE_STOP: */ + return 0; + default: + break; + } + } + if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) { + if (info->tag != ev->tag) + return 0; + } + + return 1; +} + +/** + * \brief remove events on input/output buffers and pools + * \param seq sequencer handle + * \param rmp remove event container + * + * Removes matching events with the given condition from input/output buffers + * and pools. + * The removal condition is specified in \a rmp argument. + * + * \sa snd_seq_event_output(), snd_seq_drop_output(), snd_seq_reset_pool_output() + */ +int snd_seq_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp) +{ + if (rmp->remove_mode & SNDRV_SEQ_REMOVE_INPUT) { + /* + * First deal with any events that are still buffered + * in the library. + */ + snd_seq_drop_input_buffer(seq); + } + + if (rmp->remove_mode & SNDRV_SEQ_REMOVE_OUTPUT) { + /* + * First deal with any events that are still buffered + * in the library. + */ + if (! (rmp->remove_mode & ~(SNDRV_SEQ_REMOVE_INPUT|SNDRV_SEQ_REMOVE_OUTPUT))) { + /* The simple case - remove all */ + snd_seq_drop_output_buffer(seq); + } else { + char *ep; + size_t len; + snd_seq_event_t *ev; + + ep = seq->obuf; + while (ep - seq->obuf < (ssize_t)seq->obufused) { + + ev = (snd_seq_event_t *)ep; + len = snd_seq_event_length(ev); + + if (remove_match(rmp, ev)) { + /* Remove event */ + seq->obufused -= len; + memmove(ep, ep + len, seq->obufused - (ep - seq->obuf)); + } else { + ep += len; + } + } + } + } + + return seq->ops->remove_events(seq, rmp); +} + +/*----------------------------------------------------------------*/ + +/* + * client memory pool + */ + +/** + * \brief get size of #snd_seq_client_pool_t + * \return size in bytes + */ +size_t snd_seq_client_pool_sizeof() +{ + return sizeof(snd_seq_client_pool_t); +} + +/** + * \brief allocate an empty #snd_seq_client_pool_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_seq_client_pool_malloc(snd_seq_client_pool_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_seq_client_pool_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_client_pool_t + * \param obj pointer to object to free + */ +void snd_seq_client_pool_free(snd_seq_client_pool_t *obj) +{ + free(obj); +} + +/** + * \brief copy one #snd_seq_client_pool_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_seq_client_pool_copy(snd_seq_client_pool_t *dst, const snd_seq_client_pool_t *src) +{ + assert(dst && src); + *dst = *src; +} + + +/** + * \brief Get the client id of a queue_info container + * \param info client_pool container + * \return client id + */ +int snd_seq_client_pool_get_client(const snd_seq_client_pool_t *info) +{ + assert(info); + return info->client; +} + +/** + * \brief Get the output pool size of a queue_info container + * \param info client_pool container + * \return output pool size + */ +size_t snd_seq_client_pool_get_output_pool(const snd_seq_client_pool_t *info) +{ + assert(info); + return info->output_pool; +} + +/** + * \brief Get the input pool size of a queue_info container + * \param info client_pool container + * \return input pool size + */ +size_t snd_seq_client_pool_get_input_pool(const snd_seq_client_pool_t *info) +{ + assert(info); + return info->input_pool; +} + +/** + * \brief Get the output room size of a queue_info container + * \param info client_pool container + * \return output room size + */ +size_t snd_seq_client_pool_get_output_room(const snd_seq_client_pool_t *info) +{ + assert(info); + return info->output_room; +} + +/** + * \brief Get the available size on output pool of a queue_info container + * \param info client_pool container + * \return available output size + */ +size_t snd_seq_client_pool_get_output_free(const snd_seq_client_pool_t *info) +{ + assert(info); + return info->output_free; +} + +/** + * \brief Get the available size on input pool of a queue_info container + * \param info client_pool container + * \return available input size + */ +size_t snd_seq_client_pool_get_input_free(const snd_seq_client_pool_t *info) +{ + assert(info); + return info->input_free; +} + +/** + * \brief Set the output pool size of a queue_info container + * \param info client_pool container + * \param size output pool size + */ +void snd_seq_client_pool_set_output_pool(snd_seq_client_pool_t *info, size_t size) +{ + assert(info); + info->output_pool = size; +} + +/** + * \brief Set the input pool size of a queue_info container + * \param info client_pool container + * \param size input pool size + */ +void snd_seq_client_pool_set_input_pool(snd_seq_client_pool_t *info, size_t size) +{ + assert(info); + info->input_pool = size; +} + +/** + * \brief Set the output room size of a queue_info container + * \param info client_pool container + * \param size output room size + */ +void snd_seq_client_pool_set_output_room(snd_seq_client_pool_t *info, size_t size) +{ + assert(info); + info->output_room = size; +} + + +/** + * \brief obtain the pool information of the current client + * \param seq sequencer handle + * \param info information to be stored + */ +int snd_seq_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info) +{ + assert(seq && info); + info->client = seq->client; + return seq->ops->get_client_pool(seq, info); +} + +/** + * \brief set the pool information + * \param seq sequencer handle + * \param info information to update + * + * Sets the pool information of the current client. + * The client field in \a info is replaced automatically with the current id. + */ +int snd_seq_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info) +{ + assert(seq && info); + info->client = seq->client; + return seq->ops->set_client_pool(seq, info); +} + +/*----------------------------------------------------------------*/ + +/* + * misc. + */ + +/** + * \brief set a bit flag + */ +void snd_seq_set_bit(int nr, void *array) +{ + ((unsigned int *)array)[nr >> 5] |= 1UL << (nr & 31); +} + +/** + * \brief unset a bit flag + */ +void snd_seq_unset_bit(int nr, void *array) +{ + ((unsigned int *)array)[nr >> 5] &= ~(1UL << (nr & 31)); +} + +/** + * \brief change a bit flag + */ +int snd_seq_change_bit(int nr, void *array) +{ + int result; + + result = ((((unsigned int *)array)[nr >> 5]) & (1UL << (nr & 31))) ? 1 : 0; + ((unsigned int *)array)[nr >> 5] ^= 1UL << (nr & 31); + return result; +} + +/** + * \brief get a bit flag state + */ +int snd_seq_get_bit(int nr, void *array) +{ + return ((((unsigned int *)array)[nr >> 5]) & (1UL << (nr & 31))) ? 1 : 0; +} diff --git a/src/seq/seq_event.c b/src/seq/seq_event.c new file mode 100644 index 0000000..0571b21 --- /dev/null +++ b/src/seq/seq_event.c @@ -0,0 +1,49 @@ +/** + * \file seq/seq_event.c + * \brief Sequencer Event Types + * \author Takashi Iwai + * \date 2001 + */ + +#include "local.h" + +#ifndef DOC_HIDDEN +#define FIXED_EV(x) (_SND_SEQ_TYPE(SND_SEQ_EVFLG_FIXED) | _SND_SEQ_TYPE(x)) +#endif + +/** Event types conversion array */ +const unsigned int snd_seq_event_types[256] = { + [SND_SEQ_EVENT_SYSTEM ... SND_SEQ_EVENT_RESULT] + = FIXED_EV(SND_SEQ_EVFLG_RESULT), + [SND_SEQ_EVENT_NOTE] + = FIXED_EV(SND_SEQ_EVFLG_NOTE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_NOTE_TWOARG), + [SND_SEQ_EVENT_NOTEON ... SND_SEQ_EVENT_KEYPRESS] + = FIXED_EV(SND_SEQ_EVFLG_NOTE), + [SND_SEQ_EVENT_CONTROLLER ... SND_SEQ_EVENT_REGPARAM] + = FIXED_EV(SND_SEQ_EVFLG_CONTROL), + [SND_SEQ_EVENT_START ... SND_SEQ_EVENT_STOP] + = FIXED_EV(SND_SEQ_EVFLG_QUEUE), + [SND_SEQ_EVENT_SETPOS_TICK] + = FIXED_EV(SND_SEQ_EVFLG_QUEUE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_QUEUE_TICK), + [SND_SEQ_EVENT_SETPOS_TIME] + = FIXED_EV(SND_SEQ_EVFLG_QUEUE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_QUEUE_TIME), + [SND_SEQ_EVENT_TEMPO ... SND_SEQ_EVENT_SYNC_POS] + = FIXED_EV(SND_SEQ_EVFLG_QUEUE) | _SND_SEQ_TYPE_OPT(SND_SEQ_EVFLG_QUEUE_VALUE), + [SND_SEQ_EVENT_TUNE_REQUEST ... SND_SEQ_EVENT_SENSING] + = FIXED_EV(SND_SEQ_EVFLG_NONE), + [SND_SEQ_EVENT_ECHO ... SND_SEQ_EVENT_OSS] + = FIXED_EV(SND_SEQ_EVFLG_RAW) | FIXED_EV(SND_SEQ_EVFLG_SYSTEM), + [SND_SEQ_EVENT_CLIENT_START ... SND_SEQ_EVENT_PORT_CHANGE] + = FIXED_EV(SND_SEQ_EVFLG_MESSAGE), + [SND_SEQ_EVENT_PORT_SUBSCRIBED ... SND_SEQ_EVENT_PORT_UNSUBSCRIBED] + = FIXED_EV(SND_SEQ_EVFLG_CONNECTION), + [SND_SEQ_EVENT_USR0 ... SND_SEQ_EVENT_USR9] + = FIXED_EV(SND_SEQ_EVFLG_RAW) | FIXED_EV(SND_SEQ_EVFLG_USERS), + [SND_SEQ_EVENT_SYSEX ... SND_SEQ_EVENT_BOUNCE] + = _SND_SEQ_TYPE(SND_SEQ_EVFLG_VARIABLE), + [SND_SEQ_EVENT_USR_VAR0 ... SND_SEQ_EVENT_USR_VAR4] + = _SND_SEQ_TYPE(SND_SEQ_EVFLG_VARIABLE) | _SND_SEQ_TYPE(SND_SEQ_EVFLG_USERS), + [SND_SEQ_EVENT_NONE] + = FIXED_EV(SND_SEQ_EVFLG_NONE), +}; + diff --git a/src/seq/seq_hw.c b/src/seq/seq_hw.c new file mode 100644 index 0000000..5bb26f3 --- /dev/null +++ b/src/seq/seq_hw.c @@ -0,0 +1,557 @@ +/* + * Sequencer Interface - main file + * Copyright (c) 2000 by Jaroslav Kysela + * Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include "seq_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_seq_hw = ""; +#endif + +#ifndef DOC_HIDDEN +#define SNDRV_FILE_SEQ ALSA_DEVICE_DIRECTORY "seq" +#define SNDRV_FILE_ALOADSEQ ALOAD_DEVICE_DIRECTORY "aloadSEQ" +#define SNDRV_SEQ_VERSION_MAX SNDRV_PROTOCOL_VERSION(1, 0, 1) + +typedef struct { + int fd; +} snd_seq_hw_t; +#endif /* DOC_HIDDEN */ + +static int snd_seq_hw_close(snd_seq_t *seq) +{ + snd_seq_hw_t *hw = seq->private_data; + int err = 0; + + if (close(hw->fd)) { + err = -errno; + SYSERR("close failed\n"); + } + free(hw); + return err; +} + +static int snd_seq_hw_nonblock(snd_seq_t *seq, int nonblock) +{ + snd_seq_hw_t *hw = seq->private_data; + long flags; + + if ((flags = fcntl(hw->fd, F_GETFL)) < 0) { + SYSERR("F_GETFL failed"); + return -errno; + } + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(hw->fd, F_SETFL, flags) < 0) { + SYSERR("F_SETFL for O_NONBLOCK failed"); + return -errno; + } + return 0; +} + +static int snd_seq_hw_client_id(snd_seq_t *seq) +{ + snd_seq_hw_t *hw = seq->private_data; + int client; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CLIENT_ID, &client) < 0) { + SYSERR("SNDRV_SEQ_IOCTL_CLIENT_ID failed"); + return -errno; + } + return client; +} + +static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SYSTEM_INFO, info) < 0) { + SYSERR("SNDRV_SEQ_IOCTL_SYSTEM_INFO failed"); + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_CLIENT_INFO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_INFO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_create_port(snd_seq_t *seq, snd_seq_port_info_t * port) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CREATE_PORT, port) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_CREATE_PORT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_DELETE_PORT, port) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_DELETE_PORT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_port_info(snd_seq_t *seq, snd_seq_port_info_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_PORT_INFO, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_PORT_INFO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_port_info(snd_seq_t *seq, snd_seq_port_info_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_PORT_INFO, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_PORT_INFO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subscribe_t * subs) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_SUBS, subs) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_SUBS failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_queue_status(snd_seq_t *seq, snd_seq_queue_status_t * status) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CREATE_QUEUE, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_CREATE_QUEUE failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_delete_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_DELETE_QUEUE, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_DELETE_QUEUE failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_INFO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_INFO failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_named_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE failed");*/ + return -errno; + } + return 0; +} + +static ssize_t snd_seq_hw_write(snd_seq_t *seq, void *buf, size_t len) +{ + snd_seq_hw_t *hw = seq->private_data; + ssize_t result = write(hw->fd, buf, len); + if (result < 0) + return -errno; + return result; +} + +static ssize_t snd_seq_hw_read(snd_seq_t *seq, void *buf, size_t len) +{ + snd_seq_hw_t *hw = seq->private_data; + ssize_t result = read(hw->fd, buf, len); + if (result < 0) + return -errno; + return result; +} + +static int snd_seq_hw_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_REMOVE_EVENTS failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_GET_CLIENT_POOL failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_POOL failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT failed");*/ + return -errno; + } + return 0; +} + +static int snd_seq_hw_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info) +{ + snd_seq_hw_t *hw = seq->private_data; + if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0) { + /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT failed");*/ + return -errno; + } + return 0; +} + +static const snd_seq_ops_t snd_seq_hw_ops = { + .close = snd_seq_hw_close, + .nonblock = snd_seq_hw_nonblock, + .system_info = snd_seq_hw_system_info, + .get_client_info = snd_seq_hw_get_client_info, + .set_client_info = snd_seq_hw_set_client_info, + .create_port = snd_seq_hw_create_port, + .delete_port = snd_seq_hw_delete_port, + .get_port_info = snd_seq_hw_get_port_info, + .set_port_info = snd_seq_hw_set_port_info, + .get_port_subscription = snd_seq_hw_get_port_subscription, + .subscribe_port = snd_seq_hw_subscribe_port, + .unsubscribe_port = snd_seq_hw_unsubscribe_port, + .query_port_subscribers = snd_seq_hw_query_port_subscribers, + .get_queue_status = snd_seq_hw_get_queue_status, + .get_queue_tempo = snd_seq_hw_get_queue_tempo, + .set_queue_tempo = snd_seq_hw_set_queue_tempo, + .get_queue_timer = snd_seq_hw_get_queue_timer, + .set_queue_timer = snd_seq_hw_set_queue_timer, + .get_queue_client = snd_seq_hw_get_queue_client, + .set_queue_client = snd_seq_hw_set_queue_client, + .create_queue = snd_seq_hw_create_queue, + .delete_queue = snd_seq_hw_delete_queue, + .get_queue_info = snd_seq_hw_get_queue_info, + .set_queue_info = snd_seq_hw_set_queue_info, + .get_named_queue = snd_seq_hw_get_named_queue, + .write = snd_seq_hw_write, + .read = snd_seq_hw_read, + .remove_events = snd_seq_hw_remove_events, + .get_client_pool = snd_seq_hw_get_client_pool, + .set_client_pool = snd_seq_hw_set_client_pool, + .query_next_client = snd_seq_hw_query_next_client, + .query_next_port = snd_seq_hw_query_next_port, +}; + +int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode) +{ + int fd, ver, client, fmode, ret; + const char *filename; + snd_seq_t *seq; + snd_seq_hw_t *hw; + + *handle = NULL; + + switch (streams) { + case SND_SEQ_OPEN_OUTPUT: + fmode = O_WRONLY; + break; + case SND_SEQ_OPEN_INPUT: + fmode = O_RDONLY; + break; + case SND_SEQ_OPEN_DUPLEX: + fmode = O_RDWR; + break; + default: + assert(0); + return -EINVAL; + } + + if (mode & SND_SEQ_NONBLOCK) + fmode |= O_NONBLOCK; + + filename = SNDRV_FILE_SEQ; + fd = snd_open_device(filename, fmode); +#ifdef SUPPORT_ALOAD + if (fd < 0) { + fd = snd_open_device(SNDRV_FILE_ALOADSEQ, fmode); + if (fd >= 0) + close(fd); + fd = snd_open_device(filename, fmode); + } +#endif + if (fd < 0) { + SYSERR("open %s failed", filename); + return -errno; + } + if (ioctl(fd, SNDRV_SEQ_IOCTL_PVERSION, &ver) < 0) { + SYSERR("SNDRV_SEQ_IOCTL_PVERSION failed"); + ret = -errno; + close(fd); + return ret; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_SEQ_VERSION_MAX)) { + close(fd); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } + hw = calloc(1, sizeof(snd_seq_hw_t)); + if (hw == NULL) { + close(fd); + return -ENOMEM; + } + + seq = calloc(1, sizeof(snd_seq_t)); + if (seq == NULL) { + free(hw); + close(fd); + return -ENOMEM; + } + hw->fd = fd; + if (streams & SND_SEQ_OPEN_OUTPUT) { + seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE); + if (!seq->obuf) { + free(hw); + free(seq); + close(fd); + return -ENOMEM; + } + } + if (streams & SND_SEQ_OPEN_INPUT) { + seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE); + if (!seq->ibuf) { + free(seq->obuf); + free(hw); + free(seq); + close(fd); + return -ENOMEM; + } + } + if (name) + seq->name = strdup(name); + seq->type = SND_SEQ_TYPE_HW; + seq->streams = streams; + seq->mode = mode; + seq->tmpbuf = NULL; + seq->tmpbufsize = 0; + seq->poll_fd = fd; + seq->ops = &snd_seq_hw_ops; + seq->private_data = hw; + client = snd_seq_hw_client_id(seq); + if (client < 0) { + snd_seq_close(seq); + return client; + } else + seq->client = client; + +#ifdef SNDRV_SEQ_IOCTL_RUNNING_MODE + { + struct sndrv_seq_running_info run_mode; + /* check running mode */ + memset(&run_mode, 0, sizeof(run_mode)); + run_mode.client = client; +#ifdef SNDRV_BIG_ENDIAN + run_mode.big_endian = 1; +#else + run_mode.big_endian = 0; +#endif + run_mode.cpu_mode = sizeof(long); + ioctl(fd, SNDRV_SEQ_IOCTL_RUNNING_MODE, &run_mode); + } +#endif + + *handle = seq; + return 0; +} + +int _snd_seq_hw_open(snd_seq_t **handlep, char *name, + snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, + int streams, int mode) +{ + snd_config_iterator_t i, next; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + return -EINVAL; + } + return snd_seq_hw_open(handlep, name, streams, mode); +} +SND_DLSYM_BUILD_VERSION(_snd_seq_hw_open, SND_SEQ_DLSYM_VERSION); diff --git a/src/seq/seq_local.h b/src/seq/seq_local.h new file mode 100644 index 0000000..f0a0acd --- /dev/null +++ b/src/seq/seq_local.h @@ -0,0 +1,97 @@ +/* + * Sequencer Interface - definition of sequencer event handler + * Copyright (c) 2000 by Jaroslav Kysela + * Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __SEQ_LOCAL_H +#define __SEQ_LOCAL_H + +#include +#include +#include +#include "local.h" + +#define SND_SEQ_OBUF_SIZE (16*1024) /* default size */ +#define SND_SEQ_IBUF_SIZE 500 /* in event_size aligned */ +#define DEFAULT_TMPBUF_SIZE 20 + +typedef struct sndrv_seq_queue_client snd_seq_queue_client_t; + + +typedef struct { + int (*close)(snd_seq_t *seq); + int (*nonblock)(snd_seq_t *seq, int nonblock); + int (*system_info)(snd_seq_t *seq, snd_seq_system_info_t * info); + int (*get_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info); + int (*set_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info); + int (*create_port)(snd_seq_t *seq, snd_seq_port_info_t * port); + int (*delete_port)(snd_seq_t *seq, snd_seq_port_info_t * port); + int (*get_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info); + int (*set_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info); + int (*get_port_subscription)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub); + int (*subscribe_port)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub); + int (*unsubscribe_port)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub); + int (*query_port_subscribers)(snd_seq_t *seq, snd_seq_query_subscribe_t * subs); + int (*get_queue_status)(snd_seq_t *seq, snd_seq_queue_status_t * status); + int (*get_queue_tempo)(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo); + int (*set_queue_tempo)(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo); + int (*get_queue_timer)(snd_seq_t *seq, snd_seq_queue_timer_t * timer); + int (*set_queue_timer)(snd_seq_t *seq, snd_seq_queue_timer_t * timer); + int (*get_queue_client)(snd_seq_t *seq, snd_seq_queue_client_t * client); + int (*set_queue_client)(snd_seq_t *seq, snd_seq_queue_client_t * client); + int (*create_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info); + int (*delete_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info); + int (*get_queue_info)(snd_seq_t *seq, snd_seq_queue_info_t *info); + int (*set_queue_info)(snd_seq_t *seq, snd_seq_queue_info_t *info); + int (*get_named_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info); + ssize_t (*write)(snd_seq_t *seq, void *buf, size_t len); + ssize_t (*read)(snd_seq_t *seq, void *buf, size_t len); + int (*remove_events)(snd_seq_t *seq, snd_seq_remove_events_t *rmp); + int (*get_client_pool)(snd_seq_t *seq, snd_seq_client_pool_t *info); + int (*set_client_pool)(snd_seq_t *seq, snd_seq_client_pool_t *info); + int (*query_next_client)(snd_seq_t *seq, snd_seq_client_info_t *info); + int (*query_next_port)(snd_seq_t *seq, snd_seq_port_info_t *info); +} snd_seq_ops_t; + +struct _snd_seq { + char *name; + snd_seq_type_t type; + int streams; + int mode; + int poll_fd; + void *dl_handle; + const snd_seq_ops_t *ops; + void *private_data; + int client; /* client number */ + /* buffers */ + char *obuf; /* output buffer */ + size_t obufsize; /* output buffer size */ + size_t obufused; /* output buffer used size */ + snd_seq_event_t *ibuf; /* input buffer */ + size_t ibufptr; /* current pointer of input buffer */ + size_t ibuflen; /* queued length */ + size_t ibufsize; /* input buffer size */ + snd_seq_event_t *tmpbuf; /* temporary event for extracted event */ + size_t tmpbufsize; /* size of errbuf */ +}; + +int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode); + +#endif diff --git a/src/seq/seq_midi_event.c b/src/seq/seq_midi_event.c new file mode 100644 index 0000000..ddaac5a --- /dev/null +++ b/src/seq/seq_midi_event.c @@ -0,0 +1,727 @@ +/** + * \file seq/seq_midi_event.c + * \brief MIDI byte <-> sequencer event coder + * \author Takashi Iwai + * \author Jaroslav Kysela + * \date 2000-2001 + */ + +/* + * MIDI byte <-> sequencer event coder + * + * Copyright (C) 1998,99,2000 Takashi Iwai , + * Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "local.h" + +#ifndef DOC_HIDDEN + +/* midi status */ +struct snd_midi_event { + size_t qlen; /* queue length */ + size_t read; /* chars read */ + int type; /* current event type */ + unsigned char lastcmd; + unsigned char nostat; + size_t bufsize; + unsigned char *buf; /* input buffer */ +}; + + +/* event type, index into status_event[] */ +/* from 0 to 6 are normal commands (note off, on, etc.) for 0x8?-0xe? */ +#define ST_INVALID 7 +#define ST_SPECIAL 8 +#define ST_SYSEX ST_SPECIAL +/* from 8 to 15 are events for 0xf0-0xf7 */ + + +/* status event types */ +typedef void (*event_encode_t)(snd_midi_event_t *dev, snd_seq_event_t *ev); +typedef void (*event_decode_t)(const snd_seq_event_t *ev, unsigned char *buf); + +#endif /* DOC_HIDDEN */ + +/* + * prototypes + */ +static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static void note_decode(const snd_seq_event_t *ev, unsigned char *buf); +static void one_param_decode(const snd_seq_event_t *ev, unsigned char *buf); +static void pitchbend_decode(const snd_seq_event_t *ev, unsigned char *buf); +static void two_param_decode(const snd_seq_event_t *ev, unsigned char *buf); +static void songpos_decode(const snd_seq_event_t *ev, unsigned char *buf); + +/* + * event list + */ +#ifndef DOC_HIDDEN +static const struct status_event_list_t { + int event; + int qlen; + event_encode_t encode; + event_decode_t decode; +} status_event[] = { + /* 0x80 - 0xef */ + {SND_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, + {SND_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, + {SND_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, + {SND_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, + {SND_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, + {SND_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, + {SND_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, + /* invalid */ + {SND_SEQ_EVENT_NONE, -1, NULL, NULL}, + /* 0xf0 - 0xff */ + {SND_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ + {SND_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ + {SND_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ + {SND_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ + {SND_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf4 */ + {SND_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf5 */ + {SND_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ + {SND_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf7 */ + {SND_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ + {SND_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf9 */ + {SND_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ + {SND_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ + {SND_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ + {SND_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xfd */ + {SND_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ + {SND_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ +}; + +static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, const snd_seq_event_t *ev); +static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, const snd_seq_event_t *ev); + +static const struct extra_event_list_t { + int event; + int (*decode)(snd_midi_event_t *dev, unsigned char *buf, int len, const snd_seq_event_t *ev); +} extra_event[] = { + {SND_SEQ_EVENT_CONTROL14, extra_decode_ctrl14}, + {SND_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn}, + {SND_SEQ_EVENT_REGPARAM, extra_decode_xrpn}, +}; + +#define numberof(ary) (sizeof(ary)/sizeof(ary[0])) +#endif /* DOC_HIDDEN */ + +/** + * \brief Creates a MIDI event parser. + * \param[in] bufsize Size of the buffer used for encoding; this should be + * large enough to hold the largest MIDI message to be + * encoded. + * \param[out] rdev The new MIDI event parser. + * \return Zero on success, otherwise a negative error code. + * + * This function creates and initializes a MIDI parser object that can be used + * to convert a MIDI byte stream to sequencer events (encoding) and/or to + * convert sequencer events to a MIDI byte stream (decoding). + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + * + * \par Conforming to: + * LSB 3.2 + */ +int snd_midi_event_new(size_t bufsize, snd_midi_event_t **rdev) +{ + snd_midi_event_t *dev; + + *rdev = NULL; + dev = (snd_midi_event_t *)calloc(1, sizeof(snd_midi_event_t)); + if (dev == NULL) + return -ENOMEM; + if (bufsize > 0) { + dev->buf = malloc(bufsize); + if (dev->buf == NULL) { + free(dev); + return -ENOMEM; + } + } + dev->bufsize = bufsize; + dev->lastcmd = 0xff; + dev->type = ST_INVALID; + *rdev = dev; + return 0; +} + +/** + * \brief Frees a MIDI event parser. + * \param dev MIDI event parser. + * + * Frees a MIDI event parser. + * + * \par Conforming to: + * LSB 3.2 + */ +void snd_midi_event_free(snd_midi_event_t *dev) +{ + if (dev != NULL) { + free(dev->buf); + free(dev); + } +} + +/** + * \brief Enables/disables MIDI command merging. + * \param dev MIDI event parser. + * \param on 0 to enable MIDI command merging, + * 1 to always write the command byte. + * + * This function enables or disables MIDI command merging (running status). + * + * When MIDI command merging is not disabled, #snd_midi_event_decode is allowed + * to omit any status byte that is identical to the previous status byte. + */ +void snd_midi_event_no_status(snd_midi_event_t *dev, int on) +{ + dev->nostat = on ? 1 : 0; +} + +/* + * initialize record + */ +inline static void reset_encode(snd_midi_event_t *dev) +{ + dev->read = 0; + dev->qlen = 0; + dev->type = ST_INVALID; +} + +/** + * \brief Resets MIDI encode parser. + * \param dev MIDI event parser. + * + * This function resets the MIDI encoder of the parser \a dev. + * Any partially encoded MIDI message is dropped, + * and running status state is cleared. + * + * \par Conforming to: + * LSB 3.2 + */ +void snd_midi_event_reset_encode(snd_midi_event_t *dev) +{ + reset_encode(dev); +} + +/** + * \brief Resets MIDI decode parser. + * \param dev MIDI event parser. + * + * This function resets the MIDI decoder of the parser \a dev. + * The next decoded message does not use running status from before the call to + * \a snd_midi_event_reset_decode. + * + * \par Conforming to: + * LSB 3.2 + */ +void snd_midi_event_reset_decode(snd_midi_event_t *dev) +{ + dev->lastcmd = 0xff; +} + +/** + * \brief Resets MIDI encode/decode parsers. + * \param dev MIDI event parser. + * + * This function resets both encoder and decoder of the MIDI event parser. + * \sa snd_midi_event_reset_encode, snd_midi_event_reset_decode + * + * \par Conforming to: + * LSB 3.2 + */ +void snd_midi_event_init(snd_midi_event_t *dev) +{ + snd_midi_event_reset_encode(dev); + snd_midi_event_reset_decode(dev); +} + +/** + * \brief Resizes the MIDI message encoding buffer. + * \param dev MIDI event parser. + * \param bufsize The new buffer size. + * \return Zero on success, otherwise a negative error code. + * + * This function resizes the buffer that is used to hold partially encoded MIDI + * messages. + * + * If there is a partially encoded message in the buffer, it is dropped. + * + * \par Errors: + *
+ *
-ENOMEM
Out of memory. + * + * \sa snd_midi_event_encode, snd_midi_event_reset_encode + */ +int snd_midi_event_resize_buffer(snd_midi_event_t *dev, size_t bufsize) +{ + unsigned char *new_buf, *old_buf; + + if (bufsize == dev->bufsize) + return 0; + new_buf = malloc(bufsize); + if (new_buf == NULL) + return -ENOMEM; + old_buf = dev->buf; + dev->buf = new_buf; + dev->bufsize = bufsize; + reset_encode(dev); + free(old_buf); + return 0; +} + +/** + * \brief Encodes bytes to sequencer event. + * \param[in] dev MIDI event parser. + * \param[in] buf Buffer containing bytes of a raw MIDI stream. + * \param[in] count Number of bytes in \a buf. + * \param[out] ev Sequencer event. + * \return The number of bytes consumed, or a negative error code. + * + * This function tries to use up to \a count bytes from the beginning of the + * buffer to encode a sequencer event. If a complete MIDI message has been + * encoded, the sequencer event is written to \a ev; otherwise, \a ev->type is + * set to #SND_SEQ_EVENT_NONE, and further bytes are required to complete + * a message. + * + * The buffer in \a dev is used to hold any bytes of a not-yet-complete MIDI + * message. If a System Exclusive message is larger than the buffer, the + * message is split into multiple parts, and a sequencer event is returned at + * the end of each part. + * + * Any bytes that are not part of a valid MIDI message are silently ignored, + * i.e., they are consumed without signaling an error. + * + * When this function returns a system exclusive sequencer event (\a ev->type + * is #SND_SEQ_EVENT_SYSEX), the data pointer (\a ev->data.ext.ptr) points into + * the MIDI event parser's buffer. Therefore, the sequencer event can only be + * used as long as that buffer remains valid, i.e., until the next call to + * #snd_midi_event_encode, #snd_midi_event_encode_byte, + * #snd_midi_event_resize_buffer, #snd_midi_event_init, + * #snd_midi_event_reset_encode, or #snd_midi_event_free for that MIDI event + * parser. + * + * This function can generate any sequencer event that corresponds to a MIDI + * message, i.e.: + * - #SND_SEQ_EVENT_NOTEOFF + * - #SND_SEQ_EVENT_NOTEON + * - #SND_SEQ_EVENT_KEYPRESS + * - #SND_SEQ_EVENT_CONTROLLER + * - #SND_SEQ_EVENT_PGMCHANGE + * - #SND_SEQ_EVENT_CHANPRESS + * - #SND_SEQ_EVENT_PITCHBEND + * - #SND_SEQ_EVENT_SYSEX + * - #SND_SEQ_EVENT_QFRAME + * - #SND_SEQ_EVENT_SONGPOS + * - #SND_SEQ_EVENT_SONGSEL + * - #SND_SEQ_EVENT_TUNE_REQUEST + * - #SND_SEQ_EVENT_CLOCK + * - #SND_SEQ_EVENT_START + * - #SND_SEQ_EVENT_CONTINUE + * - #SND_SEQ_EVENT_STOP + * - #SND_SEQ_EVENT_SENSING + * - #SND_SEQ_EVENT_RESET + * . + * Some implementations may also be able to generate the following events + * for a sequence of controller change messages: + * - #SND_SEQ_EVENT_CONTROL14 + * - #SND_SEQ_EVENT_NONREGPARAM + * - #SND_SEQ_EVENT_REGPARAM + * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_midi_event_new, snd_midi_event_reset_encode, snd_midi_event_encode_byte + */ +long snd_midi_event_encode(snd_midi_event_t *dev, const unsigned char *buf, long count, snd_seq_event_t *ev) +{ + long result = 0; + int rc; + + ev->type = SND_SEQ_EVENT_NONE; + + while (count-- > 0) { + rc = snd_midi_event_encode_byte(dev, *buf++, ev); + result++; + if (rc < 0) + return rc; + else if (rc > 0) + return result; + } + + return result; +} + +/** + * \brief Encodes byte to sequencer event. + * \param[in] dev MIDI event parser. + * \param[in] c A byte of a raw MIDI stream. + * \param[out] ev Sequencer event. + * \return 1 if a sequenver event has been completed, 0 if more bytes are + * required to complete an event, or a negative error code. + * + * This function tries to use the byte \a c to encode a sequencer event. If + * a complete MIDI message has been encoded, the sequencer event is written to + * \a ev; otherwise, further bytes are required to complete a message. + * + * See also the description of #snd_midi_event_encode. + * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_midi_event_new, snd_midi_event_reset_encode, snd_midi_event_encode + */ +int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev) +{ + int rc = 0; + + c &= 0xff; + + if (c >= MIDI_CMD_COMMON_CLOCK) { + /* real-time event */ + ev->type = status_event[ST_SPECIAL + c - 0xf0].event; + ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; + ev->flags |= SND_SEQ_EVENT_LENGTH_FIXED; + return ev->type != SND_SEQ_EVENT_NONE; + } + + if ((c & 0x80) && + (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) { + /* new command */ + dev->buf[0] = c; + if ((c & 0xf0) == 0xf0) /* system message */ + dev->type = (c & 0x0f) + ST_SPECIAL; + else + dev->type = (c >> 4) & 0x07; + dev->read = 1; + dev->qlen = status_event[dev->type].qlen; + } else { + if (dev->qlen > 0) { + /* rest of command */ + dev->buf[dev->read++] = c; + if (dev->type != ST_SYSEX) + dev->qlen--; + } else { + /* running status */ + dev->buf[1] = c; + dev->qlen = status_event[dev->type].qlen - 1; + dev->read = 2; + } + } + if (dev->qlen == 0) { + ev->type = status_event[dev->type].event; + ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; + ev->flags |= SND_SEQ_EVENT_LENGTH_FIXED; + if (status_event[dev->type].encode) /* set data values */ + status_event[dev->type].encode(dev, ev); + if (dev->type >= ST_SPECIAL) + dev->type = ST_INVALID; + rc = 1; + } else if (dev->type == ST_SYSEX) { + if (c == MIDI_CMD_COMMON_SYSEX_END || + dev->read >= dev->bufsize) { + ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; + ev->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE; + ev->type = SND_SEQ_EVENT_SYSEX; + ev->data.ext.len = dev->read; + ev->data.ext.ptr = dev->buf; + if (c != MIDI_CMD_COMMON_SYSEX_END) + dev->read = 0; /* continue to parse */ + else + reset_encode(dev); /* all parsed */ + rc = 1; + } + } + + return rc; +} + +/* encode note event */ +static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + ev->data.note.channel = dev->buf[0] & 0x0f; + ev->data.note.note = dev->buf[1]; + ev->data.note.velocity = dev->buf[2]; +} + +/* encode one parameter controls */ +static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + ev->data.control.channel = dev->buf[0] & 0x0f; + ev->data.control.value = dev->buf[1]; +} + +/* encode pitch wheel change */ +static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + ev->data.control.channel = dev->buf[0] & 0x0f; + ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192; +} + +/* encode midi control change */ +static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + ev->data.control.channel = dev->buf[0] & 0x0f; + ev->data.control.param = dev->buf[1]; + ev->data.control.value = dev->buf[2]; +} + +/* encode one parameter value*/ +static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + ev->data.control.value = dev->buf[1]; +} + +/* encode song position */ +static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1]; +} + +/** + * \brief Decodes sequencer event to MIDI byte stream. + * \param[in] dev MIDI event parser. + * \param[out] buf Buffer for the resulting MIDI byte stream. + * \param[in] count Number of bytes in \a buf. + * \param[in] ev The sequencer event to decode. + * \return The number of bytes written to \a buf, or a negative error code. + * + * This function tries to decode the sequencer event into one or more MIDI + * messages, and writes the raw MIDI byte(s) into \a buf. + * + * The generated MIDI messages may use running status, unless disabled with + * #snd_midi_event_no_status. + * + * The required buffer size for a sequencer event it as most 12 bytes, except + * for System Exclusive events (\a ev->type == #SND_SEQ_EVENT_SYSEX) which can + * have any length (as specified by \a ev->data.ext.len). + * + * The following sequencer events correspond to MIDI messages: + * - #SND_SEQ_EVENT_NOTEOFF + * - #SND_SEQ_EVENT_NOTEON + * - #SND_SEQ_EVENT_KEYPRESS + * - #SND_SEQ_EVENT_CONTROLLER + * - #SND_SEQ_EVENT_PGMCHANGE + * - #SND_SEQ_EVENT_CHANPRESS + * - #SND_SEQ_EVENT_PITCHBEND + * - #SND_SEQ_EVENT_SYSEX + * - #SND_SEQ_EVENT_QFRAME + * - #SND_SEQ_EVENT_SONGPOS + * - #SND_SEQ_EVENT_SONGSEL + * - #SND_SEQ_EVENT_TUNE_REQUEST + * - #SND_SEQ_EVENT_CLOCK + * - #SND_SEQ_EVENT_START + * - #SND_SEQ_EVENT_CONTINUE + * - #SND_SEQ_EVENT_STOP + * - #SND_SEQ_EVENT_SENSING + * - #SND_SEQ_EVENT_RESET + * - #SND_SEQ_EVENT_CONTROL14 + * - #SND_SEQ_EVENT_NONREGPARAM + * - #SND_SEQ_EVENT_REGPARAM + * + * \par Errors: + *
+ *
-EINVAL
\a ev is not a valid sequencer event. + *
-ENOENT
The sequencer event does not correspond to one or more MIDI messages. + *
-ENOMEM
The MIDI message(s) would not fit into \a count bytes. + * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_midi_event_reset_decode, snd_midi_event_no_status + */ +long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count, const snd_seq_event_t *ev) +{ + int cmd; + long qlen; + unsigned int type; + + if (ev->type == SND_SEQ_EVENT_NONE) + return -ENOENT; + + for (type = 0; type < numberof(status_event); type++) { + if (ev->type == status_event[type].event) + goto __found; + } + for (type = 0; type < numberof(extra_event); type++) { + if (ev->type == extra_event[type].event) + return extra_event[type].decode(dev, buf, count, ev); + } + return -ENOENT; + + __found: + if (type >= ST_SPECIAL) + cmd = 0xf0 + (type - ST_SPECIAL); + else + /* data.note.channel and data.control.channel is identical */ + cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f); + + + if (cmd == MIDI_CMD_COMMON_SYSEX) { + snd_midi_event_reset_decode(dev); + qlen = ev->data.ext.len; + if (count < qlen) + return -ENOMEM; + switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) { + case SND_SEQ_EVENT_LENGTH_FIXED: + return -EINVAL; /* invalid event */ + } + memcpy(buf, ev->data.ext.ptr, qlen); + return qlen; + } else { + unsigned char xbuf[4]; + + if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) { + dev->lastcmd = cmd; + xbuf[0] = cmd; + if (status_event[type].decode) + status_event[type].decode(ev, xbuf + 1); + qlen = status_event[type].qlen + 1; + } else { + if (status_event[type].decode) + status_event[type].decode(ev, xbuf + 0); + qlen = status_event[type].qlen; + } + if (count < qlen) + return -ENOMEM; + memcpy(buf, xbuf, qlen); + return qlen; + } +} + + +/* decode note event */ +static void note_decode(const snd_seq_event_t *ev, unsigned char *buf) +{ + buf[0] = ev->data.note.note & 0x7f; + buf[1] = ev->data.note.velocity & 0x7f; +} + +/* decode one parameter controls */ +static void one_param_decode(const snd_seq_event_t *ev, unsigned char *buf) +{ + buf[0] = ev->data.control.value & 0x7f; +} + +/* decode pitch wheel change */ +static void pitchbend_decode(const snd_seq_event_t *ev, unsigned char *buf) +{ + int value = ev->data.control.value + 8192; + buf[0] = value & 0x7f; + buf[1] = (value >> 7) & 0x7f; +} + +/* decode midi control change */ +static void two_param_decode(const snd_seq_event_t *ev, unsigned char *buf) +{ + buf[0] = ev->data.control.param & 0x7f; + buf[1] = ev->data.control.value & 0x7f; +} + +/* decode song position */ +static void songpos_decode(const snd_seq_event_t *ev, unsigned char *buf) +{ + buf[0] = ev->data.control.value & 0x7f; + buf[1] = (ev->data.control.value >> 7) & 0x7f; +} + +/* decode 14bit control */ +static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int count, const snd_seq_event_t *ev) +{ + unsigned char cmd; + int idx = 0; + + cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); + if (ev->data.control.param < 32) { + if (count < 4) + return -ENOMEM; + if (dev->nostat && count < 6) + return -ENOMEM; + if (cmd != dev->lastcmd || dev->nostat) { + if (count < 5) + return -ENOMEM; + buf[idx++] = dev->lastcmd = cmd; + } + buf[idx++] = ev->data.control.param; + buf[idx++] = (ev->data.control.value >> 7) & 0x7f; + if (dev->nostat) + buf[idx++] = cmd; + buf[idx++] = ev->data.control.param + 32; + buf[idx++] = ev->data.control.value & 0x7f; + } else { + if (count < 2) + return -ENOMEM; + if (cmd != dev->lastcmd || dev->nostat) { + if (count < 3) + return -ENOMEM; + buf[idx++] = dev->lastcmd = cmd; + } + buf[idx++] = ev->data.control.param & 0x7f; + buf[idx++] = ev->data.control.value & 0x7f; + } + return idx; +} + +/* decode reg/nonreg param */ +static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, const snd_seq_event_t *ev) +{ + unsigned char cmd; + const char *cbytes; + static const char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB, + MIDI_CTL_NONREG_PARM_NUM_LSB, + MIDI_CTL_MSB_DATA_ENTRY, + MIDI_CTL_LSB_DATA_ENTRY }; + static const char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB, + MIDI_CTL_REGIST_PARM_NUM_LSB, + MIDI_CTL_MSB_DATA_ENTRY, + MIDI_CTL_LSB_DATA_ENTRY }; + unsigned char bytes[4]; + int idx = 0, i; + + if (count < 8) + return -ENOMEM; + if (dev->nostat && count < 12) + return -ENOMEM; + cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); + bytes[0] = (ev->data.control.param & 0x3f80) >> 7; + bytes[1] = ev->data.control.param & 0x007f; + bytes[2] = (ev->data.control.value & 0x3f80) >> 7; + bytes[3] = ev->data.control.value & 0x007f; + if (cmd != dev->lastcmd && !dev->nostat) { + if (count < 9) + return -ENOMEM; + buf[idx++] = dev->lastcmd = cmd; + } + cbytes = ev->type == SND_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn; + for (i = 0; i < 4; i++) { + if (dev->nostat) + buf[idx++] = dev->lastcmd = cmd; + buf[idx++] = cbytes[i]; + buf[idx++] = bytes[i]; + } + return idx; +} diff --git a/src/seq/seq_old.c b/src/seq/seq_old.c new file mode 100644 index 0000000..60d5f4b --- /dev/null +++ b/src/seq/seq_old.c @@ -0,0 +1,222 @@ +/* + * place-holders to keep libasound linkable to old binaries + */ + +#ifndef DOXYGEN + +#include "local.h" + +size_t snd_instr_header_sizeof(void) +{ + return 0; +} + +int snd_instr_header_malloc(void **ptr ATTRIBUTE_UNUSED, + size_t len ATTRIBUTE_UNUSED) +{ + return -ENOMEM; +} + +void snd_instr_header_free(void *obj ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_copy(void *dst ATTRIBUTE_UNUSED, + const void *src ATTRIBUTE_UNUSED) +{ +} + +const void *snd_instr_header_get_id(const void *info ATTRIBUTE_UNUSED) +{ + return NULL; +} + +int snd_instr_header_get_cluster(const void *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +unsigned int snd_instr_header_get_cmd(const void *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +size_t snd_instr_header_get_len(const void *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +const char *snd_instr_header_get_name(const void *info ATTRIBUTE_UNUSED) +{ + return NULL; +} + +int snd_instr_header_get_type(const void *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +const char *snd_instr_header_get_format(const void *info ATTRIBUTE_UNUSED) +{ + return NULL; +} + +const void *snd_instr_header_get_alias(const void *info ATTRIBUTE_UNUSED) +{ + return NULL; +} + +void *snd_instr_header_get_data(const void *info ATTRIBUTE_UNUSED) +{ + return NULL; +} + +int snd_instr_header_get_follow_alias(const void *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +void snd_instr_header_set_id(void *info ATTRIBUTE_UNUSED, + const void *id ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_cluster(void *info ATTRIBUTE_UNUSED, + int cluster ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_cmd(void *info ATTRIBUTE_UNUSED, + unsigned int cmd ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_len(void *info ATTRIBUTE_UNUSED, + size_t len ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_name(void *info ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_type(void *info ATTRIBUTE_UNUSED, + int type ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_format(void *info ATTRIBUTE_UNUSED, + const char *format ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_alias(void *info ATTRIBUTE_UNUSED, + const void *instr ATTRIBUTE_UNUSED) +{ +} + +void snd_instr_header_set_follow_alias(void *info ATTRIBUTE_UNUSED, + int val ATTRIBUTE_UNUSED) +{ +} + +int snd_instr_fm_free(void *fm ATTRIBUTE_UNUSED) +{ + return 0; +} + +int snd_instr_fm_convert_to_stream(void *fm ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + void **__data ATTRIBUTE_UNUSED, + size_t *__size ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_fm_convert_from_stream(void *__data ATTRIBUTE_UNUSED, + size_t size ATTRIBUTE_UNUSED, + void **simple ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + + +int snd_instr_iwffff_open(void **handle ATTRIBUTE_UNUSED, + const char *name_fff ATTRIBUTE_UNUSED, + const char *name_dat ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_iwffff_open_rom(void **handle ATTRIBUTE_UNUSED, + int card ATTRIBUTE_UNUSED, + int bank ATTRIBUTE_UNUSED, + int file ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_iwffff_open_rom_file(void **handle ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + int bank ATTRIBUTE_UNUSED, + int file ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_iwffff_close(void *handle ATTRIBUTE_UNUSED) +{ + return 0; +} + +int snd_instr_iwffff_free(void *__instr ATTRIBUTE_UNUSED) +{ + return 0; +} + +int snd_instr_iwffff_load(void *iwf ATTRIBUTE_UNUSED, + int bank ATTRIBUTE_UNUSED, + int prg ATTRIBUTE_UNUSED, + void **__iwffff ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_iwffff_convert_to_stream(void *iwffff ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + void **__data ATTRIBUTE_UNUSED, + size_t *__size ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_iwffff_convert_from_stream(void *data ATTRIBUTE_UNUSED, + size_t size ATTRIBUTE_UNUSED, + void **iwffff ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + + +int snd_instr_simple_free(void *simple ATTRIBUTE_UNUSED) +{ + return 0; +} + +int snd_instr_simple_convert_to_stream(void *simple ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + void **__data ATTRIBUTE_UNUSED, + size_t *__size ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +int snd_instr_simple_convert_from_stream(void *__data ATTRIBUTE_UNUSED, + size_t size ATTRIBUTE_UNUSED, + void **simple ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +#endif /* !DOXYGEN */ diff --git a/src/seq/seq_symbols.c b/src/seq/seq_symbols.c new file mode 100644 index 0000000..1d30133 --- /dev/null +++ b/src/seq/seq_symbols.c @@ -0,0 +1,34 @@ +/* + * Sequencer Symbols + * Copyright (c) 2001 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +extern const char *_snd_module_seq_hw; + +static const char **snd_seq_open_objects[] = { + &_snd_module_seq_hw +}; + +void *snd_seq_open_symbols(void) +{ + return snd_seq_open_objects; +} + +#endif /* !PIC */ diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c new file mode 100644 index 0000000..894c3a2 --- /dev/null +++ b/src/seq/seqmid.c @@ -0,0 +1,427 @@ +/* + * Sequencer Interface - middle-level routines + * + * Copyright (c) 1999 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "seq_local.h" + +/** + * \brief queue controls - start/stop/continue + * \param seq sequencer handle + * \param q queue id to control + * \param type event type + * \param value event value + * \param ev event instance + * + * This function sets up general queue control event and sends it. + * To send at scheduled time, set the schedule in \a ev. + * If \a ev is NULL, the event is composed locally and sent immediately + * to the specified queue. In any cases, you need to call #snd_seq_drain_output() + * appropriately to feed the event. + * + * \sa snd_seq_alloc_queue() + */ +int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev) +{ + snd_seq_event_t tmpev; + if (ev == NULL) { + snd_seq_ev_clear(&tmpev); + ev = &tmpev; + snd_seq_ev_set_direct(ev); + } + snd_seq_ev_set_queue_control(ev, type, q, value); + return snd_seq_event_output(seq, ev); +} + + +/** + * \brief create a port - simple version + * \param seq sequencer handle + * \param name the name of the port + * \param caps capability bits + * \param type type bits + * \return the created port number or negative error code + * + * Creates a port with the given capability and type bits. + * + * \sa snd_seq_create_port(), snd_seq_delete_simple_port() + */ +int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, + unsigned int caps, unsigned int type) +{ + snd_seq_port_info_t pinfo; + int result; + + memset(&pinfo, 0, sizeof(pinfo)); + if (name) + strncpy(pinfo.name, name, sizeof(pinfo.name) - 1); + pinfo.capability = caps; + pinfo.type = type; + pinfo.midi_channels = 16; + pinfo.midi_voices = 64; /* XXX */ + pinfo.synth_voices = 0; /* XXX */ + + result = snd_seq_create_port(seq, &pinfo); + if (result < 0) + return result; + else + return pinfo.addr.port; +} + +/** + * \brief delete the port + * \param seq sequencer handle + * \param port port id + * \return 0 on success or negative error code + * + * \sa snd_seq_delete_port(), snd_seq_create_simple_port() + */ +int snd_seq_delete_simple_port(snd_seq_t *seq, int port) +{ + return snd_seq_delete_port(seq, port); +} + +/** + * \brief simple subscription (w/o exclusive & time conversion) + * \param seq sequencer handle + * \param myport the port id as receiver + * \param src_client sender client id + * \param src_port sender port id + * \return 0 on success or negative error code + * + * Connect from the given sender client:port to the given destination port in the + * current client. + * + * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from() + */ +int snd_seq_connect_from(snd_seq_t *seq, int myport, int src_client, int src_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + subs.sender.client = src_client; + subs.sender.port = src_port; + /*subs.dest.client = seq->client;*/ + subs.dest.client = snd_seq_client_id(seq); + subs.dest.port = myport; + + return snd_seq_subscribe_port(seq, &subs); +} + +/** + * \brief simple subscription (w/o exclusive & time conversion) + * \param seq sequencer handle + * \param myport the port id as sender + * \param dest_client destination client id + * \param dest_port destination port id + * \return 0 on success or negative error code + * + * Connect from the given receiver port in the current client + * to the given destination client:port. + * + * \sa snd_seq_subscribe_port(), snd_seq_disconnect_to() + */ +int snd_seq_connect_to(snd_seq_t *seq, int myport, int dest_client, int dest_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + /*subs.sender.client = seq->client;*/ + subs.sender.client = snd_seq_client_id(seq); + subs.sender.port = myport; + subs.dest.client = dest_client; + subs.dest.port = dest_port; + + return snd_seq_subscribe_port(seq, &subs); +} + +/** + * \brief simple disconnection + * \param seq sequencer handle + * \param myport the port id as receiver + * \param src_client sender client id + * \param src_port sender port id + * \return 0 on success or negative error code + * + * Remove connection from the given sender client:port + * to the given destination port in the current client. + * + * \sa snd_seq_unsubscribe_port(), snd_seq_connect_from() + */ +int snd_seq_disconnect_from(snd_seq_t *seq, int myport, int src_client, int src_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + subs.sender.client = src_client; + subs.sender.port = src_port; + /*subs.dest.client = seq->client;*/ + subs.dest.client = snd_seq_client_id(seq); + subs.dest.port = myport; + + return snd_seq_unsubscribe_port(seq, &subs); +} + +/** + * \brief simple disconnection + * \param seq sequencer handle + * \param myport the port id as sender + * \param dest_client destination client id + * \param dest_port destination port id + * \return 0 on success or negative error code + * + * Remove connection from the given sender client:port + * to the given destination port in the current client. + * + * \sa snd_seq_unsubscribe_port(), snd_seq_connect_to() + */ +int snd_seq_disconnect_to(snd_seq_t *seq, int myport, int dest_client, int dest_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + /*subs.sender.client = seq->client;*/ + subs.sender.client = snd_seq_client_id(seq); + subs.sender.port = myport; + subs.dest.client = dest_client; + subs.dest.port = dest_port; + + return snd_seq_unsubscribe_port(seq, &subs); +} + +/* + * set client information + */ + +/** + * \brief set client name + * \param seq sequencer handle + * \param name name string + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_info() + */ +int snd_seq_set_client_name(snd_seq_t *seq, const char *name) +{ + snd_seq_client_info_t info; + int err; + + if ((err = snd_seq_get_client_info(seq, &info)) < 0) + return err; + strncpy(info.name, name, sizeof(info.name) - 1); + return snd_seq_set_client_info(seq, &info); +} + +/** + * \brief add client event filter + * \param seq sequencer handle + * \param event_type event type to be added + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_info() + */ +int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type) +{ + snd_seq_client_info_t info; + int err; + + if ((err = snd_seq_get_client_info(seq, &info)) < 0) + return err; + snd_seq_client_info_event_filter_add(&info, event_type); + return snd_seq_set_client_info(seq, &info); +} + +/** + * \brief change the output pool size of the given client + * \param seq sequencer handle + * \param size output pool size + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_pool() + */ +int snd_seq_set_client_pool_output(snd_seq_t *seq, size_t size) +{ + snd_seq_client_pool_t info; + int err; + + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + info.output_pool = size; + return snd_seq_set_client_pool(seq, &info); +} + +/** + * \brief change the output room size of the given client + * \param seq sequencer handle + * \param size output room size + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_pool() + */ +int snd_seq_set_client_pool_output_room(snd_seq_t *seq, size_t size) +{ + snd_seq_client_pool_t info; + int err; + + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + info.output_room = size; + return snd_seq_set_client_pool(seq, &info); +} + +/** + * \brief change the input pool size of the given client + * \param seq sequencer handle + * \param size input pool size + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_pool() + */ +int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size) +{ + snd_seq_client_pool_t info; + int err; + + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + info.input_pool = size; + return snd_seq_set_client_pool(seq, &info); +} + +/** + * \brief reset client output pool + * \param seq sequencer handle + * \return 0 on success or negative error code + * + * So far, this works identically like #snd_seq_drop_output(). + */ +int snd_seq_reset_pool_output(snd_seq_t *seq) +{ + return snd_seq_drop_output(seq); +} + +/** + * \brief reset client input pool + * \param seq sequencer handle + * \return 0 on success or negative error code + * + * So far, this works identically like #snd_seq_drop_input(). + */ +int snd_seq_reset_pool_input(snd_seq_t *seq) +{ + return snd_seq_drop_input(seq); +} + +/** + * \brief wait until all events are processed + * \param seq sequencer handle + * \return 0 on success or negative error code + * + * This function waits until all events of this client are processed. + * + * \sa snd_seq_drain_output() + */ +int snd_seq_sync_output_queue(snd_seq_t *seq) +{ + int err; + snd_seq_client_pool_t info; + int saved_room; + struct pollfd pfd; + + assert(seq); + /* reprogram the room size to full */ + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + saved_room = info.output_room; + info.output_room = info.output_pool; /* wait until all gone */ + if ((err = snd_seq_set_client_pool(seq, &info)) < 0) + return err; + /* wait until all events are purged */ + pfd.fd = seq->poll_fd; + pfd.events = POLLOUT; + err = poll(&pfd, 1, -1); + /* restore the room size */ + info.output_room = saved_room; + snd_seq_set_client_pool(seq, &info); + return err; +} + +/** + * \brief parse the given string and get the sequencer address + * \param seq sequencer handle + * \param addr the address pointer to be returned + * \param arg the string to be parsed + * \return 0 on success or negative error code + * + * This function parses the sequencer client and port numbers from the given string. + * The client and port tokes are separated by either colon or period, e.g. 128:1. + * When \a seq is not NULL, the function accepts also a client name not only + * digit numbers. + */ +int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg) +{ + char *p; + int client, port; + int len; + + assert(addr && arg); + + if ((p = strpbrk(arg, ":.")) != NULL) { + if ((port = atoi(p + 1)) < 0) + return -EINVAL; + len = (int)(p - arg); /* length of client name */ + } else { + port = 0; + len = strlen(arg); + } + addr->port = port; + if (isdigit(*arg)) { + client = atoi(arg); + if (client < 0) + return -EINVAL; + addr->client = client; + } else { + /* convert from the name */ + snd_seq_client_info_t cinfo; + + if (! seq) + return -EINVAL; + if (len <= 0) + return -EINVAL; + cinfo.client = -1; + while (snd_seq_query_next_client(seq, &cinfo) >= 0) { + if ((strlen(cinfo.name) == len) && + ! strncmp(arg, cinfo.name, len)) { + addr->client = cinfo.client; + return 0; + } + } + return -ENOENT; /* not found */ + } + return 0; +} + diff --git a/src/shmarea.c b/src/shmarea.c new file mode 100644 index 0000000..071f9f3 --- /dev/null +++ b/src/shmarea.c @@ -0,0 +1,108 @@ +/* + * IPC SHM area manager + * Copyright (c) 2003 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "list.h" + +#ifndef DOC_HIDDEN +struct snd_shm_area { + struct list_head list; + int shmid; + void *ptr; + int share; +}; +#endif + +static LIST_HEAD(shm_areas); + +/** + * \brief Create a shm area record + * \param shmid IPC SHM ID + * \param ptr the shared area pointer + * \return The allocated shm area record, NULL if fail + * + * Allocates a shared area record with the given SHM ID and pointer. + * The record has a reference counter, which is initialized to 1 by this function. + */ +struct snd_shm_area *snd_shm_area_create(int shmid, void *ptr) +{ + struct snd_shm_area *area = malloc(sizeof(*area)); + if (area) { + area->shmid = shmid; + area->ptr = ptr; + area->share = 1; + list_add_tail(&area->list, &shm_areas); + } + return area; +} + +/** + * \brief Increase the reference counter of shm area record + * \param area shm area record + * \return the shm area record (identical with the argument) + * + * Increases the reference counter of the given shared area record. + */ +struct snd_shm_area *snd_shm_area_share(struct snd_shm_area *area) +{ + if (area == NULL) + return NULL; + area->share++; + return area; +} + +/** + * \brief Release the shared area record + * \param area the shared are record + * \return 0 if successful, or a negative error code + * + * Decreases the reference counter of the given shared area record, and + * releases the resources automaticall if it reaches to 0. + */ +int snd_shm_area_destroy(struct snd_shm_area *area) +{ + if (area == NULL) + return -ENOENT; + if (--area->share) + return 0; + list_del(&area->list); + shmdt(area->ptr); + free(area); + return 0; +} + +void snd_shm_area_destructor(void) __attribute__ ((destructor)); + +void snd_shm_area_destructor(void) +{ + struct list_head *pos; + struct snd_shm_area *area; + + list_for_each(pos, &shm_areas) { + area = list_entry(pos, struct snd_shm_area, list); + shmdt(area->ptr); + } +} diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..97c919f --- /dev/null +++ b/src/socket.c @@ -0,0 +1,158 @@ +/** + * \file socket.c + * \brief Socket helper routines + * \author Abramo Bagnara + * \date 2003 + */ +/* + * Socket helper routines + * Copyright (c) 2003 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "local.h" + +#ifndef DOC_HIDDEN +int snd_send_fd(int sock, void *data, size_t len, int fd) +{ + int ret; + size_t cmsg_len = CMSG_LEN(sizeof(int)); + struct cmsghdr *cmsg = alloca(cmsg_len); + int *fds = (int *) CMSG_DATA(cmsg); + struct msghdr msghdr; + struct iovec vec; + + vec.iov_base = (void *)&data; + vec.iov_len = len; + + cmsg->cmsg_len = cmsg_len; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *fds = fd; + + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = &vec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = cmsg; + msghdr.msg_controllen = cmsg_len; + msghdr.msg_flags = 0; + + ret = sendmsg(sock, &msghdr, 0 ); + if (ret < 0) { + SYSERR("sendmsg failed"); + return -errno; + } + return ret; +} + +int snd_receive_fd(int sock, void *data, size_t len, int *fd) +{ + int ret; + size_t cmsg_len = CMSG_LEN(sizeof(int)); + struct cmsghdr *cmsg = alloca(cmsg_len); + int *fds = (int *) CMSG_DATA(cmsg); + struct msghdr msghdr; + struct iovec vec; + + vec.iov_base = (void *)&data; + vec.iov_len = len; + + cmsg->cmsg_len = cmsg_len; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *fds = -1; + + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; + msghdr.msg_iov = &vec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = cmsg; + msghdr.msg_controllen = cmsg_len; + msghdr.msg_flags = 0; + + ret = recvmsg(sock, &msghdr, 0); + if (ret < 0) { + SYSERR("recvmsg failed"); + return -errno; + } + *fd = *fds; + return ret; +} + +int snd_is_local(struct hostent *hent) +{ + int s; + int err; + struct ifconf conf; + size_t numreqs = 10; + size_t i; + struct in_addr *haddr = (struct in_addr*) hent->h_addr_list[0]; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s < 0) { + SYSERR("socket failed"); + return -errno; + } + + conf.ifc_len = numreqs * sizeof(struct ifreq); + conf.ifc_buf = malloc((unsigned int) conf.ifc_len); + if (! conf.ifc_buf) + return -ENOMEM; + while (1) { + err = ioctl(s, SIOCGIFCONF, &conf); + if (err < 0) { + SYSERR("SIOCGIFCONF failed"); + return -errno; + } + if ((size_t)conf.ifc_len < numreqs * sizeof(struct ifreq)) + break; + numreqs *= 2; + conf.ifc_len = numreqs * sizeof(struct ifreq); + conf.ifc_buf = realloc(conf.ifc_buf, (unsigned int) conf.ifc_len); + if (! conf.ifc_buf) + return -ENOMEM; + } + numreqs = conf.ifc_len / sizeof(struct ifreq); + for (i = 0; i < numreqs; ++i) { + struct ifreq *req = &conf.ifc_req[i]; + struct sockaddr_in *s_in = (struct sockaddr_in *)&req->ifr_addr; + s_in->sin_family = AF_INET; + err = ioctl(s, SIOCGIFADDR, req); + if (err < 0) + continue; + if (haddr->s_addr == s_in->sin_addr.s_addr) + break; + } + close(s); + free(conf.ifc_buf); + return i < numreqs; +} +#endif diff --git a/src/timer/Makefile.am b/src/timer/Makefile.am new file mode 100644 index 0000000..e7cf77b --- /dev/null +++ b/src/timer/Makefile.am @@ -0,0 +1,9 @@ +EXTRA_LTLIBRARIES=libtimer.la + +libtimer_la_SOURCES = timer.c timer_hw.c timer_query.c timer_query_hw.c \ + timer_symbols.c +noinst_HEADERS = timer_local.h +all: libtimer.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/timer/Makefile.in b/src/timer/Makefile.in new file mode 100644 index 0000000..2ed9bac --- /dev/null +++ b/src/timer/Makefile.in @@ -0,0 +1,497 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/timer +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libtimer_la_LIBADD = +am_libtimer_la_OBJECTS = timer.lo timer_hw.lo timer_query.lo \ + timer_query_hw.lo timer_symbols.lo +libtimer_la_OBJECTS = $(am_libtimer_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libtimer_la_SOURCES) +DIST_SOURCES = $(libtimer_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libtimer.la +libtimer_la_SOURCES = timer.c timer_hw.c timer_query.c timer_query_hw.c \ + timer_symbols.c + +noinst_HEADERS = timer_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/timer/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/timer/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libtimer.la: $(libtimer_la_OBJECTS) $(libtimer_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libtimer_la_OBJECTS) $(libtimer_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_query.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_query_hw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_symbols.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + +all: libtimer.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/timer/timer.c b/src/timer/timer.c new file mode 100644 index 0000000..b71a9f8 --- /dev/null +++ b/src/timer/timer.c @@ -0,0 +1,959 @@ +/** + * \file timer/timer.c + * \brief Timer Interface + * \author Jaroslav Kysela + * \date 1998-2001 + * + * Timer Interface is designed to access timers. + * See \ref timer page for more details. + */ +/* + * Timer Interface - main file + * Copyright (c) 1998-2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page timer Timer interface + +

Timer interface is designed to use internal timers in sound hardware, but +it can be driven with any timer. + +\section timer_general_overview General overview + +The timer implementation uses ring buffer to store information about timing +events. In this buffer is recorded count of ticks and current tick resolution +in nanoseconds. + +\section timer_open Opening + +Timer devices can be opened in two ways. When #SND_TIMER_OPEN_NONBLOCK flag +is used, then the open functions return immediately with -EBUSY error code when +resources are occupied with another application. When #SND_TIMER_OPEN_NONBLOCK +is not used (by default) the open functions block the application requesting +device until resources are not free. + +\section timer_events Events + +Events are read via snd_timer_read() function. + +\section timer_examples Examples + +The full featured examples with cross-links: + +\par Simple timer test program +\ref example_test_timer "example code" +\par +This example shows opening a timer device and reading of timer events. + +*/ + +/** + * \example ../test/timer.c + * \anchor example_test_timer + */ + +#include +#include +#include +#include +#include +#include +#include +#include "timer_local.h" + +static int snd_timer_open_conf(snd_timer_t **timer, + const char *name, snd_config_t *timer_root, + snd_config_t *timer_conf, int mode) +{ + const char *str; + char buf[256]; + int err; + snd_config_t *conf, *type_conf = NULL; + snd_config_iterator_t i, next; + const char *id; + const char *lib = NULL, *open_name = NULL; + int (*open_func)(snd_timer_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL; +#ifndef PIC + extern void *snd_timer_open_symbols(void); +#endif + void *h = NULL; + if (snd_config_get_type(timer_conf) != SND_CONFIG_TYPE_COMPOUND) { + if (name) + SNDERR("Invalid type for TIMER %s definition", name); + else + SNDERR("Invalid type for TIMER definition"); + return -EINVAL; + } + err = snd_config_search(timer_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(timer_root, "timer_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for TIMER type %s definition", str); + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + open_name = buf; + snprintf(buf, sizeof(buf), "_snd_timer_%s_open", str); + } +#ifndef PIC + snd_timer_open_symbols(); +#endif + h = snd_dlopen(lib, RTLD_NOW); + if (h) + open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_TIMER_DLSYM_VERSION)); + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + if (! err) { + err = open_func(timer, name, timer_root, timer_conf, mode); + if (err < 0) + snd_dlclose(h); + else + (*timer)->dl_handle = h; + } + return err; +} + +static int snd_timer_open_noupdate(snd_timer_t **timer, snd_config_t *root, const char *name, int mode) +{ + int err; + snd_config_t *timer_conf; + err = snd_config_search_definition(root, "timer", name, &timer_conf); + if (err < 0) { + SNDERR("Unknown timer %s", name); + return err; + } + err = snd_timer_open_conf(timer, name, root, timer_conf, mode); + snd_config_delete(timer_conf); + return err; +} + +/** + * \brief Opens a new connection to the timer interface. + * \param timer Returned handle (NULL if not wanted) + * \param name ASCII identifier of the timer handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the timer interface specified with + * an ASCII identifier and mode. + */ +int snd_timer_open(snd_timer_t **timer, const char *name, int mode) +{ + int err; + assert(timer && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_timer_open_noupdate(timer, snd_config, name, mode); +} + +/** + * \brief Opens a new connection to the timer interface using local configuration + * \param timer Returned handle (NULL if not wanted) + * \param name ASCII identifier of the timer handle + * \param mode Open mode + * \param lconf Local configuration + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the timer interface specified with + * an ASCII identifier and mode. + */ +int snd_timer_open_lconf(snd_timer_t **timer, const char *name, + int mode, snd_config_t *lconf) +{ + assert(timer && name && lconf); + return snd_timer_open_noupdate(timer, lconf, name, mode); +} + +/** + * \brief close timer handle + * \param timer timer handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified timer handle and frees all associated + * resources. + */ +int snd_timer_close(snd_timer_t *timer) +{ + int err; + assert(timer); + while (!list_empty(&timer->async_handlers)) { + snd_async_handler_t *h = list_entry(timer->async_handlers.next, snd_async_handler_t, hlist); + snd_async_del_handler(h); + } + err = timer->ops->close(timer); + if (timer->dl_handle) + snd_dlclose(timer->dl_handle); + free(timer->name); + free(timer); + return err; +} + +/** + * \brief get identifier of timer handle + * \param timer a timer handle + * \return ascii identifier of timer handle + * + * Returns the ASCII identifier of given timer handle. It's the same + * identifier specified in snd_timer_open(). + */ +const char *snd_timer_name(snd_timer_t *timer) +{ + assert(timer); + return timer->name; +} + +/** + * \brief get type of timer handle + * \param timer a timer handle + * \return type of timer handle + * + * Returns the type #snd_timer_type_t of given timer handle. + */ +snd_timer_type_t snd_timer_type(snd_timer_t *timer) +{ + assert(timer); + return timer->type; +} + +/** + * \brief Add an async handler for a timer + * \param handler Returned handler handle + * \param timer timer handle + * \param callback Callback function + * \param private_data Callback private data + * \return 0 otherwise a negative error code on failure + * + * The asynchronous callback is called when new timer event occurs. + */ +int snd_async_add_timer_handler(snd_async_handler_t **handler, snd_timer_t *timer, + snd_async_callback_t callback, void *private_data) +{ + int err; + int was_empty; + snd_async_handler_t *h; + err = snd_async_add_handler(&h, timer->poll_fd, + callback, private_data); + if (err < 0) + return err; + h->type = SND_ASYNC_HANDLER_TIMER; + h->u.timer = timer; + was_empty = list_empty(&timer->async_handlers); + list_add_tail(&h->hlist, &timer->async_handlers); + if (was_empty) { + err = snd_timer_async(timer, snd_async_handler_get_signo(h), getpid()); + if (err < 0) { + snd_async_del_handler(h); + return err; + } + } + *handler = h; + return 0; +} + +/** + * \brief Return timer handle related to an async handler + * \param handler Async handler handle + * \return timer handle + */ +snd_timer_t *snd_async_handler_get_timer(snd_async_handler_t *handler) +{ + if (handler->type != SND_ASYNC_HANDLER_TIMER) { + SNDMSG("invalid handler type %d", handler->type); + return NULL; + } + return handler->u.timer; +} + +/** + * \brief get count of poll descriptors for timer handle + * \param timer timer handle + * \return count of poll descriptors + */ +int snd_timer_poll_descriptors_count(snd_timer_t *timer) +{ + assert(timer); + return 1; +} + +/** + * \brief get poll descriptors + * \param timer timer handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_timer_poll_descriptors(snd_timer_t *timer, struct pollfd *pfds, unsigned int space) +{ + assert(timer); + if (space >= 1) { + pfds->fd = timer->poll_fd; + switch (timer->mode & O_ACCMODE) { + case O_WRONLY: + pfds->events = POLLOUT|POLLERR|POLLNVAL; + break; + case O_RDONLY: + pfds->events = POLLIN|POLLERR|POLLNVAL; + break; + case O_RDWR: + pfds->events = POLLOUT|POLLIN|POLLERR|POLLNVAL; + break; + default: + return -EIO; + } + return 1; + } + return 0; +} + +/** + * \brief get returned events from poll descriptors + * \param timer timer handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int snd_timer_poll_descriptors_revents(snd_timer_t *timer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(timer && pfds && revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +/** + * \brief set nonblock mode + * \param timer timer handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int snd_timer_nonblock(snd_timer_t *timer, int nonblock) +{ + int err; + assert(timer); + if ((err = timer->ops->nonblock(timer, nonblock)) < 0) + return err; + if (nonblock) + timer->mode |= SND_TIMER_OPEN_NONBLOCK; + else + timer->mode &= ~SND_TIMER_OPEN_NONBLOCK; + return 0; +} + +#ifndef DOC_HIDDEN +/** + * \brief set async mode + * \param timer timer handle + * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) + * \param pid Process ID to signal: 0 current + * \return 0 on success otherwise a negative error code + * + * A signal is raised every period. + */ +int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid) +{ + assert(timer); + if (sig == 0) + sig = SIGIO; + if (pid == 0) + pid = getpid(); + return timer->ops->async(timer, sig, pid); +} +#endif + +/** + * \brief get size of the snd_timer_info_t structure in bytes + * \return size of the snd_timer_info_t structure in bytes + */ +size_t snd_timer_info_sizeof() +{ + return sizeof(snd_timer_info_t); +} + +/** + * \brief allocate a new snd_timer_info_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_timer_info_t structure using the standard + * malloc C library function. + */ +int snd_timer_info_malloc(snd_timer_info_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_timer_info_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_timer_info_t structure + * \param info pointer to the snd_timer_info_t structure to free + * + * Frees the given snd_timer_info_t structure using the standard + * free C library function. + */ +void snd_timer_info_free(snd_timer_info_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_timer_info_t structure to another + * \param dst destination snd_timer_info_t structure + * \param src source snd_timer_info_t structure + */ +void snd_timer_info_copy(snd_timer_info_t *dst, const snd_timer_info_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief determine, if timer is slave + * \param info pointer to #snd_timer_info_t structure + * \return nonzero if timer is slave + */ +int snd_timer_info_is_slave(snd_timer_info_t * info) +{ + assert(info); + return info->flags & SNDRV_TIMER_FLG_SLAVE ? 1 : 0; +} + +/** + * \brief get timer card + * \param info pointer to #snd_timer_info_t structure + * \return timer card number + */ +int snd_timer_info_get_card(snd_timer_info_t * info) +{ + assert(info); + return info->card; +} + +/** + * \brief get timer id + * \param info pointer to #snd_timer_info_t structure + * \return timer id + */ +const char *snd_timer_info_get_id(snd_timer_info_t * info) +{ + assert(info); + return (const char *)info->id; +} + +/** + * \brief get timer name + * \param info pointer to #snd_timer_info_t structure + * \return timer name + */ +const char *snd_timer_info_get_name(snd_timer_info_t * info) +{ + assert(info); + return (const char *)info->name; +} + + +/** + * \brief get timer resolution in us + * \param info pointer to #snd_timer_info_t structure + * \return timer resolution + */ +long snd_timer_info_get_resolution(snd_timer_info_t * info) +{ + assert(info); + return info->resolution; +} + +/** + * \brief get information about timer handle + * \param timer timer handle + * \param info pointer to a snd_timer_info_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_timer_info(snd_timer_t *timer, snd_timer_info_t * info) +{ + assert(timer); + assert(info); + return timer->ops->info(timer, info); +} + +/** + * \brief get size of the snd_timer_params_t structure in bytes + * \return size of the snd_timer_params_t structure in bytes + */ +size_t snd_timer_params_sizeof() +{ + return sizeof(snd_timer_params_t); +} + +/** + * \brief allocate a new snd_timer_params_t structure + * \param params returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_timer_params_t structure using the standard + * malloc C library function. + */ +int snd_timer_params_malloc(snd_timer_params_t **params) +{ + assert(params); + *params = calloc(1, sizeof(snd_timer_params_t)); + if (!*params) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_timer_params_t structure + * \param params pointer to the snd_timer_params_t structure to free + * + * Frees the given snd_timer_params_t structure using the standard + * free C library function. + */ +void snd_timer_params_free(snd_timer_params_t *params) +{ + assert(params); + free(params); +} + +/** + * \brief copy one snd_timer_params_t structure to another + * \param dst destination snd_timer_params_t structure + * \param src source snd_timer_params_t structure + */ +void snd_timer_params_copy(snd_timer_params_t *dst, const snd_timer_params_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief set timer auto start + * \param params pointer to #snd_timer_params_t structure + * \param auto_start The boolean value to set + */ +int snd_timer_params_set_auto_start(snd_timer_params_t * params, int auto_start) +{ + assert(params); + if (auto_start) + params->flags |= SNDRV_TIMER_PSFLG_AUTO; + else + params->flags &= ~SNDRV_TIMER_PSFLG_AUTO; + return 0; +} + +/** + * \brief determine if timer has auto start flag + * \param params pointer to #snd_timer_params_t structure + * \return nonzero if timer has auto start flag + */ +int snd_timer_params_get_auto_start(snd_timer_params_t * params) +{ + assert(params); + return params->flags & SNDRV_TIMER_PSFLG_AUTO ? 1 : 0; +} + +/** + * \brief set timer exclusive use + * \param params pointer to #snd_timer_params_t structure + * \param exclusive The boolean value to set + */ +#ifndef DOXYGEN +int INTERNAL(snd_timer_params_set_exclusive)(snd_timer_params_t * params, int exclusive) +#else +int snd_timer_params_set_exclusive(snd_timer_params_t * params, int exclusive) +#endif +{ + assert(params); + if (exclusive) + params->flags |= SNDRV_TIMER_PSFLG_EXCLUSIVE; + else + params->flags &= ~SNDRV_TIMER_PSFLG_EXCLUSIVE; + return 0; +} +use_default_symbol_version(__snd_timer_params_set_exclusive, snd_timer_params_set_exclusive, ALSA_0.9.0); + +/** + * \brief determine if timer has exclusive flag + * \param params pointer to #snd_timer_params_t structure + * \return nonzero if timer has exclusive flag + */ +#ifndef DOXYGEN +int INTERNAL(snd_timer_params_get_exclusive)(snd_timer_params_t * params) +#else +int snd_timer_params_get_exclusive(snd_timer_params_t * params) +#endif +{ + assert(params); + return params->flags & SNDRV_TIMER_PSFLG_EXCLUSIVE ? 1 : 0; +} +use_default_symbol_version(__snd_timer_params_get_exclusive, snd_timer_params_get_exclusive, ALSA_0.9.0); + +/** + * \brief set timer early event + * \param params pointer to #snd_timer_params_t structure + * \param early_event The boolean value to set + */ +int snd_timer_params_set_early_event(snd_timer_params_t * params, int early_event) +{ + assert(params); + if (early_event) + params->flags |= SNDRV_TIMER_PSFLG_EARLY_EVENT; + else + params->flags &= ~SNDRV_TIMER_PSFLG_EARLY_EVENT; + return 0; +} + +/** + * \brief determine if timer has early event flag + * \param params pointer to #snd_timer_params_t structure + * \return nonzero if timer has early event flag set + */ +int snd_timer_params_get_early_event(snd_timer_params_t * params) +{ + assert(params); + return params->flags & SNDRV_TIMER_PSFLG_EARLY_EVENT ? 1 : 0; +} + +/** + * \brief set timer ticks + * \param params pointer to #snd_timer_params_t structure + * \param ticks Ticks to set + */ +void snd_timer_params_set_ticks(snd_timer_params_t * params, long ticks) +{ + assert(params); + params->ticks = ticks; +} + +/** + * \brief get timer ticks + * \param params pointer to #snd_timer_params_t structure + * \return timer ticks + */ +long snd_timer_params_get_ticks(snd_timer_params_t * params) +{ + assert(params); + return params->ticks; +} + +/** + * \brief set timer queue size (32-1024) + * \param params pointer to #snd_timer_params_t structure + * \param queue_size The queue size to set + */ +void snd_timer_params_set_queue_size(snd_timer_params_t * params, long queue_size) +{ + assert(params); + params->queue_size = queue_size; +} + +/** + * \brief get queue size + * \param params pointer to #snd_timer_params_t structure + * \return queue size + */ +long snd_timer_params_get_queue_size(snd_timer_params_t * params) +{ + assert(params); + return params->queue_size; +} + +/** + * \brief set timer event filter + * \param params pointer to #snd_timer_params_t structure + * \param filter The event filter bits to set + */ +#ifndef DOXYGEN +void INTERNAL(snd_timer_params_set_filter)(snd_timer_params_t * params, unsigned int filter) +#else +void snd_timer_params_set_filter(snd_timer_params_t * params, unsigned int filter) +#endif +{ + assert(params); + params->filter = filter; +} +use_default_symbol_version(__snd_timer_params_set_filter, snd_timer_params_set_filter, ALSA_0.9.0); + +/** + * \brief get timer event filter + * \param params pointer to #snd_timer_params_t structure + * \return timer event filter + */ +#ifndef DOXYGEN +unsigned int INTERNAL(snd_timer_params_get_filter)(snd_timer_params_t * params) +#else +unsigned int snd_timer_params_get_filter(snd_timer_params_t * params) +#endif +{ + assert(params); + return params->filter; +} +use_default_symbol_version(__snd_timer_params_get_filter, snd_timer_params_get_filter, ALSA_0.9.0); + +/** + * \brief set parameters for timer handle + * \param timer timer handle + * \param params pointer to a #snd_timer_params_t structure + * \return 0 on success otherwise a negative error code + */ +int snd_timer_params(snd_timer_t *timer, snd_timer_params_t * params) +{ + assert(timer); + assert(params); + return timer->ops->params(timer, params); +} + +/** + * \brief get size of the snd_timer_status_t structure in bytes + * \return size of the snd_timer_status_t structure in bytes + */ +size_t snd_timer_status_sizeof() +{ + return sizeof(snd_timer_status_t); +} + +/** + * \brief allocate a new snd_timer_status_t structure + * \param status returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_timer_status_t structure using the standard + * malloc C library function. + */ +int snd_timer_status_malloc(snd_timer_status_t **status) +{ + assert(status); + *status = calloc(1, sizeof(snd_timer_status_t)); + if (!*status) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_timer_status_t structure + * \param status pointer to the snd_timer_status_t structure to free + * + * Frees the given snd_timer_status_t structure using the standard + * free C library function. + */ +void snd_timer_status_free(snd_timer_status_t *status) +{ + assert(status); + free(status); +} + +/** + * \brief copy one snd_timer_status_t structure to another + * \param dst destination snd_timer_status_t structure + * \param src source snd_timer_status_t structure + */ +void snd_timer_status_copy(snd_timer_status_t *dst, const snd_timer_status_t *src) +{ + assert(dst && src); + *dst = *src; +} + + + +/** + * \brief get timestamp + * \param status pointer to #snd_timer_status_t structure + * \return timestamp + */ +snd_htimestamp_t snd_timer_status_get_timestamp(snd_timer_status_t * status) +{ + assert(status); + return status->tstamp; +} + +/** + * \brief get resolution in us + * \param status pointer to #snd_timer_status_t structure + * \return resolution + */ +long snd_timer_status_get_resolution(snd_timer_status_t * status) +{ + assert(status); + return status->resolution; +} + +/** + * \brief get master tick lost count + * \param status pointer to #snd_timer_status_t structure + * \return master tick lost count + */ +long snd_timer_status_get_lost(snd_timer_status_t * status) +{ + assert(status); + return status->lost; +} + +/** + * \brief get overrun count + * \param status pointer to #snd_timer_status_t structure + * \return overrun count + */ +long snd_timer_status_get_overrun(snd_timer_status_t * status) +{ + assert(status); + return status->overrun; +} + +/** + * \brief get count of used queue elements + * \param status pointer to #snd_timer_status_t structure + * \return count of used queue elements + */ +long snd_timer_status_get_queue(snd_timer_status_t * status) +{ + assert(status); + return status->queue; +} + +/** + * \brief get status from timer handle + * \param timer timer handle + * \param status pointer to a #snd_timer_status_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int snd_timer_status(snd_timer_t *timer, snd_timer_status_t * status) +{ + assert(timer); + assert(status); + return timer->ops->status(timer, status); +} + +/** + * \brief start the timer + * \param timer timer handle + * \return 0 on success otherwise a negative error code + */ +int snd_timer_start(snd_timer_t *timer) +{ + assert(timer); + return timer->ops->rt_start(timer); +} + +/** + * \brief stop the timer + * \param timer timer handle + * \return 0 on success otherwise a negative error code + */ +int snd_timer_stop(snd_timer_t *timer) +{ + assert(timer); + return timer->ops->rt_stop(timer); +} + +/** + * \brief continue the timer + * \param timer timer handle + * \return 0 on success otherwise a negative error code + */ +int snd_timer_continue(snd_timer_t *timer) +{ + assert(timer); + return timer->ops->rt_continue(timer); +} + +/** + * \brief read bytes using timer handle + * \param timer timer handle + * \param buffer buffer to store the input bytes + * \param size input buffer size in bytes + */ +ssize_t snd_timer_read(snd_timer_t *timer, void *buffer, size_t size) +{ + assert(timer); + assert(((timer->mode & O_ACCMODE) == O_RDONLY) || ((timer->mode & O_ACCMODE) == O_RDWR)); + assert(buffer || size == 0); + return (timer->ops->read)(timer, buffer, size); +} + +/** + * \brief (DEPRECATED) get maximum timer ticks + * \param info pointer to #snd_timer_info_t structure + * \return maximum timer ticks + */ +long snd_timer_info_get_ticks(snd_timer_info_t * info) +{ + assert(info); + return 1; +} +#ifndef DOC_HIDDEN +link_warning(snd_timer_info_get_ticks, "Warning: snd_timer_info_get_ticks is deprecated"); +#endif diff --git a/src/timer/timer_hw.c b/src/timer/timer_hw.c new file mode 100644 index 0000000..2fae75e --- /dev/null +++ b/src/timer/timer_hw.c @@ -0,0 +1,349 @@ +/* + * Timer Interface - main file + * Copyright (c) 1998-2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "timer_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_timer_hw = ""; +#endif + +#define SNDRV_FILE_TIMER ALSA_DEVICE_DIRECTORY "timer" +#define SNDRV_TIMER_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 5) + +#define SNDRV_TIMER_IOCTL_STATUS_OLD _IOW('T', 0x14, struct sndrv_timer_status) + +enum { + SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), + SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), + SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22), + SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), +}; + +static int snd_timer_hw_close(snd_timer_t *handle) +{ + snd_timer_t *tmr = handle; + int res; + + if (!tmr) + return -EINVAL; + res = close(tmr->poll_fd) < 0 ? -errno : 0; + return res; +} + +static int snd_timer_hw_nonblock(snd_timer_t *timer, int nonblock) +{ + long flags; + assert(timer); + if ((flags = fcntl(timer->poll_fd, F_GETFL)) < 0) + return -errno; + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(timer->poll_fd, F_SETFL, flags) < 0) + return -errno; + return 0; +} + +static int snd_timer_hw_async(snd_timer_t *timer, int sig, pid_t pid) +{ + long flags; + int fd; + + assert(timer); + fd = timer->poll_fd; + if ((flags = fcntl(fd, F_GETFL)) < 0) { + SYSERR("F_GETFL failed"); + return -errno; + } + if (sig >= 0) + flags |= O_ASYNC; + else + flags &= ~O_ASYNC; + if (fcntl(fd, F_SETFL, flags) < 0) { + SYSERR("F_SETFL for O_ASYNC failed"); + return -errno; + } + if (sig < 0) + return 0; + if (fcntl(fd, F_SETSIG, (long)sig) < 0) { + SYSERR("F_SETSIG failed"); + return -errno; + } + if (fcntl(fd, F_SETOWN, (long)pid) < 0) { + SYSERR("F_SETOWN failed"); + return -errno; + } + return 0; +} + +static int snd_timer_hw_info(snd_timer_t *handle, snd_timer_info_t * info) +{ + snd_timer_t *tmr; + + tmr = handle; + if (!tmr || !info) + return -EINVAL; + if (ioctl(tmr->poll_fd, SNDRV_TIMER_IOCTL_INFO, info) < 0) + return -errno; + return 0; +} + +static int snd_timer_hw_params(snd_timer_t *handle, snd_timer_params_t * params) +{ + snd_timer_t *tmr; + + tmr = handle; + if (!tmr || !params) + return -EINVAL; + if (ioctl(tmr->poll_fd, SNDRV_TIMER_IOCTL_PARAMS, params) < 0) + return -errno; + return 0; +} + +static int snd_timer_hw_status(snd_timer_t *handle, snd_timer_status_t * status) +{ + snd_timer_t *tmr; + int cmd; + + tmr = handle; + if (!tmr || !status) + return -EINVAL; + if (tmr->version < SNDRV_PROTOCOL_VERSION(2, 0, 1)) + cmd = SNDRV_TIMER_IOCTL_STATUS_OLD; + else + cmd = SNDRV_TIMER_IOCTL_STATUS; + if (ioctl(tmr->poll_fd, cmd, status) < 0) + return -errno; + return 0; +} + +static int snd_timer_hw_start(snd_timer_t *handle) +{ + snd_timer_t *tmr; + unsigned int cmd; + + tmr = handle; + if (!tmr) + return -EINVAL; + if (tmr->version < SNDRV_PROTOCOL_VERSION(2, 0, 4)) + cmd = SNDRV_TIMER_IOCTL_START_OLD; + else + cmd = SNDRV_TIMER_IOCTL_START; + if (ioctl(tmr->poll_fd, cmd) < 0) + return -errno; + return 0; +} + +static int snd_timer_hw_stop(snd_timer_t *handle) +{ + snd_timer_t *tmr; + unsigned int cmd; + + tmr = handle; + if (!tmr) + return -EINVAL; + if (tmr->version < SNDRV_PROTOCOL_VERSION(2, 0, 4)) + cmd = SNDRV_TIMER_IOCTL_STOP_OLD; + else + cmd = SNDRV_TIMER_IOCTL_STOP; + if (ioctl(tmr->poll_fd, cmd) < 0) + return -errno; + return 0; +} + +static int snd_timer_hw_continue(snd_timer_t *handle) +{ + snd_timer_t *tmr; + unsigned int cmd; + + tmr = handle; + if (!tmr) + return -EINVAL; + if (tmr->version < SNDRV_PROTOCOL_VERSION(2, 0, 4)) + cmd = SNDRV_TIMER_IOCTL_CONTINUE_OLD; + else + cmd = SNDRV_TIMER_IOCTL_CONTINUE; + if (ioctl(tmr->poll_fd, cmd) < 0) + return -errno; + return 0; +} + +static ssize_t snd_timer_hw_read(snd_timer_t *handle, void *buffer, size_t size) +{ + snd_timer_t *tmr; + ssize_t result; + + tmr = handle; + if (!tmr || (!buffer && size > 0)) + return -EINVAL; + result = read(tmr->poll_fd, buffer, size); + if (result < 0) + return -errno; + return result; +} + +static const snd_timer_ops_t snd_timer_hw_ops = { + .close = snd_timer_hw_close, + .nonblock = snd_timer_hw_nonblock, + .async = snd_timer_hw_async, + .info = snd_timer_hw_info, + .params = snd_timer_hw_params, + .status = snd_timer_hw_status, + .rt_start = snd_timer_hw_start, + .rt_stop = snd_timer_hw_stop, + .rt_continue = snd_timer_hw_continue, + .read = snd_timer_hw_read, +}; + +int snd_timer_hw_open(snd_timer_t **handle, const char *name, int dev_class, int dev_sclass, int card, int device, int subdevice, int mode) +{ + int fd, ver, tmode, ret; + snd_timer_t *tmr; + struct sndrv_timer_select sel; + + *handle = NULL; + + tmode = O_RDONLY; + if (mode & SND_TIMER_OPEN_NONBLOCK) + tmode |= O_NONBLOCK; + fd = snd_open_device(SNDRV_FILE_TIMER, tmode); + if (fd < 0) + return -errno; + if (ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver) < 0) { + ret = -errno; + close(fd); + return ret; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_TIMER_VERSION_MAX)) { + close(fd); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } + if (mode & SND_TIMER_OPEN_TREAD) { + int arg = 1; + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 3)) { + ret = -ENOTTY; + goto __no_tread; + } + if (ioctl(fd, SNDRV_TIMER_IOCTL_TREAD, &arg) < 0) { + ret = -errno; + __no_tread: + close(fd); + SNDMSG("extended read is not supported (SNDRV_TIMER_IOCTL_TREAD)"); + return ret; + } + } + memset(&sel, 0, sizeof(sel)); + sel.id.dev_class = dev_class; + sel.id.dev_sclass = dev_sclass; + sel.id.card = card; + sel.id.device = device; + sel.id.subdevice = subdevice; + if (ioctl(fd, SNDRV_TIMER_IOCTL_SELECT, &sel) < 0) { + ret = -errno; + close(fd); + return ret; + } + tmr = (snd_timer_t *) calloc(1, sizeof(snd_timer_t)); + if (tmr == NULL) { + close(fd); + return -ENOMEM; + } + tmr->type = SND_TIMER_TYPE_HW; + tmr->version = ver; + tmr->mode = tmode; + tmr->name = strdup(name); + tmr->poll_fd = fd; + tmr->ops = &snd_timer_hw_ops; + INIT_LIST_HEAD(&tmr->async_handlers); + *handle = tmr; + return 0; +} + +int _snd_timer_hw_open(snd_timer_t **timer, char *name, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + long dev_class = SND_TIMER_CLASS_GLOBAL, dev_sclass = SND_TIMER_SCLASS_NONE; + long card = 0, device = 0, subdevice = 0; + const char *str; + int err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "class") == 0) { + err = snd_config_get_integer(n, &dev_class); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "sclass") == 0) { + err = snd_config_get_integer(n, &dev_sclass); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) + return -EINVAL; + card = snd_card_get_index(str); + if (card < 0) + return card; + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) + return err; + continue; + } + if (strcmp(id, "subdevice") == 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) + return err; + continue; + } + SNDERR("Unexpected field %s", id); + return -EINVAL; + } + if (card < 0) + return -EINVAL; + return snd_timer_hw_open(timer, name, dev_class, dev_sclass, card, device, subdevice, mode); +} +SND_DLSYM_BUILD_VERSION(_snd_timer_hw_open, SND_TIMER_DLSYM_VERSION); diff --git a/src/timer/timer_local.h b/src/timer/timer_local.h new file mode 100644 index 0000000..8040b05 --- /dev/null +++ b/src/timer/timer_local.h @@ -0,0 +1,76 @@ +/* + * Timer interface - local header file + * Copyright (c) 2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "local.h" + +#ifndef DOC_HIDDEN +typedef struct { + int (*close)(snd_timer_t *timer); + int (*nonblock)(snd_timer_t *timer, int nonblock); + int (*async)(snd_timer_t *timer, int sig, pid_t pid); + int (*info)(snd_timer_t *timer, snd_timer_info_t *info); + int (*params)(snd_timer_t *timer, snd_timer_params_t *params); + int (*status)(snd_timer_t *timer, snd_timer_status_t *status); + int (*rt_start)(snd_timer_t *timer); + int (*rt_stop)(snd_timer_t *timer); + int (*rt_continue)(snd_timer_t *timer); + ssize_t (*read)(snd_timer_t *timer, void *buffer, size_t size); +} snd_timer_ops_t; + +struct _snd_timer { + unsigned int version; + void *dl_handle; + char *name; + snd_timer_type_t type; + int mode; + int poll_fd; + const snd_timer_ops_t *ops; + void *private_data; + struct list_head async_handlers; +}; + +typedef struct { + int (*close)(snd_timer_query_t *timer); + int (*next_device)(snd_timer_query_t *timer, snd_timer_id_t *tid); + int (*info)(snd_timer_query_t *timer, snd_timer_ginfo_t *info); + int (*params)(snd_timer_query_t *timer, snd_timer_gparams_t *info); + int (*status)(snd_timer_query_t *timer, snd_timer_gstatus_t *info); +} snd_timer_query_ops_t; + +struct _snd_timer_query { + void *dl_handle; + char *name; + snd_timer_type_t type; + int mode; + int poll_fd; + const snd_timer_query_ops_t *ops; + void *private_data; +}; +#endif /* DOC_HIDDEN */ + +int snd_timer_hw_open(snd_timer_t **handle, const char *name, int dev_class, int dev_sclass, int card, int device, int subdevice, int mode); + +int snd_timer_query_hw_open(snd_timer_query_t **handle, const char *name, int mode); + +int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); diff --git a/src/timer/timer_query.c b/src/timer/timer_query.c new file mode 100644 index 0000000..50b098a --- /dev/null +++ b/src/timer/timer_query.c @@ -0,0 +1,594 @@ +/** + * \file timer/timer_query.c + * \author Jaroslav Kysela + * \date 2001 + * + * Timer Query Interface is designed to obtain identification of timers. + */ +/* + * Timer Query Interface - main file + * Copyright (c) 2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "timer_local.h" + +static int snd_timer_query_open_conf(snd_timer_query_t **timer, + const char *name, snd_config_t *timer_root, + snd_config_t *timer_conf, int mode) +{ + const char *str; + char buf[256]; + int err; + snd_config_t *conf, *type_conf = NULL; + snd_config_iterator_t i, next; + const char *id; + const char *lib = NULL, *open_name = NULL; + int (*open_func)(snd_timer_query_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL; +#ifndef PIC + extern void *snd_timer_query_open_symbols(void); +#endif + void *h = NULL; + if (snd_config_get_type(timer_conf) != SND_CONFIG_TYPE_COMPOUND) { + if (name) + SNDERR("Invalid type for TIMER %s definition", name); + else + SNDERR("Invalid type for TIMER definition"); + return -EINVAL; + } + err = snd_config_search(timer_conf, "type", &conf); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_id(conf, &id); + if (err < 0) { + SNDERR("unable to get id"); + return err; + } + err = snd_config_get_string(conf, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + err = snd_config_search_definition(timer_root, "timer_query_type", str, &type_conf); + if (err >= 0) { + if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for TIMER type %s definition", str); + err = -EINVAL; + goto _err; + } + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open_name); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto _err; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto _err; + } + } + if (!open_name) { + open_name = buf; + snprintf(buf, sizeof(buf), "_snd_timer_query_%s_open", str); + } +#ifndef PIC + snd_timer_query_open_symbols(); +#endif + h = snd_dlopen(lib, RTLD_NOW); + if (h) + open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_TIMER_QUERY_DLSYM_VERSION)); + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s", lib); + err = -ENOENT; + } else if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open_name, lib); + snd_dlclose(h); + err = -ENXIO; + } + _err: + if (type_conf) + snd_config_delete(type_conf); + if (! err) { + err = open_func(timer, name, timer_root, timer_conf, mode); + if (err < 0) + snd_dlclose(h); + else + (*timer)->dl_handle = h; + } + return err; +} + +static int snd_timer_query_open_noupdate(snd_timer_query_t **timer, snd_config_t *root, const char *name, int mode) +{ + int err; + snd_config_t *timer_conf; + err = snd_config_search_definition(root, "timer_query", name, &timer_conf); + if (err < 0) { + SNDERR("Unknown timer %s", name); + return err; + } + err = snd_timer_query_open_conf(timer, name, root, timer_conf, mode); + snd_config_delete(timer_conf); + return err; +} + +/** + * \brief Opens a new connection to the timer query interface. + * \param timer Returned handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int snd_timer_query_open(snd_timer_query_t **timer, const char *name, int mode) +{ + int err; + assert(timer && name); + err = snd_config_update(); + if (err < 0) + return err; + return snd_timer_query_open_noupdate(timer, snd_config, name, mode); +} + +/** + * \brief Opens a new connection to the timer query interface using local configuration + * \param timer Returned handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \param lconf Local configuration + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int snd_timer_query_open_lconf(snd_timer_query_t **timer, const char *name, + int mode, snd_config_t *lconf) +{ + assert(timer && name && lconf); + return snd_timer_query_open_noupdate(timer, lconf, name, mode); +} + +/** + * \brief close timer query handle + * \param timer timer handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified timer handle and frees all associated + * resources. + */ +int snd_timer_query_close(snd_timer_query_t *timer) +{ + int err; + assert(timer); + err = timer->ops->close(timer); + if (timer->dl_handle) + snd_dlclose(timer->dl_handle); + free(timer->name); + free(timer); + return err; +} + +/** + * \brief obtain the next timer identification + * \param timer timer handle + * \param tid timer identification + * \return 0 on success otherwise a negative error code + * + * if tid->dev_class is -1, then the first device is returned + * if result tid->dev_class is -1, no more devices are left + */ +int snd_timer_query_next_device(snd_timer_query_t *timer, snd_timer_id_t *tid) +{ + assert(timer); + assert(tid); + return timer->ops->next_device(timer, tid); +} + +/** + * \brief get size of the snd_timer_ginfo_t structure in bytes + * \return size of the snd_timer_ginfo_t structure in bytes + */ +size_t snd_timer_ginfo_sizeof(void) +{ + return sizeof(snd_timer_ginfo_t); +} + +/** + * \brief allocate a new snd_timer_ginfo_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_timer_info_t structure using the standard + * malloc C library function. + */ +int snd_timer_ginfo_malloc(snd_timer_ginfo_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_timer_ginfo_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_timer_ginfo_t structure + * \param info pointer to the snd_timer_ginfo_t structure to free + * + * Frees the given snd_timer_info_t structure using the standard + * free C library function. + */ +void snd_timer_ginfo_free(snd_timer_ginfo_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_timer_info_t structure to another + * \param dst destination snd_timer_info_t structure + * \param src source snd_timer_info_t structure + */ +void snd_timer_ginfo_copy(snd_timer_ginfo_t *dst, const snd_timer_ginfo_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief set timer identification + * \param obj pointer to #snd_timer_ginfo_t structure + * \param tid pointer to #snd_timer_id_t structure + * \return zero on success otherwise a negative error number + */ +int snd_timer_ginfo_set_tid(snd_timer_ginfo_t *obj, snd_timer_id_t *tid) +{ + obj->tid = *((snd_timer_id_t *)tid); + return 0; +} + +/** + * \brief get timer identification + * \param obj pointer to #snd_timer_ginfo_t structure + * \return pointer to snd_timer_id_t + */ +snd_timer_id_t *snd_timer_ginfo_get_tid(snd_timer_ginfo_t *obj) +{ + return (snd_timer_id_t *)&obj->tid; +} + +/** + * \brief get timer flags + * \param obj pointer to #snd_timer_ginfo_t structure + * \return timer flags + */ +unsigned int snd_timer_ginfo_get_flags(snd_timer_ginfo_t *obj) +{ + return obj->flags; +} + +/** + * \brief get associated card with timer + * \param obj pointer to #snd_timer_ginfo_t structure + * \return associated card + */ +int snd_timer_ginfo_get_card(snd_timer_ginfo_t *obj) +{ + return obj->card; +} + +/** + * \brief get timer identification + * \param obj pointer to #snd_timer_ginfo_t structure + * \return timer identification + */ +char *snd_timer_ginfo_get_id(snd_timer_ginfo_t *obj) +{ + return (char *)obj->id; +} + +/** + * \brief get timer name + * \param obj pointer to #snd_timer_ginfo_t structure + * \return timer name + */ +char *snd_timer_ginfo_get_name(snd_timer_ginfo_t *obj) +{ + return (char *)obj->name; +} + +/** + * \brief get timer resolution in ns + * \param obj pointer to #snd_timer_ginfo_t structure + * \return timer resolution in ns + */ +unsigned long snd_timer_ginfo_get_resolution(snd_timer_ginfo_t *obj) +{ + return obj->resolution; +} + +/** + * \brief get timer minimal resolution in ns + * \param obj pointer to #snd_timer_ginfo_t structure + * \return timer minimal resolution in ns + */ +unsigned long snd_timer_ginfo_get_resolution_min(snd_timer_ginfo_t *obj) +{ + return obj->resolution_min; +} + +/** + * \brief get timer maximal resolution in ns + * \param obj pointer to #snd_timer_ginfo_t structure + * \return timer maximal resolution in ns + */ +unsigned long snd_timer_ginfo_get_resolution_max(snd_timer_ginfo_t *obj) +{ + return obj->resolution_max; +} + +/** + * \brief get current timer clients + * \param obj pointer to #snd_timer_ginfo_t structure + * \return current timer clients + */ +unsigned int snd_timer_ginfo_get_clients(snd_timer_ginfo_t *obj) +{ + return obj->clients; +} + +/** + * \brief obtain the timer global information + * \param timer timer handle + * \param info timer information + * \return 0 on success otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_timer_query_info)(snd_timer_query_t *timer, snd_timer_ginfo_t *info) +#else +int snd_timer_query_info(snd_timer_query_t *timer, snd_timer_ginfo_t *info) +#endif +{ + assert(timer); + assert(info); + return timer->ops->info(timer, info); +} +use_default_symbol_version(__snd_timer_query_info, snd_timer_query_info, ALSA_0.9.0); + +/** + * \brief set the timer global parameters + * \param timer timer handle + * \param params timer parameters + * \return 0 on success otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_timer_query_params)(snd_timer_query_t *timer, snd_timer_gparams_t *params) +#else +int snd_timer_query_params(snd_timer_query_t *timer, snd_timer_gparams_t *params) +#endif +{ + assert(timer); + assert(params); + return timer->ops->params(timer, params); +} +use_default_symbol_version(__snd_timer_query_params, snd_timer_query_params, ALSA_0.9.0); + +/** + * \brief get the timer global status + * \param timer timer handle + * \param status timer status + * \return 0 on success otherwise a negative error code + */ +#ifndef DOXYGEN +int INTERNAL(snd_timer_query_status)(snd_timer_query_t *timer, snd_timer_gstatus_t *status) +#else +int snd_timer_query_status(snd_timer_query_t *timer, snd_timer_gstatus_t *status) +#endif +{ + assert(timer); + assert(status); + return timer->ops->status(timer, status); +} +use_default_symbol_version(__snd_timer_query_status, snd_timer_query_status, ALSA_0.9.0); + +/** + * \brief get size of the snd_timer_id_t structure in bytes + * \return size of the snd_timer_id_t structure in bytes + */ +size_t snd_timer_id_sizeof() +{ + return sizeof(snd_timer_id_t); +} + +/** + * \brief allocate a new snd_timer_id_t structure + * \param info returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_timer_id_t structure using the standard + * malloc C library function. + */ +int snd_timer_id_malloc(snd_timer_id_t **info) +{ + assert(info); + *info = calloc(1, sizeof(snd_timer_id_t)); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_timer_id_t structure + * \param info pointer to the snd_timer_id_t structure to free + * + * Frees the given snd_timer_id_t structure using the standard + * free C library function. + */ +void snd_timer_id_free(snd_timer_id_t *info) +{ + assert(info); + free(info); +} + +/** + * \brief copy one snd_timer_id_t structure to another + * \param dst destination snd_timer_id_t structure + * \param src source snd_timer_id_t structure + */ +void snd_timer_id_copy(snd_timer_id_t *dst, const snd_timer_id_t *src) +{ + assert(dst && src); + *dst = *src; +} + +/** + * \brief set timer class + * \param tid pointer to #snd_timer_id_t structure + * \param dev_class class of timer device + */ +void snd_timer_id_set_class(snd_timer_id_t * tid, int dev_class) +{ + assert(tid); + tid->dev_class = dev_class; +} + +/** + * \brief get timer class + * \param tid pointer to #snd_timer_id_t structure + * \return timer class + */ +int snd_timer_id_get_class(snd_timer_id_t * tid) +{ + assert(tid); + return tid->dev_class; +} + +/** + * \brief set timer sub-class + * \param tid pointer to #snd_timer_id_t structure + * \param dev_sclass sub-class of timer device + */ +void snd_timer_id_set_sclass(snd_timer_id_t * tid, int dev_sclass) +{ + assert(tid); + tid->dev_sclass = dev_sclass; +} + +/** + * \brief get timer sub-class + * \param tid pointer to #snd_timer_id_t structure + * \return timer sub-class + */ +int snd_timer_id_get_sclass(snd_timer_id_t * tid) +{ + assert(tid); + return tid->dev_sclass; +} + +/** + * \brief set timer card + * \param tid pointer to #snd_timer_id_t structure + * \param card card number + */ +void snd_timer_id_set_card(snd_timer_id_t * tid, int card) +{ + assert(tid); + tid->card = card; +} + +/** + * \brief get timer card + * \param tid pointer to #snd_timer_id_t structure + * \return timer card number + */ +int snd_timer_id_get_card(snd_timer_id_t * tid) +{ + assert(tid); + return tid->card; +} + +/** + * \brief set timer device + * \param tid pointer to #snd_timer_id_t structure + * \param device device number + */ +void snd_timer_id_set_device(snd_timer_id_t * tid, int device) +{ + assert(tid); + tid->device = device; +} + +/** + * \brief get timer device + * \param tid pointer to #snd_timer_id_t structure + * \return timer device number + */ +int snd_timer_id_get_device(snd_timer_id_t * tid) +{ + assert(tid); + return tid->device; +} + +/** + * \brief set timer subdevice + * \param tid pointer to #snd_timer_id_t structure + * \param subdevice subdevice number + */ +void snd_timer_id_set_subdevice(snd_timer_id_t * tid, int subdevice) +{ + assert(tid); + tid->subdevice = subdevice; +} + +/** + * \brief get timer subdevice + * \param tid pointer to #snd_timer_id_t structure + * \return timer subdevice number + */ +int snd_timer_id_get_subdevice(snd_timer_id_t * tid) +{ + assert(tid); + return tid->subdevice; +} diff --git a/src/timer/timer_query_hw.c b/src/timer/timer_query_hw.c new file mode 100644 index 0000000..9f62b78 --- /dev/null +++ b/src/timer/timer_query_hw.c @@ -0,0 +1,146 @@ +/* + * Timer Interface - main file + * Copyright (c) 1998-2001 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "timer_local.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_timer_query_hw = ""; +#endif + +#define SNDRV_FILE_TIMER ALSA_DEVICE_DIRECTORY "timer" +#define SNDRV_TIMER_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 0) + +static int snd_timer_query_hw_close(snd_timer_query_t *handle) +{ + int res; + + if (!handle) + return -EINVAL; + res = close(handle->poll_fd) < 0 ? -errno : 0; + return res; +} + +static int snd_timer_query_hw_next_device(snd_timer_query_t *handle, snd_timer_id_t * tid) +{ + if (!handle || !tid) + return -EINVAL; + if (ioctl(handle->poll_fd, SNDRV_TIMER_IOCTL_NEXT_DEVICE, tid) < 0) + return -errno; + return 0; +} + +static int snd_timer_query_hw_info(snd_timer_query_t *handle, snd_timer_ginfo_t *info) +{ + if (!handle || !info) + return -EINVAL; + if (ioctl(handle->poll_fd, SNDRV_TIMER_IOCTL_GINFO, info) < 0) + return -errno; + return 0; +} + +static int snd_timer_query_hw_params(snd_timer_query_t *handle, snd_timer_gparams_t *params) +{ + if (!handle || !params) + return -EINVAL; + if (ioctl(handle->poll_fd, SNDRV_TIMER_IOCTL_GPARAMS, params) < 0) + return -errno; + return 0; +} + +static int snd_timer_query_hw_status(snd_timer_query_t *handle, snd_timer_gstatus_t *status) +{ + if (!handle || !status) + return -EINVAL; + if (ioctl(handle->poll_fd, SNDRV_TIMER_IOCTL_GSTATUS, status) < 0) + return -errno; + return 0; +} + +static const snd_timer_query_ops_t snd_timer_query_hw_ops = { + .close = snd_timer_query_hw_close, + .next_device = snd_timer_query_hw_next_device, + .info = snd_timer_query_hw_info, + .params = snd_timer_query_hw_params, + .status = snd_timer_query_hw_status +}; + +int snd_timer_query_hw_open(snd_timer_query_t **handle, const char *name, int mode) +{ + int fd, ver, tmode; + snd_timer_query_t *tmr; + + *handle = NULL; + + tmode = O_RDONLY; + if (mode & SND_TIMER_OPEN_NONBLOCK) + tmode |= O_NONBLOCK; + fd = snd_open_device(SNDRV_FILE_TIMER, tmode); + if (fd < 0) + return -errno; + if (ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver) < 0) { + close(fd); + return -errno; + } + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_TIMER_VERSION_MAX)) { + close(fd); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } + tmr = (snd_timer_query_t *) calloc(1, sizeof(snd_timer_t)); + if (tmr == NULL) { + close(fd); + return -ENOMEM; + } + tmr->type = SND_TIMER_TYPE_HW; + tmr->mode = tmode; + tmr->name = strdup(name); + tmr->poll_fd = fd; + tmr->ops = &snd_timer_query_hw_ops; + *handle = tmr; + return 0; +} + +int _snd_timer_query_hw_open(snd_timer_query_t **timer, char *name, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, int mode) +{ + snd_config_iterator_t i, next; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + SNDERR("Unexpected field %s", id); + return -EINVAL; + } + return snd_timer_query_hw_open(timer, name, mode); +} +SND_DLSYM_BUILD_VERSION(_snd_timer_query_hw_open, SND_TIMER_QUERY_DLSYM_VERSION); diff --git a/src/timer/timer_symbols.c b/src/timer/timer_symbols.c new file mode 100644 index 0000000..797721e --- /dev/null +++ b/src/timer/timer_symbols.c @@ -0,0 +1,46 @@ +/* + * Timer Symbols + * Copyright (c) 2001 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +extern const char *_snd_module_timer_hw; + +static const char **snd_timer_open_objects[] = { + &_snd_module_timer_hw +}; + +void *snd_timer_open_symbols(void) +{ + return (void *)snd_timer_open_objects[0]; +} + + +extern const char *_snd_module_timer_query_hw; + +static const char **snd_timer_query_open_objects[] = { + &_snd_module_timer_query_hw +}; + +void *snd_timer_query_open_symbols(void) +{ + return snd_timer_query_open_objects; +} + +#endif /* !PIC */ diff --git a/src/ucm/Makefile.am b/src/ucm/Makefile.am new file mode 100644 index 0000000..7435d90 --- /dev/null +++ b/src/ucm/Makefile.am @@ -0,0 +1,10 @@ +EXTRA_LTLIBRARIES = libucm.la + +libucm_la_SOURCES = utils.c parser.c main.c + +noinst_HEADERS = ucm_local.h + +all: libucm.la + + +INCLUDES=-I$(top_srcdir)/include diff --git a/src/ucm/Makefile.in b/src/ucm/Makefile.in new file mode 100644 index 0000000..9e7f15f --- /dev/null +++ b/src/ucm/Makefile.in @@ -0,0 +1,499 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/ucm +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libucm_la_LIBADD = +am_libucm_la_OBJECTS = utils.lo parser.lo main.lo +libucm_la_OBJECTS = $(am_libucm_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libucm_la_SOURCES) +DIST_SOURCES = $(libucm_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_NOUNDEFINED = @LDFLAGS_NOUNDEFINED@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_LTLIBRARIES = libucm.la +libucm_la_SOURCES = utils.c parser.c main.c +noinst_HEADERS = ucm_local.h +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/ucm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/ucm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libucm.la: $(libucm_la_OBJECTS) $(libucm_la_DEPENDENCIES) $(EXTRA_libucm_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libucm_la_OBJECTS) $(libucm_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +all: libucm.la + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/ucm/libucm.la b/src/ucm/libucm.la new file mode 100644 index 0000000..250a5a7 --- /dev/null +++ b/src/ucm/libucm.la @@ -0,0 +1,41 @@ +# libucm.la - a libtool library file +# Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='' + +# Names of this library. +library_names='' + +# The name of the static archive. +old_library='libucm.a' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='' + +# Libraries that this one depends upon. +dependency_libs='' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libucm. +current= +age= +revision= + +# Is this an already installed library? +installed=no + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='' diff --git a/src/ucm/main.c b/src/ucm/main.c new file mode 100644 index 0000000..76ca151 --- /dev/null +++ b/src/ucm/main.c @@ -0,0 +1,1649 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Support for the verb/device/modifier core logic and API, + * command line tool and file parser was kindly sponsored by + * Texas Instruments Inc. + * Support for multiple active modifiers and devices, + * transition sequences, multiple client access and user defined use + * cases was kindly sponsored by Wolfson Microelectronics PLC. + * + * Copyright (C) 2008-2010 SlimLogic Ltd + * Copyright (C) 2010 Wolfson Microelectronics PLC + * Copyright (C) 2010 Texas Instruments Inc. + * Copyright (C) 2010 Red Hat Inc. + * Authors: Liam Girdwood + * Stefan Schmidt + * Justin Xu + * Jaroslav Kysela + */ + +#include "ucm_local.h" +#include +#include + +/* + * misc + */ + +static int get_value1(const char **value, struct list_head *value_list, + const char *identifier); +static int get_value3(const char **value, + const char *identifier, + struct list_head *value_list1, + struct list_head *value_list2, + struct list_head *value_list3); + +static int check_identifier(const char *identifier, const char *prefix) +{ + int len; + + if (strcmp(identifier, prefix) == 0) + return 1; + len = strlen(prefix); + if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/') + return 1; + return 0; +} + +static int list_count(struct list_head *list) +{ + struct list_head *pos; + int count = 0; + + list_for_each(pos, list) { + count += 1; + } + return count; +} + +static int alloc_str_list(struct list_head *list, int mult, char **result[]) +{ + char **res; + int cnt; + + cnt = list_count(list) * mult; + if (cnt == 0) { + *result = NULL; + return cnt; + } + res = calloc(mult, cnt * sizeof(char *)); + if (res == NULL) + return -ENOMEM; + *result = res; + return cnt; +} + +/** + * \brief Create an identifier + * \param fmt Format (sprintf like) + * \param ... Optional arguments for sprintf like format + * \return Allocated string identifier or NULL on error + */ +char *snd_use_case_identifier(const char *fmt, ...) +{ + char *str, *res; + int size = strlen(fmt) + 512; + va_list args; + + str = malloc(size); + if (str == NULL) + return NULL; + va_start(args, fmt); + vsnprintf(str, size, fmt, args); + va_end(args); + str[size-1] = '\0'; + res = realloc(str, strlen(str) + 1); + if (res) + return res; + return str; +} + +/** + * \brief Free a string list + * \param list The string list to free + * \param items Count of strings + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_free_list(const char *list[], int items) +{ + int i; + if (list == NULL) + return 0; + for (i = 0; i < items; i++) + free((void *)list[i]); + free(list); + return 0; +} + +static int open_ctl(snd_use_case_mgr_t *uc_mgr, + snd_ctl_t **ctl, + const char *ctl_dev) +{ + int err; + + /* FIXME: add a list of ctl devices to uc_mgr structure and + cache accesses for multiple opened ctl devices */ + if (uc_mgr->ctl_dev != NULL && strcmp(ctl_dev, uc_mgr->ctl_dev) == 0) { + *ctl = uc_mgr->ctl; + return 0; + } + if (uc_mgr->ctl_dev) { + free(uc_mgr->ctl_dev); + uc_mgr->ctl_dev = NULL; + snd_ctl_close(uc_mgr->ctl); + + } + err = snd_ctl_open(ctl, ctl_dev, 0); + if (err < 0) + return err; + uc_mgr->ctl_dev = strdup(ctl_dev); + if (uc_mgr->ctl_dev == NULL) { + snd_ctl_close(*ctl); + return -ENOMEM; + } + uc_mgr->ctl = *ctl; + return 0; +} + +static int execute_cset(snd_ctl_t *ctl, char *cset) +{ + char *pos; + int err; + snd_ctl_elem_id_t *id; + snd_ctl_elem_value_t *value; + snd_ctl_elem_info_t *info; + + snd_ctl_elem_id_malloc(&id); + snd_ctl_elem_value_malloc(&value); + snd_ctl_elem_info_malloc(&info); + + pos = strrchr(cset, ' '); + if (pos == NULL) { + uc_error("undefined value for cset >%s<", cset); + err = -EINVAL; + goto __fail; + } + *pos = '\0'; + err = snd_ctl_ascii_elem_id_parse(id, cset); + if (err < 0) + goto __fail; + snd_ctl_elem_value_set_id(value, id); + snd_ctl_elem_info_set_id(info, id); + err = snd_ctl_elem_read(ctl, value); + if (err < 0) + goto __fail; + err = snd_ctl_elem_info(ctl, info); + if (err < 0) + goto __fail; + err = snd_ctl_ascii_value_parse(ctl, value, info, pos + 1); + if (err < 0) + goto __fail; + err = snd_ctl_elem_write(ctl, value); + if (err < 0) + goto __fail; + err = 0; + __fail: + if (pos != NULL) + *pos = ' '; + + if (id != NULL) + free(id); + if (value != NULL) + free(value); + if (info != NULL) + free(info); + + return err; +} + +/** + * \brief Execute the sequence + * \param uc_mgr Use case manager + * \param seq Sequence + * \return zero on success, otherwise a negative error code + */ +static int execute_sequence(snd_use_case_mgr_t *uc_mgr, + struct list_head *seq, + struct list_head *value_list1, + struct list_head *value_list2, + struct list_head *value_list3) +{ + struct list_head *pos; + struct sequence_element *s; + char *cdev = NULL; + snd_ctl_t *ctl = NULL; + int err = 0; + + list_for_each(pos, seq) { + s = list_entry(pos, struct sequence_element, list); + switch (s->type) { + case SEQUENCE_ELEMENT_TYPE_CDEV: + cdev = strdup(s->data.cdev); + if (cdev == NULL) + goto __fail_nomem; + break; + case SEQUENCE_ELEMENT_TYPE_CSET: + if (cdev == NULL) { + const char *cdev1 = NULL, *cdev2 = NULL; + err = get_value3(&cdev1, "PlaybackCTL", + value_list1, + value_list2, + value_list3); + if (err < 0 && err != ENOENT) { + uc_error("cdev is not defined!"); + return err; + } + err = get_value3(&cdev1, "CaptureCTL", + value_list1, + value_list2, + value_list3); + if (err < 0 && err != ENOENT) { + free((char *)cdev1); + uc_error("cdev is not defined!"); + return err; + } + if (cdev1 == NULL || cdev2 == NULL || + strcmp(cdev1, cdev2) == 0) { + cdev = (char *)cdev1; + free((char *)cdev2); + } else { + free((char *)cdev1); + free((char *)cdev2); + } + } + if (ctl == NULL) { + err = open_ctl(uc_mgr, &ctl, cdev); + if (err < 0) { + uc_error("unable to open ctl device '%s'", cdev); + goto __fail; + } + } + err = execute_cset(ctl, s->data.cset); + if (err < 0) { + uc_error("unable to execute cset '%s'\n", s->data.cset); + goto __fail; + } + break; + case SEQUENCE_ELEMENT_TYPE_SLEEP: + usleep(s->data.sleep); + break; + case SEQUENCE_ELEMENT_TYPE_EXEC: + err = system(s->data.exec); + if (err < 0) + goto __fail; + break; + default: + uc_error("unknown sequence command %i", s->type); + break; + } + } + free(cdev); + return 0; + __fail_nomem: + err = -ENOMEM; + __fail: + free(cdev); + return err; + +} + +/** + * \brief Import master config and execute the default sequence + * \param uc_mgr Use case manager + * \return zero on success, otherwise a negative error code + */ +static int import_master_config(snd_use_case_mgr_t *uc_mgr) +{ + int err; + + err = uc_mgr_import_master_config(uc_mgr); + if (err < 0) + return err; + err = execute_sequence(uc_mgr, &uc_mgr->default_list, + &uc_mgr->value_list, NULL, NULL); + if (err < 0) + uc_error("Unable to execute default sequence"); + return err; +} + +/** + * \brief Universal find - string in a list + * \param list List of structures + * \param offset Offset of list structure + * \param soffset Offset of string structure + * \param match String to match + * \return structure on success, otherwise a NULL (not found) + */ +static void *find0(struct list_head *list, + unsigned long offset, + unsigned long soffset, + const char *match) +{ + struct list_head *pos; + char *ptr, *str; + + list_for_each(pos, list) { + ptr = list_entry_offset(pos, char, offset); + str = *((char **)(ptr + soffset)); + if (strcmp(str, match) == 0) + return ptr; + } + return NULL; +} + +#define find(list, type, member, value, match) \ + find0(list, (unsigned long)(&((type *)0)->member), \ + (unsigned long)(&((type *)0)->value), match) + +/** + * \brief Universal string list + * \param list List of structures + * \param result Result list + * \param offset Offset of list structure + * \param s1offset Offset of string structure + * \return count of items on success, otherwise a negative error code + */ +static int get_list0(struct list_head *list, + const char **result[], + unsigned long offset, + unsigned long s1offset) +{ + char **res; + int cnt; + struct list_head *pos; + char *ptr, *str1; + + cnt = alloc_str_list(list, 1, &res); + if (cnt <= 0) + return cnt; + *result = (const char **)res; + list_for_each(pos, list) { + ptr = list_entry_offset(pos, char, offset); + str1 = *((char **)(ptr + s1offset)); + if (str1 != NULL) { + *res = strdup(str1); + if (*res == NULL) + goto __fail; + } else { + *res = NULL; + } + res++; + } + return cnt; + __fail: + snd_use_case_free_list((const char **)res, cnt); + return -ENOMEM; +} + +#define get_list(list, result, type, member, s1) \ + get_list0(list, result, \ + (unsigned long)(&((type *)0)->member), \ + (unsigned long)(&((type *)0)->s1)) + +/** + * \brief Universal string list - pair of strings + * \param list List of structures + * \param result Result list + * \param offset Offset of list structure + * \param s1offset Offset of string structure + * \param s1offset Offset of string structure + * \return count of items on success, otherwise a negative error code + */ +static int get_list20(struct list_head *list, + const char **result[], + unsigned long offset, + unsigned long s1offset, + unsigned long s2offset) +{ + char **res; + int cnt; + struct list_head *pos; + char *ptr, *str1, *str2; + + cnt = alloc_str_list(list, 2, &res); + if (cnt <= 0) + return cnt; + *result = (const char **)res; + list_for_each(pos, list) { + ptr = list_entry_offset(pos, char, offset); + str1 = *((char **)(ptr + s1offset)); + if (str1 != NULL) { + *res = strdup(str1); + if (*res == NULL) + goto __fail; + } else { + *res = NULL; + } + res++; + str2 = *((char **)(ptr + s2offset)); + if (str2 != NULL) { + *res = strdup(str2); + if (*res == NULL) + goto __fail; + } else { + *res = NULL; + } + res++; + } + return cnt; + __fail: + snd_use_case_free_list((const char **)res, cnt); + return -ENOMEM; +} + +#define get_list2(list, result, type, member, s1, s2) \ + get_list20(list, result, \ + (unsigned long)(&((type *)0)->member), \ + (unsigned long)(&((type *)0)->s1), \ + (unsigned long)(&((type *)0)->s2)) + +/** + * \brief Find verb + * \param uc_mgr Use case manager + * \param verb_name verb to find + * \return structure on success, otherwise a NULL (not found) + */ +static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr, + const char *verb_name) +{ + return find(&uc_mgr->verb_list, + struct use_case_verb, list, name, + verb_name); +} + +static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, + struct dev_list *dev_list) +{ + struct dev_list_node *device; + struct use_case_device *adev; + struct list_head *pos, *pos1; + int found_ret; + + switch (dev_list->type) { + case DEVLIST_NONE: + default: + return 1; + case DEVLIST_SUPPORTED: + found_ret = 1; + break; + case DEVLIST_CONFLICTING: + found_ret = 0; + break; + } + + list_for_each(pos, &dev_list->list) { + device = list_entry(pos, struct dev_list_node, list); + + list_for_each(pos1, &uc_mgr->active_devices) { + adev = list_entry(pos1, struct use_case_device, + active_list); + if (!strcmp(device->name, adev->name)) + return found_ret; + } + } + return 1 - found_ret; +} + +static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr, + struct use_case_modifier *modifier) +{ + return is_devlist_supported(uc_mgr, &modifier->dev_list); +} + +static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr, + struct use_case_device *device) +{ + return is_devlist_supported(uc_mgr, &device->dev_list); +} + +/** + * \brief Find device + * \param verb Use case verb + * \param device_name device to find + * \return structure on success, otherwise a NULL (not found) + */ +static inline struct use_case_device * + find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, + const char *device_name, int check_supported) +{ + struct use_case_device *device; + struct list_head *pos; + + list_for_each(pos, &verb->device_list) { + device = list_entry(pos, struct use_case_device, list); + + if (strcmp(device_name, device->name)) + continue; + + if (check_supported && + !is_device_supported(uc_mgr, device)) + continue; + + return device; + } + return NULL; +} + +/** + * \brief Find modifier + * \param verb Use case verb + * \param modifier_name modifier to find + * \return structure on success, otherwise a NULL (not found) + */ +static struct use_case_modifier * + find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, + const char *modifier_name, int check_supported) +{ + struct use_case_modifier *modifier; + struct list_head *pos; + + list_for_each(pos, &verb->modifier_list) { + modifier = list_entry(pos, struct use_case_modifier, list); + + if (strcmp(modifier->name, modifier_name)) + continue; + + if (check_supported && + !is_modifier_supported(uc_mgr, modifier)) + continue; + + return modifier; + } + return NULL; +} + +/** + * \brief Set verb + * \param uc_mgr Use case manager + * \param verb verb to set + * \param enable nonzero = enable, zero = disable + * \return zero on success, otherwise a negative error code + */ +static int set_verb(snd_use_case_mgr_t *uc_mgr, + struct use_case_verb *verb, + int enable) +{ + struct list_head *seq; + int err; + + if (enable) { + seq = &verb->enable_list; + } else { + seq = &verb->disable_list; + } + err = execute_sequence(uc_mgr, seq, + &verb->value_list, + &uc_mgr->value_list, + NULL); + if (enable && err >= 0) + uc_mgr->active_verb = verb; + return err; +} + +/** + * \brief Set modifier + * \param uc_mgr Use case manager + * \param modifier modifier to set + * \param enable nonzero = enable, zero = disable + * \return zero on success, otherwise a negative error code + */ +static int set_modifier(snd_use_case_mgr_t *uc_mgr, + struct use_case_modifier *modifier, + int enable) +{ + struct list_head *seq; + int err; + + if (enable) { + seq = &modifier->enable_list; + } else { + seq = &modifier->disable_list; + } + err = execute_sequence(uc_mgr, seq, + &modifier->value_list, + &uc_mgr->active_verb->value_list, + &uc_mgr->value_list); + if (enable && err >= 0) { + list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers); + } else if (!enable) { + list_del(&modifier->active_list); + } + return err; +} + +/** + * \brief Set device + * \param uc_mgr Use case manager + * \param device device to set + * \param enable nonzero = enable, zero = disable + * \return zero on success, otherwise a negative error code + */ +static int set_device(snd_use_case_mgr_t *uc_mgr, + struct use_case_device *device, + int enable) +{ + struct list_head *seq; + int err; + + if (enable) { + seq = &device->enable_list; + } else { + seq = &device->disable_list; + } + err = execute_sequence(uc_mgr, seq, + &device->value_list, + &uc_mgr->active_verb->value_list, + &uc_mgr->value_list); + if (enable && err >= 0) { + list_add_tail(&device->active_list, &uc_mgr->active_devices); + } else if (!enable) { + list_del(&device->active_list); + } + return err; +} + +/** + * \brief Init sound card use case manager. + * \param uc_mgr Returned use case manager pointer + * \param card_name name of card to open + * \return zero on success, otherwise a negative error code + */ +int snd_use_case_mgr_open(snd_use_case_mgr_t **mgr, + const char *card_name) +{ + snd_use_case_mgr_t *uc_mgr; + int err; + + /* create a new UCM */ + uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t)); + if (uc_mgr == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&uc_mgr->verb_list); + INIT_LIST_HEAD(&uc_mgr->default_list); + INIT_LIST_HEAD(&uc_mgr->value_list); + INIT_LIST_HEAD(&uc_mgr->active_modifiers); + INIT_LIST_HEAD(&uc_mgr->active_devices); + pthread_mutex_init(&uc_mgr->mutex, NULL); + + uc_mgr->card_name = strdup(card_name); + if (uc_mgr->card_name == NULL) { + free(uc_mgr); + return -ENOMEM; + } + + /* get info on use_cases and verify against card */ + err = import_master_config(uc_mgr); + if (err < 0) { + uc_error("error: failed to import %s use case configuration %d", + card_name, err); + goto err; + } + + *mgr = uc_mgr; + return 0; + +err: + uc_mgr_free(uc_mgr); + return err; +} + +/** + * \brief Reload and reparse all use case files. + * \param uc_mgr Use case manager + * \return zero on success, otherwise a negative error code + */ +int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) +{ + int err; + + pthread_mutex_lock(&uc_mgr->mutex); + + uc_mgr_free_verb(uc_mgr); + + /* reload all use cases */ + err = import_master_config(uc_mgr); + if (err < 0) { + uc_error("error: failed to reload use cases\n"); + pthread_mutex_unlock(&uc_mgr->mutex); + return -EINVAL; + } + + pthread_mutex_unlock(&uc_mgr->mutex); + return err; +} + +/** + * \brief Close use case manager. + * \param uc_mgr Use case manager + * \return zero on success, otherwise a negative error code + */ +int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr) +{ + uc_mgr_free(uc_mgr); + + return 0; +} + +/* + * Tear down current use case verb, device and modifier. + */ +static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr) +{ + struct list_head *pos, *npos; + struct use_case_modifier *modifier; + struct use_case_device *device; + int err; + + list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) { + modifier = list_entry(pos, struct use_case_modifier, + active_list); + err = set_modifier(uc_mgr, modifier, 0); + if (err < 0) + uc_error("Unable to disable modifier %s", modifier->name); + } + INIT_LIST_HEAD(&uc_mgr->active_modifiers); + + list_for_each_safe(pos, npos, &uc_mgr->active_devices) { + device = list_entry(pos, struct use_case_device, + active_list); + err = set_device(uc_mgr, device, 0); + if (err < 0) + uc_error("Unable to disable device %s", device->name); + } + INIT_LIST_HEAD(&uc_mgr->active_devices); + + err = set_verb(uc_mgr, uc_mgr->active_verb, 0); + if (err < 0) { + uc_error("Unable to disable verb %s", uc_mgr->active_verb->name); + return err; + } + uc_mgr->active_verb = NULL; + + err = execute_sequence(uc_mgr, &uc_mgr->default_list, + &uc_mgr->value_list, NULL, NULL); + + return err; +} + +/** + * \brief Reset sound card controls to default values. + * \param uc_mgr Use case manager + * \return zero on success, otherwise a negative error code + */ +int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr) +{ + int err; + + pthread_mutex_lock(&uc_mgr->mutex); + err = execute_sequence(uc_mgr, &uc_mgr->default_list, + &uc_mgr->value_list, NULL, NULL); + INIT_LIST_HEAD(&uc_mgr->active_modifiers); + INIT_LIST_HEAD(&uc_mgr->active_devices); + uc_mgr->active_verb = NULL; + pthread_mutex_unlock(&uc_mgr->mutex); + return err; +} + +/** + * \brief Get list of verbs in pair verbname+comment + * \param list Returned list + * \param verbname For verb (NULL = current) + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[]) +{ + return get_list2(&uc_mgr->verb_list, list, + struct use_case_verb, list, + name, comment); +} + +/** + * \brief Get list of devices in pair devicename+comment + * \param list Returned list + * \param verbname For verb (NULL = current) + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[], + char *verbname) +{ + struct use_case_verb *verb; + + if (verbname) { + verb = find_verb(uc_mgr, verbname); + } else { + verb = uc_mgr->active_verb; + } + if (verb == NULL) + return -ENOENT; + return get_list2(&verb->device_list, list, + struct use_case_device, list, + name, comment); +} + +/** + * \brief Get list of modifiers in pair devicename+comment + * \param list Returned list + * \param verbname For verb (NULL = current) + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[], + char *verbname) +{ + struct use_case_verb *verb; + + if (verbname) { + verb = find_verb(uc_mgr, verbname); + } else { + verb = uc_mgr->active_verb; + } + if (verb == NULL) + return -ENOENT; + return get_list2(&verb->modifier_list, list, + struct use_case_modifier, list, + name, comment); +} + +/** + * \brief Get list of supported/conflicting devices + * \param list Returned list + * \param name Name of modifier or verb to query + * \param type Type of device list entries to return + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, + const char **list[], char *name, + enum dev_list_type type) +{ + char *str; + struct use_case_verb *verb; + struct use_case_modifier *modifier; + struct use_case_device *device; + + if (!name) + return -ENOENT; + + str = strchr(name, '/'); + if (str) { + *str = '\0'; + verb = find_verb(uc_mgr, str + 1); + } + else { + verb = uc_mgr->active_verb; + } + if (!verb) + return -ENOENT; + + modifier = find_modifier(uc_mgr, verb, name, 0); + if (modifier) { + if (modifier->dev_list.type != type) + return 0; + return get_list(&modifier->dev_list.list, list, + struct dev_list_node, list, + name); + } + + device = find_device(uc_mgr, verb, name, 0); + if (device) { + if (device->dev_list.type != type) + return 0; + return get_list(&device->dev_list.list, list, + struct dev_list_node, list, + name); + } + + return -ENOENT; + +} + +/** + * \brief Get list of supported devices + * \param list Returned list + * \param name Name of verb or modifier to query + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr, + const char **list[], char *name) +{ + return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED); +} + +/** + * \brief Get list of conflicting devices + * \param list Returned list + * \param name Name of verb or modifier to query + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr, + const char **list[], char *name) +{ + return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING); +} + +struct myvalue { + struct list_head list; + char *value; +}; + +static int add_values(struct list_head *list, + const char *identifier, + struct list_head *source) +{ + struct ucm_value *v; + struct myvalue *val; + struct list_head *pos, *pos1; + int match; + + list_for_each(pos, source) { + v = list_entry(pos, struct ucm_value, list); + if (check_identifier(identifier, v->name)) { + match = 0; + list_for_each(pos1, list) { + val = list_entry(pos1, struct myvalue, list); + if (strcmp(val->value, v->data) == 0) { + match = 1; + break; + } + } + if (!match) { + val = malloc(sizeof(struct myvalue)); + if (val == NULL) + return -ENOMEM; + val->value = v->data; + list_add_tail(&val->list, list); + } + } + } + return 0; +} + +/** + * \brief Get list of values + * \param list Returned list + * \param verbname For verb (NULL = current) + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_value_list(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char **list[], + char *verbname) +{ + struct list_head mylist, *pos, *npos; + struct myvalue *val; + struct use_case_verb *verb; + struct use_case_device *dev; + struct use_case_modifier *mod; + char **res; + int err; + + if (verbname) { + verb = find_verb(uc_mgr, verbname); + } else { + verb = uc_mgr->active_verb; + } + if (verb == NULL) + return -ENOENT; + INIT_LIST_HEAD(&mylist); + err = add_values(&mylist, identifier, &uc_mgr->value_list); + if (err < 0) + goto __fail; + err = add_values(&mylist, identifier, &verb->value_list); + if (err < 0) + goto __fail; + list_for_each(pos, &verb->device_list) { + dev = list_entry(pos, struct use_case_device, list); + err = add_values(&mylist, identifier, &dev->value_list); + if (err < 0) + goto __fail; + } + list_for_each(pos, &verb->modifier_list) { + mod = list_entry(pos, struct use_case_modifier, list); + err = add_values(&mylist, identifier, &mod->value_list); + if (err < 0) + goto __fail; + } + err = alloc_str_list(&mylist, 1, &res); + if (err >= 0) { + *list = (const char **)res; + list_for_each(pos, &mylist) { + val = list_entry(pos, struct myvalue, list); + *res = strdup(val->value); + if (*res == NULL) { + snd_use_case_free_list((const char **)res, err); + err = -ENOMEM; + goto __fail; + } + res++; + } + } + __fail: + list_for_each_safe(pos, npos, &mylist) { + val = list_entry(pos, struct myvalue, list); + list_del(&val->list); + free(val); + } + return err; +} + +/** + * \brief Get list of enabled devices + * \param list Returned list + * \param verbname For verb (NULL = current) + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr, + const char **list[]) +{ + if (uc_mgr->active_verb == NULL) + return -EINVAL; + return get_list(&uc_mgr->active_devices, list, + struct use_case_device, active_list, + name); +} + +/** + * \brief Get list of enabled modifiers + * \param list Returned list + * \param verbname For verb (NULL = current) + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr, + const char **list[]) +{ + if (uc_mgr->active_verb == NULL) + return -EINVAL; + return get_list(&uc_mgr->active_modifiers, list, + struct use_case_modifier, active_list, + name); +} + +/** + * \brief Obtain a list of entries + * \param uc_mgr Use case manager (may be NULL - card list) + * \param identifier (may be NULL - card list) + * \param list Returned allocated list + * \return Number of list entries if success, otherwise a negative error code + */ +int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char **list[]) +{ + char *str, *str1; + int err; + + if (uc_mgr == NULL || identifier == NULL) + return uc_mgr_scan_master_configs(list); + pthread_mutex_lock(&uc_mgr->mutex); + if (strcmp(identifier, "_verbs") == 0) + err = get_verb_list(uc_mgr, list); + else if (strcmp(identifier, "_enadevs") == 0) + err = get_enabled_device_list(uc_mgr, list); + else if (strcmp(identifier, "_enamods") == 0) + err = get_enabled_modifier_list(uc_mgr, list); + else { + str1 = strchr(identifier, '/'); + if (str1) { + str = strdup(str1 + 1); + if (str == NULL) { + err = -ENOMEM; + goto __end; + } + } else { + str = NULL; + } + if (check_identifier(identifier, "_devices")) + err = get_device_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_modifiers")) + err = get_modifier_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_supporteddevs")) + err = get_supported_device_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_conflictingdevs")) + err = get_conflicting_device_list(uc_mgr, list, str); + else if (identifier[0] == '_') + err = -ENOENT; + else + err = get_value_list(uc_mgr, identifier, list, str); + if (str) + free(str); + } + __end: + pthread_mutex_unlock(&uc_mgr->mutex); + return err; +} + +static int get_value1(const char **value, struct list_head *value_list, + const char *identifier) +{ + struct ucm_value *val; + struct list_head *pos; + + if (!value_list) + return -ENOENT; + + list_for_each(pos, value_list) { + val = list_entry(pos, struct ucm_value, list); + if (check_identifier(identifier, val->name)) { + *value = strdup(val->data); + if (*value == NULL) + return -ENOMEM; + return 0; + } + } + return -ENOENT; +} + +static int get_value3(const char **value, + const char *identifier, + struct list_head *value_list1, + struct list_head *value_list2, + struct list_head *value_list3) +{ + int err; + + err = get_value1(value, value_list1, identifier); + if (err >= 0 || err != -ENOENT) + return err; + err = get_value1(value, value_list2, identifier); + if (err >= 0 || err != -ENOENT) + return err; + err = get_value1(value, value_list3, identifier); + if (err >= 0 || err != -ENOENT) + return err; + return -ENOENT; +} + +/** + * \brief Get value + * \param uc_mgr Use case manager + * \param identifier Value identifier (string) + * \param value Returned value string + * \param item Modifier or Device name (string) + * \return Zero on success (value is filled), otherwise a negative error code + */ +static int get_value(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char **value, + const char *mod_dev_name, + const char *verb_name, + int exact) +{ + struct use_case_verb *verb; + struct use_case_modifier *mod; + struct use_case_device *dev; + int err; + + if (mod_dev_name || verb_name || !exact) { + if (verb_name && strlen(verb_name)) { + verb = find_verb(uc_mgr, verb_name); + } else { + verb = uc_mgr->active_verb; + } + if (verb) { + if (mod_dev_name) { + mod = find_modifier(uc_mgr, verb, + mod_dev_name, 0); + if (mod) { + err = get_value1(value, + &mod->value_list, + identifier); + if (err >= 0 || err != -ENOENT) + return err; + } + + dev = find_device(uc_mgr, verb, + mod_dev_name, 0); + if (dev) { + err = get_value1(value, + &dev->value_list, + identifier); + if (err >= 0 || err != -ENOENT) + return err; + } + + if (exact) + return -ENOENT; + } + + err = get_value1(value, &verb->value_list, identifier); + if (err >= 0 || err != -ENOENT) + return err; + } + + if (exact) + return -ENOENT; + } + + err = get_value1(value, &uc_mgr->value_list, identifier); + if (err >= 0 || err != -ENOENT) + return err; + + return -ENOENT; +} + +/** + * \brief Get current - string + * \param uc_mgr Use case manager + * \param identifier + * \param value Value pointer + * \return Zero if success, otherwise a negative error code + * + * Note: String is dynamically allocated, use free() to + * deallocate this string. + */ +int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char **value) +{ + const char *slash1, *slash2, *mod_dev_after; + const char *ident, *mod_dev, *verb; + int exact = 0; + int err; + + pthread_mutex_lock(&uc_mgr->mutex); + if (identifier == NULL) { + *value = strdup(uc_mgr->card_name); + if (*value == NULL) { + err = -ENOMEM; + goto __end; + } + err = 0; + } else if (strcmp(identifier, "_verb") == 0) { + if (uc_mgr->active_verb == NULL) { + err = -ENOENT; + goto __end; + } + *value = strdup(uc_mgr->active_verb->name); + if (*value == NULL) { + err = -ENOMEM; + goto __end; + } + err = 0; + } else if (identifier[0] == '_') { + err = -ENOENT; + goto __end; + } else { + if (identifier[0] == '=') { + exact = 1; + identifier++; + } + + slash1 = strchr(identifier, '/'); + if (slash1) { + ident = strndup(identifier, slash1 - identifier); + + slash2 = strchr(slash1 + 1, '/'); + if (slash2) { + mod_dev_after = slash2; + verb = slash2 + 1; + } + else { + mod_dev_after = slash1 + strlen(slash1); + verb = NULL; + } + + if (mod_dev_after == slash1 + 1) + mod_dev = NULL; + else + mod_dev = strndup(slash1 + 1, + mod_dev_after - (slash1 + 1)); + } + else { + ident = identifier; + mod_dev = NULL; + verb = NULL; + } + + err = get_value(uc_mgr, ident, value, mod_dev, verb, exact); + if (ident != identifier) + free((void *)ident); + if (mod_dev) + free((void *)mod_dev); + } + __end: + pthread_mutex_unlock(&uc_mgr->mutex); + return err; +} + +long device_status(snd_use_case_mgr_t *uc_mgr, + const char *device_name) +{ + struct use_case_device *dev; + struct list_head *pos; + + list_for_each(pos, &uc_mgr->active_devices) { + dev = list_entry(pos, struct use_case_device, active_list); + if (strcmp(dev->name, device_name) == 0) + return 1; + } + return 0; +} + +long modifier_status(snd_use_case_mgr_t *uc_mgr, + const char *modifier_name) +{ + struct use_case_modifier *mod; + struct list_head *pos; + + list_for_each(pos, &uc_mgr->active_modifiers) { + mod = list_entry(pos, struct use_case_modifier, active_list); + if (strcmp(mod->name, modifier_name) == 0) + return 1; + } + return 0; +} + + +/** + * \brief Get current - integer + * \param uc_mgr Use case manager + * \param identifier + * \return Value if success, otherwise a negative error code + */ +int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + long *value) +{ + char *str, *str1; + long err; + + pthread_mutex_lock(&uc_mgr->mutex); + if (0) { + /* nothing here - prepared for fixed identifiers */ + } else { + str1 = strchr(identifier, '/'); + if (str1) { + str = strdup(str1 + 1); + if (str == NULL) { + err = -ENOMEM; + goto __end; + } + } else { + str = NULL; + } + if (check_identifier(identifier, "_devstatus")) { + err = device_status(uc_mgr, str); + if (err >= 0) { + *value = err; + err = 0; + } + } else if (check_identifier(identifier, "_modstatus")) { + err = modifier_status(uc_mgr, str); + if (err >= 0) { + *value = err; + err = 0; + } +#if 0 + /* + * enable this block if the else clause below is expanded to query + * user-supplied values + */ + } else if (identifier[0] == '_') + err = -ENOENT; +#endif + } else + err = -ENOENT; + if (str) + free(str); + } + __end: + pthread_mutex_unlock(&uc_mgr->mutex); + return err; +} + +static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr, + struct use_case_verb *new_verb) +{ + struct list_head *pos; + struct transition_sequence *trans; + int err; + + list_for_each(pos, &uc_mgr->active_verb->transition_list) { + trans = list_entry(pos, struct transition_sequence, list); + if (strcmp(trans->name, new_verb->name) == 0) { + err = execute_sequence(uc_mgr, &trans->transition_list, + &uc_mgr->active_verb->value_list, + &uc_mgr->value_list, + NULL); + if (err >= 0) + return 1; + return err; + } + } + return 0; +} + +static int set_verb_user(snd_use_case_mgr_t *uc_mgr, + const char *verb_name) +{ + struct use_case_verb *verb; + int err; + + if (uc_mgr->active_verb && + strcmp(uc_mgr->active_verb->name, verb_name) == 0) + return 0; + if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) { + verb = find_verb(uc_mgr, verb_name); + if (verb == NULL) + return -ENOENT; + } else { + verb = NULL; + } + if (uc_mgr->active_verb) { + err = handle_transition_verb(uc_mgr, verb); + if (err == 0) { + err = dismantle_use_case(uc_mgr); + if (err < 0) + return err; + } else if (err == 1) { + uc_mgr->active_verb = verb; + verb = NULL; + } else { + verb = NULL; /* show error */ + } + } + if (verb) { + err = set_verb(uc_mgr, verb, 1); + if (err < 0) + uc_error("error: failed to initialize new use case: %s", + verb_name); + } + return err; +} + + +static int set_device_user(snd_use_case_mgr_t *uc_mgr, + const char *device_name, + int enable) +{ + struct use_case_device *device; + + if (uc_mgr->active_verb == NULL) + return -ENOENT; + device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1); + if (device == NULL) + return -ENOENT; + return set_device(uc_mgr, device, enable); +} + +static int set_modifier_user(snd_use_case_mgr_t *uc_mgr, + const char *modifier_name, + int enable) +{ + struct use_case_modifier *modifier; + + if (uc_mgr->active_verb == NULL) + return -ENOENT; + + modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1); + if (modifier == NULL) + return -ENOENT; + return set_modifier(uc_mgr, modifier, enable); +} + +static int switch_device(snd_use_case_mgr_t *uc_mgr, + const char *old_device, + const char *new_device) +{ + struct use_case_device *xold, *xnew; + struct transition_sequence *trans; + struct list_head *pos; + int err, seq_found = 0; + + if (uc_mgr->active_verb == NULL) + return -ENOENT; + if (device_status(uc_mgr, old_device) == 0) { + uc_error("error: device %s not enabled", old_device); + return -EINVAL; + } + if (device_status(uc_mgr, new_device) != 0) { + uc_error("error: device %s already enabled", new_device); + return -EINVAL; + } + xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1); + if (xold == NULL) + return -ENOENT; + list_del(&xold->active_list); + xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1); + list_add_tail(&xold->active_list, &uc_mgr->active_devices); + if (xnew == NULL) + return -ENOENT; + err = 0; + list_for_each(pos, &xold->transition_list) { + trans = list_entry(pos, struct transition_sequence, list); + if (strcmp(trans->name, new_device) == 0) { + err = execute_sequence(uc_mgr, &trans->transition_list, + &xold->value_list, + &uc_mgr->active_verb->value_list, + &uc_mgr->value_list); + if (err >= 0) { + list_del(&xold->active_list); + list_add_tail(&xnew->active_list, &uc_mgr->active_devices); + } + seq_found = 1; + break; + } + } + if (!seq_found) { + err = set_device(uc_mgr, xold, 0); + if (err < 0) + return err; + err = set_device(uc_mgr, xnew, 1); + if (err < 0) + return err; + } + return err; +} + +static int switch_modifier(snd_use_case_mgr_t *uc_mgr, + const char *old_modifier, + const char *new_modifier) +{ + struct use_case_modifier *xold, *xnew; + struct transition_sequence *trans; + struct list_head *pos; + int err, seq_found = 0; + + if (uc_mgr->active_verb == NULL) + return -ENOENT; + if (modifier_status(uc_mgr, old_modifier) == 0) { + uc_error("error: modifier %s not enabled", old_modifier); + return -EINVAL; + } + if (modifier_status(uc_mgr, new_modifier) != 0) { + uc_error("error: modifier %s already enabled", new_modifier); + return -EINVAL; + } + xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1); + if (xold == NULL) + return -ENOENT; + xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1); + if (xnew == NULL) + return -ENOENT; + err = 0; + list_for_each(pos, &xold->transition_list) { + trans = list_entry(pos, struct transition_sequence, list); + if (strcmp(trans->name, new_modifier) == 0) { + err = execute_sequence(uc_mgr, &trans->transition_list, + &xold->value_list, + &uc_mgr->active_verb->value_list, + &uc_mgr->value_list); + if (err >= 0) { + list_del(&xold->active_list); + list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers); + } + seq_found = 1; + break; + } + } + if (!seq_found) { + err = set_modifier(uc_mgr, xold, 0); + if (err < 0) + return err; + err = set_modifier(uc_mgr, xnew, 1); + if (err < 0) + return err; + } + return err; +} + +/** + * \brief Set new + * \param uc_mgr Use case manager + * \param identifier + * \param value Value + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + const char *value) +{ + char *str, *str1; + int err; + + pthread_mutex_lock(&uc_mgr->mutex); + if (strcmp(identifier, "_verb") == 0) + err = set_verb_user(uc_mgr, value); + else if (strcmp(identifier, "_enadev") == 0) + err = set_device_user(uc_mgr, value, 1); + else if (strcmp(identifier, "_disdev") == 0) + err = set_device_user(uc_mgr, value, 0); + else if (strcmp(identifier, "_enamod") == 0) + err = set_modifier_user(uc_mgr, value, 1); + else if (strcmp(identifier, "_dismod") == 0) + err = set_modifier_user(uc_mgr, value, 0); + else { + str1 = strchr(identifier, '/'); + if (str1) { + str = strdup(str1 + 1); + if (str == NULL) { + err = -ENOMEM; + goto __end; + } + } else { + str = NULL; + } + if (check_identifier(identifier, "_swdev")) + err = switch_device(uc_mgr, str, value); + else if (check_identifier(identifier, "_swmod")) + err = switch_modifier(uc_mgr, str, value); + else + err = -EINVAL; + if (str) + free(str); + } + __end: + pthread_mutex_unlock(&uc_mgr->mutex); + return err; +} diff --git a/src/ucm/parser.c b/src/ucm/parser.c new file mode 100644 index 0000000..b93d832 --- /dev/null +++ b/src/ucm/parser.c @@ -0,0 +1,1329 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Support for the verb/device/modifier core logic and API, + * command line tool and file parser was kindly sponsored by + * Texas Instruments Inc. + * Support for multiple active modifiers and devices, + * transition sequences, multiple client access and user defined use + * cases was kindly sponsored by Wolfson Microelectronics PLC. + * + * Copyright (C) 2008-2010 SlimLogic Ltd + * Copyright (C) 2010 Wolfson Microelectronics PLC + * Copyright (C) 2010 Texas Instruments Inc. + * Copyright (C) 2010 Red Hat Inc. + * Authors: Liam Girdwood + * Stefan Schmidt + * Justin Xu + * Jaroslav Kysela + */ + +#include "ucm_local.h" +#include + +/** The name of the environment variable containing the UCM directory */ +#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" + +static int parse_sequence(snd_use_case_mgr_t *uc_mgr, + struct list_head *base, + snd_config_t *cfg); + +/* + * Parse string + */ +int parse_string(snd_config_t *n, char **res) +{ + int err; + + err = snd_config_get_string(n, (const char **)res); + if (err < 0) + return err; + *res = strdup(*res); + if (*res == NULL) + return -ENOMEM; + return 0; +} + +/* + * Parse safe ID + */ +int parse_is_name_safe(const char *name) +{ + if (strchr(name, '.')) { + uc_error("char '.' not allowed in '%s'", name); + return 0; + } + return 1; +} + +int parse_get_safe_id(snd_config_t *n, const char **id) +{ + int err; + + err = snd_config_get_id(n, id); + if (err < 0) + return err; + if (!parse_is_name_safe((char *)(*id))) + return -EINVAL; + return 0; +} + +/* + * Parse transition + */ +static int parse_transition(snd_use_case_mgr_t *uc_mgr, + struct list_head *tlist, + snd_config_t *cfg) +{ + struct transition_sequence *tseq; + const char *id; + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for %s", id); + return -EINVAL; + } + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + if (snd_config_get_id(n, &id) < 0) + return -EINVAL; + + tseq = calloc(1, sizeof(*tseq)); + if (tseq == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&tseq->transition_list); + + tseq->name = strdup(id); + if (tseq->name == NULL) { + free(tseq); + return -ENOMEM; + } + + err = parse_sequence(uc_mgr, &tseq->transition_list, n); + if (err < 0) { + uc_mgr_free_transition_element(tseq); + return err; + } + + list_add(&tseq->list, tlist); + } + return 0; +} + +/* + * Parse compound + */ +static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, + int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *), + void *data1, void *data2) +{ + const char *id; + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for %s", id); + return -EINVAL; + } + /* parse compound */ + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for %s, is %d", id, snd_config_get_type(cfg)); + return -EINVAL; + } + + err = fcn(uc_mgr, n, data1, data2); + if (err < 0) + return err; + } + + return 0; +} + +static int strip_legacy_dev_index(char *name) +{ + char *dot = strchr(name, '.'); + if (!dot) + return 0; + if (dot[1] != '0' || dot[2] != '\0') { + uc_error("device name %s contains a '.'," + " and is not legacy foo.0 format", name); + return -EINVAL; + } + *dot = '\0'; + return 0; +} + +/* + * Parse device list + */ +static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, + struct dev_list *dev_list, + enum dev_list_type type, + snd_config_t *cfg) +{ + struct dev_list_node *sdev; + const char *id; + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + if (dev_list->type != DEVLIST_NONE) { + uc_error("error: multiple supported or" + " conflicting device lists"); + return -EEXIST; + } + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for %s", id); + return -EINVAL; + } + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + if (snd_config_get_id(n, &id) < 0) + return -EINVAL; + + sdev = calloc(1, sizeof(struct dev_list_node)); + if (sdev == NULL) + return -ENOMEM; + err = parse_string(n, &sdev->name); + if (err < 0) { + free(sdev); + return err; + } + err = strip_legacy_dev_index(sdev->name); + if (err < 0) { + free(sdev->name); + free(sdev); + return err; + } + list_add(&sdev->list, &dev_list->list); + } + + dev_list->type = type; + + return 0; +} + +/* + * Parse sequences. + * + * Sequence controls elements are in the following form:- + * + * cdev "hw:0" + * cset "element_id_syntax value_syntax" + * usleep time + * exec "any unix command with arguments" + * + * e.g. + * cset "name='Master Playback Switch' 0,0" + * cset "iface=PCM,name='Disable HDMI',index=1 0" + */ +static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, + struct list_head *base, + snd_config_t *cfg) +{ + struct sequence_element *curr; + snd_config_iterator_t i, next; + snd_config_t *n; + int err, idx = 0; + const char *cmd = NULL; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("error: compound is expected for sequence definition"); + return -EINVAL; + } + + snd_config_for_each(i, next, cfg) { + const char *id; + idx ^= 1; + n = snd_config_iterator_entry(i); + err = snd_config_get_id(n, &id); + if (err < 0) + continue; + if (idx == 1) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { + uc_error("error: string type is expected for sequence command"); + return -EINVAL; + } + snd_config_get_string(n, &cmd); + continue; + } + + /* alloc new sequence element */ + curr = calloc(1, sizeof(struct sequence_element)); + if (curr == NULL) + return -ENOMEM; + list_add_tail(&curr->list, base); + + if (strcmp(cmd, "cdev") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_CDEV; + err = parse_string(n, &curr->data.cdev); + if (err < 0) { + uc_error("error: cdev requires a string!"); + return err; + } + continue; + } + + if (strcmp(cmd, "cset") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_CSET; + err = parse_string(n, &curr->data.cset); + if (err < 0) { + uc_error("error: cset requires a string!"); + return err; + } + continue; + } + + if (strcmp(cmd, "usleep") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; + err = snd_config_get_integer(n, &curr->data.sleep); + if (err < 0) { + uc_error("error: usleep requires integer!"); + return err; + } + continue; + } + + if (strcmp(cmd, "msleep") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; + err = snd_config_get_integer(n, &curr->data.sleep); + if (err < 0) { + uc_error("error: msleep requires integer!"); + return err; + } + curr->data.sleep *= 1000L; + continue; + } + + if (strcmp(cmd, "exec") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_EXEC; + err = parse_string(n, &curr->data.exec); + if (err < 0) { + uc_error("error: exec requires a string!"); + return err; + } + continue; + } + + list_del(&curr->list); + uc_mgr_free_sequence_element(curr); + } + + return 0; +} + +/* + * Parse values. + * + * Parse values describing PCM, control/mixer settings and stream parameters. + * + * Value { + * TQ Voice + * CapturePCM "hw:1" + * PlaybackVolume "name='Master Playback Volume',index=2" + * PlaybackSwitch "name='Master Playback Switch',index=2" + * } + */ +static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, + struct list_head *base, + snd_config_t *cfg) +{ + struct ucm_value *curr; + snd_config_iterator_t i, next; + snd_config_t *n; + long l; + long long ll; + double d; + snd_config_type_t type; + int err; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("error: compound is expected for value definition"); + return -EINVAL; + } + snd_config_for_each(i, next, cfg) { + const char *id; + n = snd_config_iterator_entry(i); + err = snd_config_get_id(n, &id); + if (err < 0) + continue; + + /* alloc new value */ + curr = calloc(1, sizeof(struct ucm_value)); + if (curr == NULL) + return -ENOMEM; + list_add_tail(&curr->list, base); + curr->name = strdup(id); + if (curr->name == NULL) + return -ENOMEM; + type = snd_config_get_type(n); + switch (type) { + case SND_CONFIG_TYPE_INTEGER: + curr->data = malloc(16); + if (curr->data == NULL) + return -ENOMEM; + snd_config_get_integer(n, &l); + sprintf(curr->data, "%li", l); + break; + case SND_CONFIG_TYPE_INTEGER64: + curr->data = malloc(32); + if (curr->data == NULL) + return -ENOMEM; + snd_config_get_integer64(n, &ll); + sprintf(curr->data, "%lli", ll); + break; + case SND_CONFIG_TYPE_REAL: + curr->data = malloc(64); + if (curr->data == NULL) + return -ENOMEM; + snd_config_get_real(n, &d); + sprintf(curr->data, "%-16g", d); + break; + case SND_CONFIG_TYPE_STRING: + err = parse_string(n, &curr->data); + if (err < 0) { + uc_error("error: unable to parse a string for id '%s'!", id); + return err; + } + break; + default: + uc_error("error: invalid type %i in Value compound", type); + return -EINVAL; + } + } + + return 0; +} + +/* + * Parse Modifier Use cases + * + * # Each modifier is described in new section. N modifiers are allowed + * SectionModifier."Capture Voice" { + * + * Comment "Record voice call" + * + * SupportedDevice [ + * "x" + * "y" + * ] + * + * ConflictingDevice [ + * "x" + * "y" + * ] + * + * EnableSequence [ + * .... + * ] + * + * DisableSequence [ + * ... + * ] + * + * TransitionSequence."ToModifierName" [ + * ... + * ] + * + * # Optional TQ and ALSA PCMs + * Value { + * TQ Voice + * CapturePCM "hw:1" + * PlaybackVolume "name='Master Playback Volume',index=2" + * PlaybackSwitch "name='Master Playback Switch',index=2" + * } + * + * } + * + * SupportedDevice and ConflictingDevice cannot be specified together. + * Both are optional. + */ +static int parse_modifier(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cfg, + void *data1, + void *data2) +{ + struct use_case_verb *verb = data1; + struct use_case_modifier *modifier; + const char *name; + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + if (data2) { + name = data2; + if (!parse_is_name_safe(name)) + return -EINVAL; + } + else { + if (parse_get_safe_id(cfg, &name) < 0) + return -EINVAL; + } + + /* allocate modifier */ + modifier = calloc(1, sizeof(*modifier)); + if (modifier == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&modifier->enable_list); + INIT_LIST_HEAD(&modifier->disable_list); + INIT_LIST_HEAD(&modifier->transition_list); + INIT_LIST_HEAD(&modifier->dev_list.list); + INIT_LIST_HEAD(&modifier->value_list); + list_add_tail(&modifier->list, &verb->modifier_list); + modifier->name = strdup(name); + + snd_config_for_each(i, next, cfg) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "Comment") == 0) { + err = parse_string(n, &modifier->comment); + if (err < 0) { + uc_error("error: failed to get modifier comment"); + return err; + } + continue; + } + + if (strcmp(id, "SupportedDevice") == 0) { + err = parse_device_list(uc_mgr, &modifier->dev_list, + DEVLIST_SUPPORTED, n); + if (err < 0) { + uc_error("error: failed to parse supported" + " device list"); + return err; + } + } + + if (strcmp(id, "ConflictingDevice") == 0) { + err = parse_device_list(uc_mgr, &modifier->dev_list, + DEVLIST_CONFLICTING, n); + if (err < 0) { + uc_error("error: failed to parse conflicting" + " device list"); + return err; + } + } + + if (strcmp(id, "EnableSequence") == 0) { + err = parse_sequence(uc_mgr, &modifier->enable_list, n); + if (err < 0) { + uc_error("error: failed to parse modifier" + " enable sequence"); + return err; + } + continue; + } + + if (strcmp(id, "DisableSequence") == 0) { + err = parse_sequence(uc_mgr, &modifier->disable_list, n); + if (err < 0) { + uc_error("error: failed to parse modifier" + " disable sequence"); + return err; + } + continue; + } + + if (strcmp(id, "TransitionSequence") == 0) { + err = parse_transition(uc_mgr, &modifier->transition_list, n); + if (err < 0) { + uc_error("error: failed to parse transition" + " modifier"); + return err; + } + continue; + } + + if (strcmp(id, "Value") == 0) { + err = parse_value(uc_mgr, &modifier->value_list, n); + if (err < 0) { + uc_error("error: failed to parse Value"); + return err; + } + continue; + } + } + + return 0; +} + +/* + * Parse Device Use Cases + * + *# Each device is described in new section. N devices are allowed + *SectionDevice."Headphones" { + * Comment "Headphones connected to 3.5mm jack" + * + * upportedDevice [ + * "x" + * "y" + * ] + * + * ConflictingDevice [ + * "x" + * "y" + * ] + * + * EnableSequence [ + * .... + * ] + * + * DisableSequence [ + * ... + * ] + * + * TransitionSequence."ToDevice" [ + * ... + * ] + * + * Value { + * PlaybackVolume "name='Master Playback Volume',index=2" + * PlaybackSwitch "name='Master Playback Switch',index=2" + * } + * } + */ +static int parse_device(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cfg, + void *data1, + void *data2) +{ + struct use_case_verb *verb = data1; + const char *name; + struct use_case_device *device; + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + if (data2) { + name = data2; + if (!parse_is_name_safe(name)) + return -EINVAL; + } + else { + if (parse_get_safe_id(cfg, &name) < 0) + return -EINVAL; + } + + device = calloc(1, sizeof(*device)); + if (device == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&device->enable_list); + INIT_LIST_HEAD(&device->disable_list); + INIT_LIST_HEAD(&device->transition_list); + INIT_LIST_HEAD(&device->dev_list.list); + INIT_LIST_HEAD(&device->value_list); + list_add_tail(&device->list, &verb->device_list); + device->name = strdup(name); + + snd_config_for_each(i, next, cfg) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "Comment") == 0) { + err = parse_string(n, &device->comment); + if (err < 0) { + uc_error("error: failed to get device comment"); + return err; + } + continue; + } + + if (strcmp(id, "SupportedDevice") == 0) { + err = parse_device_list(uc_mgr, &device->dev_list, + DEVLIST_SUPPORTED, n); + if (err < 0) { + uc_error("error: failed to parse supported" + " device list"); + return err; + } + } + + if (strcmp(id, "ConflictingDevice") == 0) { + err = parse_device_list(uc_mgr, &device->dev_list, + DEVLIST_CONFLICTING, n); + if (err < 0) { + uc_error("error: failed to parse conflicting" + " device list"); + return err; + } + } + + if (strcmp(id, "EnableSequence") == 0) { + uc_dbg("EnableSequence"); + err = parse_sequence(uc_mgr, &device->enable_list, n); + if (err < 0) { + uc_error("error: failed to parse device enable" + " sequence"); + return err; + } + continue; + } + + if (strcmp(id, "DisableSequence") == 0) { + uc_dbg("DisableSequence"); + err = parse_sequence(uc_mgr, &device->disable_list, n); + if (err < 0) { + uc_error("error: failed to parse device disable" + " sequence"); + return err; + } + continue; + } + + if (strcmp(id, "TransitionSequence") == 0) { + uc_dbg("TransitionSequence"); + err = parse_transition(uc_mgr, &device->transition_list, n); + if (err < 0) { + uc_error("error: failed to parse transition" + " device"); + return err; + } + continue; + } + + if (strcmp(id, "Value") == 0) { + err = parse_value(uc_mgr, &device->value_list, n); + if (err < 0) { + uc_error("error: failed to parse Value"); + return err; + } + continue; + } + } + return 0; +} + +static int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cfg, + int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *), + void *data1) +{ + const char *id, *idchild; + int child_ctr = 0, legacy_format = 1; + snd_config_iterator_t i, next; + snd_config_t *child; + int err; + + err = snd_config_get_id(cfg, &id); + if (err < 0) + return err; + + snd_config_for_each(i, next, cfg) { + child_ctr++; + if (child_ctr > 1) { + break; + } + + child = snd_config_iterator_entry(i); + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + legacy_format = 0; + break; + } + + if (snd_config_get_id(child, &idchild) < 0) + return -EINVAL; + + if (strcmp(idchild, "0")) { + legacy_format = 0; + break; + } + } + if (child_ctr != 1) { + legacy_format = 0; + } + + if (legacy_format) + return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id); + else + return fcn(uc_mgr, cfg, data1, NULL); +} + +static int parse_device_name(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cfg, + void *data1, + void *data2 ATTRIBUTE_UNUSED) +{ + return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1); +} + +static int parse_modifier_name(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cfg, + void *data1, + void *data2 ATTRIBUTE_UNUSED) +{ + return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1); +} + +/* + * Parse Verb Section + * + * # Example Use case verb section for Voice call blah + * # By Joe Blogs + * + * SectionVerb { + * # enable and disable sequences are compulsory + * EnableSequence [ + * cset "name='Master Playback Switch',index=2 0,0" + * cset "name='Master Playback Volume',index=2 25,25" + * msleep 50 + * cset "name='Master Playback Switch',index=2 1,1" + * cset "name='Master Playback Volume',index=2 50,50" + * ] + * + * DisableSequence [ + * cset "name='Master Playback Switch',index=2 0,0" + * cset "name='Master Playback Volume',index=2 25,25" + * msleep 50 + * cset "name='Master Playback Switch',index=2 1,1" + * cset "name='Master Playback Volume',index=2 50,50" + * ] + * + * # Optional transition verb + * TransitionSequence."ToCaseName" [ + * msleep 1 + * ] + * + * # Optional TQ and ALSA PCMs + * Value { + * TQ HiFi + * CapturePCM "hw:0" + * PlaybackPCM "hw:0" + * } + * } + */ +static int parse_verb(snd_use_case_mgr_t *uc_mgr, + struct use_case_verb *verb, + snd_config_t *cfg) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + /* parse verb section */ + snd_config_for_each(i, next, cfg) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "EnableSequence") == 0) { + uc_dbg("Parse EnableSequence"); + err = parse_sequence(uc_mgr, &verb->enable_list, n); + if (err < 0) { + uc_error("error: failed to parse verb enable sequence"); + return err; + } + continue; + } + + if (strcmp(id, "DisableSequence") == 0) { + uc_dbg("Parse DisableSequence"); + err = parse_sequence(uc_mgr, &verb->disable_list, n); + if (err < 0) { + uc_error("error: failed to parse verb disable sequence"); + return err; + } + continue; + } + + if (strcmp(id, "TransitionSequence") == 0) { + uc_dbg("Parse TransitionSequence"); + err = parse_transition(uc_mgr, &verb->transition_list, n); + if (err < 0) { + uc_error("error: failed to parse transition sequence"); + return err; + } + continue; + } + + if (strcmp(id, "Value") == 0) { + uc_dbg("Parse Value"); + err = parse_value(uc_mgr, &verb->value_list, n); + if (err < 0) + return err; + continue; + } + } + + return 0; +} + +/* + * Parse a Use case verb file. + * + * This file contains the following :- + * o Verb enable and disable sequences. + * o Supported Device enable and disable sequences for verb. + * o Supported Modifier enable and disable sequences for verb + * o Optional QoS for the verb and modifiers. + * o Optional PCM device ID for verb and modifiers + * o Alias kcontrols IDs for master and volumes and mutes. + */ +static int parse_verb_file(snd_use_case_mgr_t *uc_mgr, + const char *use_case_name, + const char *comment, + const char *file) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct use_case_verb *verb; + snd_config_t *cfg; + char filename[MAX_FILE]; + char *env = getenv(ALSA_CONFIG_UCM_VAR); + int err; + + /* allocate verb */ + verb = calloc(1, sizeof(struct use_case_verb)); + if (verb == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&verb->enable_list); + INIT_LIST_HEAD(&verb->disable_list); + INIT_LIST_HEAD(&verb->transition_list); + INIT_LIST_HEAD(&verb->device_list); + INIT_LIST_HEAD(&verb->modifier_list); + INIT_LIST_HEAD(&verb->value_list); + list_add_tail(&verb->list, &uc_mgr->verb_list); + if (use_case_name == NULL) + return -EINVAL; + verb->name = strdup(use_case_name); + if (verb->name == NULL) + return -ENOMEM; + + if (comment != NULL) { + verb->comment = strdup(comment); + if (verb->comment == NULL) + return -ENOMEM; + } + + /* open Verb file for reading */ + snprintf(filename, sizeof(filename), "%s/%s/%s", + env ? env : ALSA_USE_CASE_DIR, + uc_mgr->card_name, file); + filename[sizeof(filename)-1] = '\0'; + + err = uc_mgr_config_load(filename, &cfg); + if (err < 0) { + uc_error("error: failed to open verb file %s : %d", + filename, -errno); + return err; + } + + /* parse master config sections */ + snd_config_for_each(i, next, cfg) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* find verb section and parse it */ + if (strcmp(id, "SectionVerb") == 0) { + err = parse_verb(uc_mgr, verb, n); + if (err < 0) { + uc_error("error: %s failed to parse verb", + file); + return err; + } + continue; + } + + /* find device sections and parse them */ + if (strcmp(id, "SectionDevice") == 0) { + err = parse_compound(uc_mgr, n, + parse_device_name, verb, NULL); + if (err < 0) { + uc_error("error: %s failed to parse device", + file); + return err; + } + continue; + } + + /* find modifier sections and parse them */ + if (strcmp(id, "SectionModifier") == 0) { + err = parse_compound(uc_mgr, n, + parse_modifier_name, verb, NULL); + if (err < 0) { + uc_error("error: %s failed to parse modifier", + file); + return err; + } + continue; + } + } + + /* use case verb must have at least 1 device */ + if (list_empty(&verb->device_list)) { + uc_error("error: no use case device defined", file); + return -EINVAL; + } + return 0; +} + +/* + * Parse master section for "Use Case" and "File" tags. + */ +static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, + void *data1 ATTRIBUTE_UNUSED, + void *data2 ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *use_case_name, *file = NULL, *comment = NULL; + int err; + + if (snd_config_get_id(cfg, &use_case_name) < 0) { + uc_error("unable to get name for use case section"); + return -EINVAL; + } + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for use case section"); + return -EINVAL; + } + /* parse master config sections */ + snd_config_for_each(i, next, cfg) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* get use case verb file name */ + if (strcmp(id, "File") == 0) { + err = snd_config_get_string(n, &file); + if (err < 0) { + uc_error("failed to get File"); + return err; + } + continue; + } + + /* get optional use case comment */ + if (strncmp(id, "Comment", 7) == 0) { + err = snd_config_get_string(n, &comment); + if (err < 0) { + uc_error("error: failed to get Comment"); + return err; + } + continue; + } + + uc_error("unknown field %s in master section"); + } + + uc_dbg("use_case_name %s file '%s'", use_case_name, file); + + /* do we have both use case name and file ? */ + if (!file) { + uc_error("error: use case missing file"); + return -EINVAL; + } + + /* parse verb file */ + return parse_verb_file(uc_mgr, use_case_name, comment, file); +} + +/* + * parse controls + */ +static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) +{ + int err; + + if (!list_empty(&uc_mgr->default_list)) { + uc_error("Default list is not empty"); + return -EINVAL; + } + err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg); + if (err < 0) { + uc_error("Unable to parse SectionDefaults"); + return err; + } + + return 0; +} + +/* + * Each sound card has a master sound card file that lists all the supported + * use case verbs for that sound card. i.e. + * + * #Example master file for blah sound card + * #By Joe Blogs + * + * Comment "Nice Abstracted Soundcard" + * + * # The file is divided into Use case sections. One section per use case verb. + * + * SectionUseCase."Voice Call" { + * File "voice_call_blah" + * Comment "Make a voice phone call." + * } + * + * SectionUseCase."HiFi" { + * File "hifi_blah" + * Comment "Play and record HiFi quality Music." + * } + * + * # Define Value defaults + * + * ValueDefaults { + * PlaybackCTL "hw:CARD=0" + * CaptureCTL "hw:CARD=0" + * } + * + * # This file also stores the default sound card state. + * + * SectionDefaults [ + * cset "name='Master Playback Switch',index=2 1,1" + * cset "name='Master Playback Volume',index=2 25,25" + * cset "name='Master Mono Playback',index=1 0" + * cset "name='Master Mono Playback Volume',index=1 0" + * cset "name='PCM Switch',index=2 1,1" + * exec "some binary here" + * msleep 50 + * ........ + * ] + * + * # End of example file. + */ +static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + int err; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for master file"); + return -EINVAL; + } + + /* parse master config sections */ + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "Comment") == 0) { + err = parse_string(n, &uc_mgr->comment); + if (err < 0) { + uc_error("error: failed to get master comment"); + return err; + } + continue; + } + + /* find use case section and parse it */ + if (strcmp(id, "SectionUseCase") == 0) { + err = parse_compound(uc_mgr, n, + parse_master_section, + NULL, NULL); + if (err < 0) + return err; + continue; + } + + /* find default control values section and parse it */ + if (strcmp(id, "SectionDefaults") == 0) { + err = parse_controls(uc_mgr, n); + if (err < 0) + return err; + continue; + } + + /* get the default values */ + if (strcmp(id, "ValueDefaults") == 0) { + err = parse_value(uc_mgr, &uc_mgr->value_list, n); + if (err < 0) { + uc_error("error: failed to parse ValueDefaults"); + return err; + } + continue; + } + + uc_error("uknown master file field %s", id); + } + return 0; +} + +static int load_master_config(const char *card_name, snd_config_t **cfg) +{ + char filename[MAX_FILE]; + char *env = getenv(ALSA_CONFIG_UCM_VAR); + int err; + + snprintf(filename, sizeof(filename)-1, + "%s/%s/%s.conf", env ? env : ALSA_USE_CASE_DIR, + card_name, card_name); + filename[MAX_FILE-1] = '\0'; + + err = uc_mgr_config_load(filename, cfg); + if (err < 0) { + uc_error("error: could not parse configuration for card %s", + card_name); + return err; + } + + return 0; +} + +/* load master use case file for sound card */ +int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) +{ + snd_config_t *cfg; + int err; + + err = load_master_config(uc_mgr->card_name, &cfg); + if (err < 0) + return err; + err = parse_master_file(uc_mgr, cfg); + snd_config_delete(cfg); + if (err < 0) + uc_mgr_free_verb(uc_mgr); + + return err; +} + +static int filename_filter(const struct dirent *dirent) +{ + if (dirent == NULL) + return 0; + if (dirent->d_type == DT_DIR) { + if (dirent->d_name[0] == '.') { + if (dirent->d_name[1] == '\0') + return 0; + if (dirent->d_name[1] == '.' && + dirent->d_name[2] == '\0') + return 0; + } + return 1; + } + return 0; +} + +/* scan all cards and comments */ +int uc_mgr_scan_master_configs(const char **_list[]) +{ + char filename[MAX_FILE], dfl[MAX_FILE]; + char *env = getenv(ALSA_CONFIG_UCM_VAR); + const char **list; + snd_config_t *cfg, *c; + int i, cnt, err; + ssize_t ss; + struct dirent **namelist; + + snprintf(filename, sizeof(filename)-1, + "%s", env ? env : ALSA_USE_CASE_DIR); + filename[MAX_FILE-1] = '\0'; + + err = scandir(filename, &namelist, filename_filter, versionsort); + if (err < 0) { + err = -errno; + uc_error("error: could not scan directory %s: %s", + filename, strerror(-err)); + return err; + } + cnt = err; + + dfl[0] = '\0'; + if (strlen(filename) + 8 < sizeof(filename)) { + strcat(filename, "/default"); + ss = readlink(filename, dfl, sizeof(dfl)-1); + if (ss >= 0) { + dfl[ss] = '\0'; + dfl[sizeof(dfl)-1] = '\0'; + if (dfl[0] && dfl[strlen(dfl)-1] == '/') + dfl[strlen(dfl)-1] = '\0'; + } else { + dfl[0] = '\0'; + } + } + + list = calloc(1, cnt * 2 * sizeof(char *)); + if (list == NULL) { + err = -ENOMEM; + goto __err; + } + + for (i = 0; i < cnt; i++) { + err = load_master_config(namelist[i]->d_name, &cfg); + if (err < 0) + goto __err; + err = snd_config_search(cfg, "Comment", &c); + if (err >= 0) { + err = parse_string(c, (char **)&list[i*2+1]); + if (err < 0) { + snd_config_delete(cfg); + goto __err; + } + } + snd_config_delete(cfg); + list[i * 2] = strdup(namelist[i]->d_name); + if (list[i * 2] == NULL) { + err = -ENOMEM; + goto __err; + } + if (strcmp(dfl, list[i * 2]) == 0) { + /* default to top */ + const char *save1 = list[i * 2]; + const char *save2 = list[i * 2 + 1]; + memmove(list + 2, list, i * 2 * sizeof(char *)); + list[0] = save1; + list[1] = save2; + } + } + err = cnt * 2; + + __err: + for (i = 0; i < cnt; i++) { + free(namelist[i]); + if (err < 0) { + free((void *)list[i * 2]); + free((void *)list[i * 2 + 1]); + } + } + free(namelist); + + if (err >= 0) + *_list = list; + + return err; +} diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h new file mode 100644 index 0000000..03d3ace --- /dev/null +++ b/src/ucm/ucm_local.h @@ -0,0 +1,221 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Support for the verb/device/modifier core logic and API, + * command line tool and file parser was kindly sponsored by + * Texas Instruments Inc. + * Support for multiple active modifiers and devices, + * transition sequences, multiple client access and user defined use + * cases was kindly sponsored by Wolfson Microelectronics PLC. + * + * Copyright (C) 2008-2010 SlimLogic Ltd + * Copyright (C) 2010 Wolfson Microelectronics PLC + * Copyright (C) 2010 Texas Instruments Inc. + * Copyright (C) 2010 Red Hat Inc. + * Authors: Liam Girdwood + * Stefan Schmidt + * Justin Xu + * Jaroslav Kysela + */ + + + +#if 0 +#define UC_MGR_DEBUG +#endif + +#include "local.h" +#include "use-case.h" + +#define MAX_FILE 256 +#define ALSA_USE_CASE_DIR ALSA_CONFIG_DIR "/ucm" + +#define SEQUENCE_ELEMENT_TYPE_CDEV 1 +#define SEQUENCE_ELEMENT_TYPE_CSET 2 +#define SEQUENCE_ELEMENT_TYPE_SLEEP 3 +#define SEQUENCE_ELEMENT_TYPE_EXEC 4 + +struct ucm_value { + struct list_head list; + char *name; + char *data; +}; + +struct sequence_element { + struct list_head list; + unsigned int type; + union { + long sleep; /* Sleep time in microseconds if sleep element, else 0 */ + char *cdev; + char *cset; + char *exec; + } data; +}; + +/* + * Transition sequences. i.e. transition between one verb, device, mod to another + */ +struct transition_sequence { + struct list_head list; + char *name; + struct list_head transition_list; +}; + +/* + * Modifier Supported Devices. + */ +enum dev_list_type { + DEVLIST_NONE, + DEVLIST_SUPPORTED, + DEVLIST_CONFLICTING +}; + +struct dev_list_node { + struct list_head list; + char *name; +}; + +struct dev_list { + enum dev_list_type type; + struct list_head list; +}; + +/* + * Describes a Use Case Modifier and it's enable and disable sequences. + * A use case verb can have N modifiers. + */ +struct use_case_modifier { + struct list_head list; + struct list_head active_list; + + char *name; + char *comment; + + /* modifier enable and disable sequences */ + struct list_head enable_list; + struct list_head disable_list; + + /* modifier transition list */ + struct list_head transition_list; + + /* list of devices supported or conflicting */ + struct dev_list dev_list; + + /* values */ + struct list_head value_list; +}; + +/* + * Describes a Use Case Device and it's enable and disable sequences. + * A use case verb can have N devices. + */ +struct use_case_device { + struct list_head list; + struct list_head active_list; + + char *name; + char *comment; + + /* device enable and disable sequences */ + struct list_head enable_list; + struct list_head disable_list; + + /* device transition list */ + struct list_head transition_list; + + /* list of devices supported or conflicting */ + struct dev_list dev_list; + + /* value list */ + struct list_head value_list; +}; + +/* + * Describes a Use Case Verb and it's enable and disable sequences. + * A use case verb can have N devices and N modifiers. + */ +struct use_case_verb { + struct list_head list; + + unsigned int active: 1; + + char *name; + char *comment; + + /* verb enable and disable sequences */ + struct list_head enable_list; + struct list_head disable_list; + + /* verb transition list */ + struct list_head transition_list; + + /* hardware devices that can be used with this use case */ + struct list_head device_list; + + /* modifiers that can be used with this use case */ + struct list_head modifier_list; + + /* value list */ + struct list_head value_list; +}; + +/* + * Manages a sound card and all its use cases. + */ +struct snd_use_case_mgr { + char *card_name; + char *comment; + + /* use case verb, devices and modifier configs parsed from files */ + struct list_head verb_list; + + /* default settings - sequence */ + struct list_head default_list; + + /* default settings - value list */ + struct list_head value_list; + + /* current status */ + struct use_case_verb *active_verb; + struct list_head active_devices; + struct list_head active_modifiers; + + /* locking */ + pthread_mutex_t mutex; + + /* change to list of ctl handles */ + snd_ctl_t *ctl; + char *ctl_dev; +}; + +#define uc_error SNDERR + +#ifdef UC_MGR_DEBUG +#define uc_dbg SNDERR +#else +#define uc_dbg(fmt, arg...) do { } while (0) +#endif + +void uc_mgr_error(const char *fmt, ...); +void uc_mgr_stdout(const char *fmt, ...); + +int uc_mgr_config_load(const char *file, snd_config_t **cfg); +int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr); +int uc_mgr_scan_master_configs(const char **_list[]); + +void uc_mgr_free_sequence_element(struct sequence_element *seq); +void uc_mgr_free_transition_element(struct transition_sequence *seq); +void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr); +void uc_mgr_free(snd_use_case_mgr_t *uc_mgr); diff --git a/src/ucm/utils.c b/src/ucm/utils.c new file mode 100644 index 0000000..3a383a9 --- /dev/null +++ b/src/ucm/utils.c @@ -0,0 +1,237 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Support for the verb/device/modifier core logic and API, + * command line tool and file parser was kindly sponsored by + * Texas Instruments Inc. + * Support for multiple active modifiers and devices, + * transition sequences, multiple client access and user defined use + * cases was kindly sponsored by Wolfson Microelectronics PLC. + * + * Copyright (C) 2008-2010 SlimLogic Ltd + * Copyright (C) 2010 Wolfson Microelectronics PLC + * Copyright (C) 2010 Texas Instruments Inc. + * Copyright (C) 2010 Red Hat Inc. + * Authors: Liam Girdwood + * Stefan Schmidt + * Justin Xu + * Jaroslav Kysela + */ + +#include "ucm_local.h" + +void uc_mgr_error(const char *fmt,...) +{ + va_list va; + va_start(va, fmt); + fprintf(stderr, "ucm: "); + vfprintf(stderr, fmt, va); + va_end(va); +} + +void uc_mgr_stdout(const char *fmt,...) +{ + va_list va; + va_start(va, fmt); + vfprintf(stdout, fmt, va); + va_end(va); +} + +int uc_mgr_config_load(const char *file, snd_config_t **cfg) +{ + FILE *fp; + snd_input_t *in; + snd_config_t *top; + int err; + + fp = fopen(file, "r"); + if (fp == NULL) { + err = -errno; + goto __err; + } + err = snd_input_stdio_attach(&in, fp, 1); + if (err < 0) { + __err: + uc_error("could not open configuration file %s", file); + return err; + } + err = snd_config_top(&top); + if (err < 0) + return err; + err = snd_config_load(top, in); + if (err < 0) { + uc_error("could not load configuration file %s", file); + snd_config_delete(top); + return err; + } + err = snd_input_close(in); + if (err < 0) { + snd_config_delete(top); + return err; + } + *cfg = top; + return 0; +} + +void uc_mgr_free_value(struct list_head *base) +{ + struct list_head *pos, *npos; + struct ucm_value *val; + + list_for_each_safe(pos, npos, base) { + val = list_entry(pos, struct ucm_value, list); + free(val->name); + free(val->data); + list_del(&val->list); + free(val); + } +} + +void uc_mgr_free_dev_list(struct dev_list *dev_list) +{ + struct list_head *pos, *npos; + struct dev_list_node *dlist; + + list_for_each_safe(pos, npos, &dev_list->list) { + dlist = list_entry(pos, struct dev_list_node, list); + free(dlist->name); + list_del(&dlist->list); + free(dlist); + } +} + +void uc_mgr_free_sequence_element(struct sequence_element *seq) +{ + if (seq == NULL) + return; + switch (seq->type) { + case SEQUENCE_ELEMENT_TYPE_CSET: + case SEQUENCE_ELEMENT_TYPE_EXEC: + free(seq->data.exec); + break; + default: + break; + } + free(seq); +} + +void uc_mgr_free_sequence(struct list_head *base) +{ + struct list_head *pos, *npos; + struct sequence_element *seq; + + list_for_each_safe(pos, npos, base) { + seq = list_entry(pos, struct sequence_element, list); + list_del(&seq->list); + uc_mgr_free_sequence_element(seq); + } +} + +void uc_mgr_free_transition_element(struct transition_sequence *tseq) +{ + free(tseq->name); + uc_mgr_free_sequence(&tseq->transition_list); + free(tseq); +} + +void uc_mgr_free_transition(struct list_head *base) +{ + struct list_head *pos, *npos; + struct transition_sequence *tseq; + + list_for_each_safe(pos, npos, base) { + tseq = list_entry(pos, struct transition_sequence, list); + list_del(&tseq->list); + uc_mgr_free_transition_element(tseq); + } +} + +void uc_mgr_free_modifier(struct list_head *base) +{ + struct list_head *pos, *npos; + struct use_case_modifier *mod; + + list_for_each_safe(pos, npos, base) { + mod = list_entry(pos, struct use_case_modifier, list); + free(mod->name); + free(mod->comment); + uc_mgr_free_sequence(&mod->enable_list); + uc_mgr_free_sequence(&mod->disable_list); + uc_mgr_free_transition(&mod->transition_list); + uc_mgr_free_dev_list(&mod->dev_list); + uc_mgr_free_value(&mod->value_list); + list_del(&mod->list); + free(mod); + } +} + +void uc_mgr_free_device(struct list_head *base) +{ + struct list_head *pos, *npos; + struct use_case_device *dev; + + list_for_each_safe(pos, npos, base) { + dev = list_entry(pos, struct use_case_device, list); + free(dev->name); + free(dev->comment); + uc_mgr_free_sequence(&dev->enable_list); + uc_mgr_free_sequence(&dev->disable_list); + uc_mgr_free_transition(&dev->transition_list); + uc_mgr_free_dev_list(&dev->dev_list); + uc_mgr_free_value(&dev->value_list); + list_del(&dev->list); + free(dev); + } +} + +void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) +{ + struct list_head *pos, *npos; + struct use_case_verb *verb; + + list_for_each_safe(pos, npos, &uc_mgr->verb_list) { + verb = list_entry(pos, struct use_case_verb, list); + free(verb->name); + free(verb->comment); + uc_mgr_free_sequence(&verb->enable_list); + uc_mgr_free_sequence(&verb->disable_list); + uc_mgr_free_transition(&verb->transition_list); + uc_mgr_free_value(&verb->value_list); + uc_mgr_free_device(&verb->device_list); + uc_mgr_free_modifier(&verb->modifier_list); + list_del(&verb->list); + free(verb); + } + uc_mgr_free_sequence(&uc_mgr->default_list); + uc_mgr_free_value(&uc_mgr->value_list); + free(uc_mgr->comment); + uc_mgr->comment = NULL; + uc_mgr->active_verb = NULL; + INIT_LIST_HEAD(&uc_mgr->active_devices); + INIT_LIST_HEAD(&uc_mgr->active_modifiers); + if (uc_mgr->ctl != NULL) { + snd_ctl_close(uc_mgr->ctl); + uc_mgr->ctl = NULL; + } + free(uc_mgr->ctl_dev); + uc_mgr->ctl_dev = NULL; +} + +void uc_mgr_free(snd_use_case_mgr_t *uc_mgr) +{ + uc_mgr_free_verb(uc_mgr); + free(uc_mgr->card_name); + free(uc_mgr); +} diff --git a/src/userfile.c b/src/userfile.c new file mode 100644 index 0000000..3a73836 --- /dev/null +++ b/src/userfile.c @@ -0,0 +1,72 @@ +/* + * Get full filename + * Copyright (c) 2003 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +/** + * \brief Get the full file name + * \param file The file name string to parse + * \param result The pointer to store the resultant file name + * \return 0 if successful, or a negative error code + * + * Parses the given file name with POSIX-Shell-like expansion and + * stores the first matchine one. The returned string is strdup'ed. + */ + +#ifdef HAVE_WORDEXP_H +#include +#include +int snd_user_file(const char *file, char **result) +{ + wordexp_t we; + int err; + + assert(file && result); + err = wordexp(file, &we, WRDE_NOCMD); + switch (err) { + case WRDE_NOSPACE: + return -ENOMEM; + case 0: + if (we.we_wordc == 1) + break; + /* fall thru */ + default: + wordfree(&we); + return -EINVAL; + } + *result = strdup(we.we_wordv[0]); + if (*result == NULL) + return -ENOMEM; + wordfree(&we); + return 0; +} + +#else /* !HAVE_WORDEXP_H */ +/* just copy the string - would be nicer to expand by ourselves, though... */ +int snd_user_file(const char *file, char **result) +{ + *result = strdup(file); + if (! *result) + return -ENOMEM; + return 0; +} +#endif /* HAVE_WORDEXP_H */ diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..ae524a4 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,25 @@ +SUBDIRS=. lsb + +check_PROGRAMS=control pcm pcm_min latency seq \ + playmidi1 timer rawmidi midiloop \ + oldapi queue_timer namehint client_event_filter + +control_LDADD=../src/libasound.la +pcm_LDADD=../src/libasound.la +pcm_min_LDADD=../src/libasound.la +latency_LDADD=../src/libasound.la +seq_LDADD=../src/libasound.la +playmidi1_LDADD=../src/libasound.la +timer_LDADD=../src/libasound.la +rawmidi_LDADD=../src/libasound.la +midiloop_LDADD=../src/libasound.la +oldapi_LDADD=../src/libasound.la +queue_timer_LDADD=../src/libasound.la +namehint_LDADD=../src/libasound.la +client_event_filter_LDADD=../src/libasound.la +code_CFLAGS=-Wall -pipe -g -O2 + +INCLUDES=-I$(top_srcdir)/include +AM_CFLAGS=-Wall -pipe -g + +EXTRA_DIST=seq-decoder.c seq-sender.c midifile.h midifile.c midifile.3 diff --git a/test/Makefile.in b/test/Makefile.in new file mode 100644 index 0000000..4735b74 --- /dev/null +++ b/test/Makefile.in @@ -0,0 +1,758 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = control$(EXEEXT) pcm$(EXEEXT) pcm_min$(EXEEXT) \ + latency$(EXEEXT) seq$(EXEEXT) playmidi1$(EXEEXT) \ + timer$(EXEEXT) rawmidi$(EXEEXT) midiloop$(EXEEXT) \ + oldapi$(EXEEXT) queue_timer$(EXEEXT) namehint$(EXEEXT) \ + client_event_filter$(EXEEXT) +subdir = test +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +client_event_filter_SOURCES = client_event_filter.c +client_event_filter_OBJECTS = client_event_filter.$(OBJEXT) +client_event_filter_DEPENDENCIES = ../src/libasound.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +control_SOURCES = control.c +control_OBJECTS = control.$(OBJEXT) +control_DEPENDENCIES = ../src/libasound.la +latency_SOURCES = latency.c +latency_OBJECTS = latency.$(OBJEXT) +latency_DEPENDENCIES = ../src/libasound.la +midiloop_SOURCES = midiloop.c +midiloop_OBJECTS = midiloop.$(OBJEXT) +midiloop_DEPENDENCIES = ../src/libasound.la +namehint_SOURCES = namehint.c +namehint_OBJECTS = namehint.$(OBJEXT) +namehint_DEPENDENCIES = ../src/libasound.la +oldapi_SOURCES = oldapi.c +oldapi_OBJECTS = oldapi.$(OBJEXT) +oldapi_DEPENDENCIES = ../src/libasound.la +pcm_SOURCES = pcm.c +pcm_OBJECTS = pcm.$(OBJEXT) +pcm_DEPENDENCIES = ../src/libasound.la +pcm_min_SOURCES = pcm_min.c +pcm_min_OBJECTS = pcm_min.$(OBJEXT) +pcm_min_DEPENDENCIES = ../src/libasound.la +playmidi1_SOURCES = playmidi1.c +playmidi1_OBJECTS = playmidi1.$(OBJEXT) +playmidi1_DEPENDENCIES = ../src/libasound.la +queue_timer_SOURCES = queue_timer.c +queue_timer_OBJECTS = queue_timer.$(OBJEXT) +queue_timer_DEPENDENCIES = ../src/libasound.la +rawmidi_SOURCES = rawmidi.c +rawmidi_OBJECTS = rawmidi.$(OBJEXT) +rawmidi_DEPENDENCIES = ../src/libasound.la +seq_SOURCES = seq.c +seq_OBJECTS = seq.$(OBJEXT) +seq_DEPENDENCIES = ../src/libasound.la +timer_SOURCES = timer.c +timer_OBJECTS = timer.$(OBJEXT) +timer_DEPENDENCIES = ../src/libasound.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = client_event_filter.c control.c latency.c midiloop.c \ + namehint.c oldapi.c pcm.c pcm_min.c playmidi1.c queue_timer.c \ + rawmidi.c seq.c timer.c +DIST_SOURCES = client_event_filter.c control.c latency.c midiloop.c \ + namehint.c oldapi.c pcm.c pcm_min.c playmidi1.c queue_timer.c \ + rawmidi.c seq.c timer.c +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . lsb +control_LDADD = ../src/libasound.la +pcm_LDADD = ../src/libasound.la +pcm_min_LDADD = ../src/libasound.la +latency_LDADD = ../src/libasound.la +seq_LDADD = ../src/libasound.la +playmidi1_LDADD = ../src/libasound.la +timer_LDADD = ../src/libasound.la +rawmidi_LDADD = ../src/libasound.la +midiloop_LDADD = ../src/libasound.la +oldapi_LDADD = ../src/libasound.la +queue_timer_LDADD = ../src/libasound.la +namehint_LDADD = ../src/libasound.la +client_event_filter_LDADD = ../src/libasound.la +code_CFLAGS = -Wall -pipe -g -O2 +INCLUDES = -I$(top_srcdir)/include +AM_CFLAGS = -Wall -pipe -g +EXTRA_DIST = seq-decoder.c seq-sender.c midifile.h midifile.c midifile.3 +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +client_event_filter$(EXEEXT): $(client_event_filter_OBJECTS) $(client_event_filter_DEPENDENCIES) + @rm -f client_event_filter$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(client_event_filter_OBJECTS) $(client_event_filter_LDADD) $(LIBS) +control$(EXEEXT): $(control_OBJECTS) $(control_DEPENDENCIES) + @rm -f control$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(control_OBJECTS) $(control_LDADD) $(LIBS) +latency$(EXEEXT): $(latency_OBJECTS) $(latency_DEPENDENCIES) + @rm -f latency$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(latency_OBJECTS) $(latency_LDADD) $(LIBS) +midiloop$(EXEEXT): $(midiloop_OBJECTS) $(midiloop_DEPENDENCIES) + @rm -f midiloop$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(midiloop_OBJECTS) $(midiloop_LDADD) $(LIBS) +namehint$(EXEEXT): $(namehint_OBJECTS) $(namehint_DEPENDENCIES) + @rm -f namehint$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(namehint_OBJECTS) $(namehint_LDADD) $(LIBS) +oldapi$(EXEEXT): $(oldapi_OBJECTS) $(oldapi_DEPENDENCIES) + @rm -f oldapi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(oldapi_OBJECTS) $(oldapi_LDADD) $(LIBS) +pcm$(EXEEXT): $(pcm_OBJECTS) $(pcm_DEPENDENCIES) + @rm -f pcm$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(pcm_OBJECTS) $(pcm_LDADD) $(LIBS) +pcm_min$(EXEEXT): $(pcm_min_OBJECTS) $(pcm_min_DEPENDENCIES) + @rm -f pcm_min$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(pcm_min_OBJECTS) $(pcm_min_LDADD) $(LIBS) +playmidi1$(EXEEXT): $(playmidi1_OBJECTS) $(playmidi1_DEPENDENCIES) + @rm -f playmidi1$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(playmidi1_OBJECTS) $(playmidi1_LDADD) $(LIBS) +queue_timer$(EXEEXT): $(queue_timer_OBJECTS) $(queue_timer_DEPENDENCIES) + @rm -f queue_timer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(queue_timer_OBJECTS) $(queue_timer_LDADD) $(LIBS) +rawmidi$(EXEEXT): $(rawmidi_OBJECTS) $(rawmidi_DEPENDENCIES) + @rm -f rawmidi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(rawmidi_OBJECTS) $(rawmidi_LDADD) $(LIBS) +seq$(EXEEXT): $(seq_OBJECTS) $(seq_DEPENDENCIES) + @rm -f seq$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(seq_OBJECTS) $(seq_LDADD) $(LIBS) +timer$(EXEEXT): $(timer_OBJECTS) $(timer_DEPENDENCIES) + @rm -f timer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(timer_OBJECTS) $(timer_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client_event_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/latency.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midiloop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namehint.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oldapi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_min.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playmidi1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/queue_timer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-checkPROGRAMS \ + clean-generic clean-libtool ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/client_event_filter.c b/test/client_event_filter.c new file mode 100644 index 0000000..0650314 --- /dev/null +++ b/test/client_event_filter.c @@ -0,0 +1,46 @@ +#include + +void dump_event_filter(snd_seq_client_info_t *client_info) { + int i, b; + + for (i = 0; i <= 255;) { + b = snd_seq_client_info_event_filter_check(client_info, i); + i++; + printf("%c%s%s", (b ? 'X' : '.'), + (i % 8 == 0 ? " " : ""), + (i % 32 == 0 ? "\n" : "")); + } + printf("\n"); +} + +int main(void) { + snd_seq_client_info_t *client_info; + + snd_seq_client_info_alloca(&client_info); + + printf("first client_info_event_filter :\n"); + dump_event_filter(client_info); + + snd_seq_client_info_event_filter_add(client_info, SND_SEQ_EVENT_NOTEON); + printf("after snd_seq_client_info_event_filter_add(client_info, SND_SEQ_EVENT_NOTEON);\n"); + dump_event_filter(client_info); + + snd_seq_client_info_event_filter_add(client_info, SND_SEQ_EVENT_PGMCHANGE); + printf("after snd_seq_client_info_event_filter_add(client_info, SND_SEQ_EVENT_PGMCHANGE);\n"); + dump_event_filter(client_info); + + snd_seq_client_info_event_filter_del(client_info, SND_SEQ_EVENT_NOTEON); + printf("after snd_seq_client_info_event_filter_del(client_info, SND_SEQ_EVENT_NOTEON);\n"); + dump_event_filter(client_info); + + snd_seq_client_info_event_filter_clear(client_info); + printf("after snd_seq_client_info_event_filter_clear(client_info);\n"); + dump_event_filter(client_info); + + snd_seq_client_info_event_filter_add(client_info, SND_SEQ_EVENT_NOTEON); + printf("after snd_seq_client_info_event_filter_add(client_info, SND_SEQ_EVENT_NOTEON);\n"); + dump_event_filter(client_info); + + return 0; +} + diff --git a/test/control.c b/test/control.c new file mode 100644 index 0000000..f4b437e --- /dev/null +++ b/test/control.c @@ -0,0 +1,106 @@ +#include +#include +#include "../include/asoundlib.h" + +int main(void) +{ + int idx, dev, err; + snd_ctl_t *handle; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_rawmidi_info_t *rawmidiinfo; + char str[128]; + + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + snd_rawmidi_info_alloca(&rawmidiinfo); + + idx = -1; + while (1) { + if ((err = snd_card_next(&idx)) < 0) { + printf("Card next error: %s\n", snd_strerror(err)); + break; + } + if (idx < 0) + break; + sprintf(str, "hw:CARD=%i", idx); + if ((err = snd_ctl_open(&handle, str, 0)) < 0) { + printf("Open error: %s\n", snd_strerror(err)); + continue; + } + if ((err = snd_ctl_card_info(handle, info)) < 0) { + printf("HW info error: %s\n", snd_strerror(err)); + continue; + } + printf("Soundcard #%i:\n", idx + 1); + printf(" card - %i\n", snd_ctl_card_info_get_card(info)); + printf(" id - '%s'\n", snd_ctl_card_info_get_id(info)); + printf(" driver - '%s'\n", snd_ctl_card_info_get_driver(info)); + printf(" name - '%s'\n", snd_ctl_card_info_get_name(info)); + printf(" longname - '%s'\n", snd_ctl_card_info_get_longname(info)); + printf(" mixername - '%s'\n", snd_ctl_card_info_get_mixername(info)); + printf(" components - '%s'\n", snd_ctl_card_info_get_components(info)); + dev = -1; + while (1) { + snd_pcm_sync_id_t sync; + if ((err = snd_ctl_pcm_next_device(handle, &dev)) < 0) { + printf(" PCM next device error: %s\n", snd_strerror(err)); + break; + } + if (dev < 0) + break; + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); + if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) { + printf(" PCM info error: %s\n", snd_strerror(err)); + continue; + } + printf("PCM info, device #%i:\n", dev); + printf(" device - %i\n", snd_pcm_info_get_device(pcminfo)); + printf(" subdevice - %i\n", snd_pcm_info_get_subdevice(pcminfo)); + printf(" stream - %i\n", snd_pcm_info_get_stream(pcminfo)); + printf(" card - %i\n", snd_pcm_info_get_card(pcminfo)); + printf(" id - '%s'\n", snd_pcm_info_get_id(pcminfo)); + printf(" name - '%s'\n", snd_pcm_info_get_name(pcminfo)); + printf(" subdevice name - '%s'\n", snd_pcm_info_get_subdevice_name(pcminfo)); + printf(" class - 0x%x\n", snd_pcm_info_get_class(pcminfo)); + printf(" subclass - 0x%x\n", snd_pcm_info_get_subclass(pcminfo)); + printf(" subdevices count - %i\n", snd_pcm_info_get_subdevices_count(pcminfo)); + printf(" subdevices avail - %i\n", snd_pcm_info_get_subdevices_avail(pcminfo)); + sync = snd_pcm_info_get_sync(pcminfo); + printf(" sync - 0x%x,0x%x,0x%x,0x%x\n", sync.id32[0], sync.id32[1], sync.id32[2], sync.id32[3]); + } + dev = -1; + while (1) { + if ((err = snd_ctl_rawmidi_next_device(handle, &dev)) < 0) { + printf(" RAWMIDI next device error: %s\n", snd_strerror(err)); + break; + } + if (dev < 0) + break; + snd_rawmidi_info_set_device(rawmidiinfo, dev); + snd_rawmidi_info_set_subdevice(rawmidiinfo, 0); + snd_rawmidi_info_set_stream(rawmidiinfo, SND_RAWMIDI_STREAM_OUTPUT); + if ((err = snd_ctl_rawmidi_info(handle, rawmidiinfo)) < 0) { + printf(" RAWMIDI info error: %s\n", snd_strerror(err)); + continue; + } + printf("RAWMIDI info, device #%i:\n", dev); + printf(" device - %i\n", snd_rawmidi_info_get_device(rawmidiinfo)); + printf(" subdevice - %i\n", snd_rawmidi_info_get_subdevice(rawmidiinfo)); + printf(" stream - %i\n", snd_rawmidi_info_get_stream(rawmidiinfo)); + printf(" card - %i\n", snd_rawmidi_info_get_card(rawmidiinfo)); + printf(" flags - 0x%x\n", snd_rawmidi_info_get_flags(rawmidiinfo)); + printf(" id - '%s'\n", snd_rawmidi_info_get_id(rawmidiinfo)); + printf(" name - '%s'\n", snd_rawmidi_info_get_name(rawmidiinfo)); + printf(" subname - '%s'\n", snd_rawmidi_info_get_subdevice_name(rawmidiinfo)); + printf(" subdevices count - %i\n", snd_rawmidi_info_get_subdevices_count(rawmidiinfo)); + printf(" subdevices avail - %i\n", snd_rawmidi_info_get_subdevices_avail(rawmidiinfo)); + } + snd_ctl_close(handle); + } + + snd_config_update_free_global(); + return 0; +} diff --git a/test/latency.c b/test/latency.c new file mode 100644 index 0000000..03d65a2 --- /dev/null +++ b/test/latency.c @@ -0,0 +1,689 @@ +/* + * Latency test program + * + * Author: Jaroslav Kysela + * + * Author of bandpass filter sweep effect: + * Maarten de Boer + * + * This small demo program can be used for measuring latency between + * capture and playback. This latency is measured from driver (diff when + * playback and capture was started). Scheduler is set to SCHED_RR. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include "../include/asoundlib.h" +#include +#include + +char *pdevice = "hw:0,0"; +char *cdevice = "hw:0,0"; +snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; +int rate = 22050; +int channels = 2; +int buffer_size = 0; /* auto */ +int period_size = 0; /* auto */ +int latency_min = 32; /* in frames / 2 */ +int latency_max = 2048; /* in frames / 2 */ +int loop_sec = 30; /* seconds */ +int block = 0; /* block mode */ +int use_poll = 0; +int resample = 1; +unsigned long loop_limit; + +snd_output_t *output = NULL; + +int setparams_stream(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + const char *id) +{ + int err; + unsigned int rrate; + + err = snd_pcm_hw_params_any(handle, params); + if (err < 0) { + printf("Broken configuration for %s PCM: no configurations available: %s\n", snd_strerror(err), id); + return err; + } + err = snd_pcm_hw_params_set_rate_resample(handle, params, resample); + if (err < 0) { + printf("Resample setup failed for %s (val %i): %s\n", id, resample, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + printf("Access type not available for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_format(handle, params, format); + if (err < 0) { + printf("Sample format not available for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_set_channels(handle, params, channels); + if (err < 0) { + printf("Channels count (%i) not available for %s: %s\n", channels, id, snd_strerror(err)); + return err; + } + rrate = rate; + err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); + if (err < 0) { + printf("Rate %iHz not available for %s: %s\n", rate, id, snd_strerror(err)); + return err; + } + if ((int)rrate != rate) { + printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); + return -EINVAL; + } + return 0; +} + +int setparams_bufsize(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *tparams, + snd_pcm_uframes_t bufsize, + const char *id) +{ + int err; + snd_pcm_uframes_t periodsize; + + snd_pcm_hw_params_copy(params, tparams); + periodsize = bufsize * 2; + err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &periodsize); + if (err < 0) { + printf("Unable to set buffer size %li for %s: %s\n", bufsize * 2, id, snd_strerror(err)); + return err; + } + if (period_size > 0) + periodsize = period_size; + else + periodsize /= 2; + err = snd_pcm_hw_params_set_period_size_near(handle, params, &periodsize, 0); + if (err < 0) { + printf("Unable to set period size %li for %s: %s\n", periodsize, id, snd_strerror(err)); + return err; + } + return 0; +} + +int setparams_set(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + snd_pcm_sw_params_t *swparams, + const char *id) +{ + int err; + snd_pcm_uframes_t val; + + err = snd_pcm_hw_params(handle, params); + if (err < 0) { + printf("Unable to set hw params for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params_current(handle, swparams); + if (err < 0) { + printf("Unable to determine current swparams for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff); + if (err < 0) { + printf("Unable to set start threshold mode for %s: %s\n", id, snd_strerror(err)); + return err; + } + if (!block) + val = 4; + else + snd_pcm_hw_params_get_period_size(params, &val, NULL); + err = snd_pcm_sw_params_set_avail_min(handle, swparams, val); + if (err < 0) { + printf("Unable to set avail min for %s: %s\n", id, snd_strerror(err)); + return err; + } + err = snd_pcm_sw_params(handle, swparams); + if (err < 0) { + printf("Unable to set sw params for %s: %s\n", id, snd_strerror(err)); + return err; + } + return 0; +} + +int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize) +{ + int err, last_bufsize = *bufsize; + snd_pcm_hw_params_t *pt_params, *ct_params; /* templates with rate, format and channels */ + snd_pcm_hw_params_t *p_params, *c_params; + snd_pcm_sw_params_t *p_swparams, *c_swparams; + snd_pcm_uframes_t p_size, c_size, p_psize, c_psize; + unsigned int p_time, c_time; + + snd_pcm_hw_params_alloca(&p_params); + snd_pcm_hw_params_alloca(&c_params); + snd_pcm_hw_params_alloca(&pt_params); + snd_pcm_hw_params_alloca(&ct_params); + snd_pcm_sw_params_alloca(&p_swparams); + snd_pcm_sw_params_alloca(&c_swparams); + if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) { + printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err)); + exit(0); + } + if ((err = setparams_stream(chandle, ct_params, "capture")) < 0) { + printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err)); + exit(0); + } + + if (buffer_size > 0) { + *bufsize = buffer_size; + goto __set_it; + } + + __again: + if (buffer_size > 0) + return -1; + if (last_bufsize == *bufsize) + *bufsize += 4; + last_bufsize = *bufsize; + if (*bufsize > latency_max) + return -1; + __set_it: + if ((err = setparams_bufsize(phandle, p_params, pt_params, *bufsize, "playback")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + exit(0); + } + if ((err = setparams_bufsize(chandle, c_params, ct_params, *bufsize, "capture")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + exit(0); + } + + snd_pcm_hw_params_get_period_size(p_params, &p_psize, NULL); + if (p_psize > (unsigned int)*bufsize) + *bufsize = p_psize; + snd_pcm_hw_params_get_period_size(c_params, &c_psize, NULL); + if (c_psize > (unsigned int)*bufsize) + *bufsize = c_psize; + snd_pcm_hw_params_get_period_time(p_params, &p_time, NULL); + snd_pcm_hw_params_get_period_time(c_params, &c_time, NULL); + if (p_time != c_time) + goto __again; + + snd_pcm_hw_params_get_buffer_size(p_params, &p_size); + if (p_psize * 2 < p_size) + goto __again; + snd_pcm_hw_params_get_buffer_size(c_params, &c_size); + if (c_psize * 2 < c_size) + goto __again; + + if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + exit(0); + } + if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) { + printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); + exit(0); + } + + if ((err = snd_pcm_prepare(phandle)) < 0) { + printf("Prepare error: %s\n", snd_strerror(err)); + exit(0); + } + + snd_pcm_dump(phandle, output); + snd_pcm_dump(chandle, output); + fflush(stdout); + return 0; +} + +void showstat(snd_pcm_t *handle, size_t frames) +{ + int err; + snd_pcm_status_t *status; + + snd_pcm_status_alloca(&status); + if ((err = snd_pcm_status(handle, status)) < 0) { + printf("Stream status error: %s\n", snd_strerror(err)); + exit(0); + } + printf("*** frames = %li ***\n", (long)frames); + snd_pcm_status_dump(status, output); +} + +void showlatency(size_t latency) +{ + double d; + latency *= 2; + d = (double)latency / (double)rate; + printf("Trying latency %li frames, %.3fus, %.6fms (%.4fHz)\n", (long)latency, d * 1000000, d * 1000, (double)1 / d); +} + +void showinmax(size_t in_max) +{ + double d; + + printf("Maximum read: %li frames\n", (long)in_max); + d = (double)in_max / (double)rate; + printf("Maximum read latency: %.3fus, %.6fms (%.4fHz)\n", d * 1000000, d * 1000, (double)1 / d); +} + +void gettimestamp(snd_pcm_t *handle, snd_timestamp_t *timestamp) +{ + int err; + snd_pcm_status_t *status; + + snd_pcm_status_alloca(&status); + if ((err = snd_pcm_status(handle, status)) < 0) { + printf("Stream status error: %s\n", snd_strerror(err)); + exit(0); + } + snd_pcm_status_get_trigger_tstamp(status, timestamp); +} + +void setscheduler(void) +{ + struct sched_param sched_param; + + if (sched_getparam(0, &sched_param) < 0) { + printf("Scheduler getparam failed...\n"); + return; + } + sched_param.sched_priority = sched_get_priority_max(SCHED_RR); + if (!sched_setscheduler(0, SCHED_RR, &sched_param)) { + printf("Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority); + fflush(stdout); + return; + } + printf("!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority); +} + +long timediff(snd_timestamp_t t1, snd_timestamp_t t2) +{ + signed long l; + + t1.tv_sec -= t2.tv_sec; + l = (signed long) t1.tv_usec - (signed long) t2.tv_usec; + if (l < 0) { + t1.tv_sec--; + l = 1000000 + l; + l %= 1000000; + } + return (t1.tv_sec * 1000000) + l; +} + +long readbuf(snd_pcm_t *handle, char *buf, long len, size_t *frames, size_t *max) +{ + long r; + + if (!block) { + do { + r = snd_pcm_readi(handle, buf, len); + } while (r == -EAGAIN); + if (r > 0) { + *frames += r; + if ((long)*max < r) + *max = r; + } + // printf("read = %li\n", r); + } else { + int frame_bytes = (snd_pcm_format_width(format) / 8) * channels; + do { + r = snd_pcm_readi(handle, buf, len); + if (r > 0) { + buf += r * frame_bytes; + len -= r; + *frames += r; + if ((long)*max < r) + *max = r; + } + // printf("r = %li, len = %li\n", r, len); + } while (r >= 1 && len > 0); + } + // showstat(handle, 0); + return r; +} + +long writebuf(snd_pcm_t *handle, char *buf, long len, size_t *frames) +{ + long r; + + while (len > 0) { + r = snd_pcm_writei(handle, buf, len); + if (r == -EAGAIN) + continue; + // printf("write = %li\n", r); + if (r < 0) + return r; + // showstat(handle, 0); + buf += r * 4; + len -= r; + *frames += r; + } + return 0; +} + +#define FILTERSWEEP_LFO_CENTER 2000. +#define FILTERSWEEP_LFO_DEPTH 1800. +#define FILTERSWEEP_LFO_FREQ 0.2 +#define FILTER_BANDWIDTH 50 + +/* filter the sweep variables */ +float lfo,dlfo,fs,fc,BW,C,D,a0,a1,a2,b1,b2,*x[3],*y[3]; + +void applyeffect(char* buffer,int r) +{ + short* samples = (short*) buffer; + int i; + for (i=0;i2.*M_PI) lfo -= 2.*M_PI; + C = 1./tan(M_PI*BW/fs); + D = 2.*cos(2*M_PI*fc/fs); + a0 = 1./(1.+C); + a1 = 0; + a2 = -a0; + b1 = -C*D*a0; + b2 = (C-1)*a0; + + for (chn=0;chn= 4 ? err : 4; + if (latency_max < latency_min) + latency_max = latency_min; + break; + case 'M': + err = atoi(optarg) / 2; + latency_max = latency_min > err ? latency_min : err; + break; + case 'f': + format = snd_pcm_format_value(optarg); + if (format == SND_PCM_FORMAT_UNKNOWN) { + printf("Unknown format, setting to default S16_LE\n"); + format = SND_PCM_FORMAT_S16_LE; + } + break; + case 'c': + err = atoi(optarg); + channels = err >= 1 && err < 1024 ? err : 1; + break; + case 'r': + err = atoi(optarg); + rate = err >= 4000 && err < 200000 ? err : 44100; + break; + case 'B': + err = atoi(optarg); + buffer_size = err >= 32 && err < 200000 ? err : 0; + break; + case 'E': + err = atoi(optarg); + period_size = err >= 32 && err < 200000 ? err : 0; + break; + case 's': + err = atoi(optarg); + loop_sec = err >= 1 && err <= 100000 ? err : 30; + break; + case 'b': + block = 1; + break; + case 'p': + use_poll = 1; + break; + case 'e': + effect = 1; + break; + case 'n': + resample = 0; + break; + } + } + + if (morehelp) { + help(); + return 0; + } + err = snd_output_stdio_attach(&output, stdout, 0); + if (err < 0) { + printf("Output failed: %s\n", snd_strerror(err)); + return 0; + } + + loop_limit = loop_sec * rate; + latency = latency_min - 4; + buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2); + + setscheduler(); + + printf("Playback device is %s\n", pdevice); + printf("Capture device is %s\n", cdevice); + printf("Parameters are %iHz, %s, %i channels, %s mode\n", rate, snd_pcm_format_name(format), channels, block ? "blocking" : "non-blocking"); + printf("Poll mode: %s\n", use_poll ? "yes" : "no"); + printf("Loop limit is %li frames, minimum latency = %i, maximum latency = %i\n", loop_limit, latency_min * 2, latency_max * 2); + + if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) { + printf("Playback open error: %s\n", snd_strerror(err)); + return 0; + } + if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) { + printf("Record open error: %s\n", snd_strerror(err)); + return 0; + } + + /* initialize the filter sweep variables */ + if (effect) { + fs = (float) rate; + BW = FILTER_BANDWIDTH; + + lfo = 0; + dlfo = 2.*M_PI*FILTERSWEEP_LFO_FREQ/fs; + + x[0] = (float*) malloc(channels*sizeof(float)); + x[1] = (float*) malloc(channels*sizeof(float)); + x[2] = (float*) malloc(channels*sizeof(float)); + y[0] = (float*) malloc(channels*sizeof(float)); + y[1] = (float*) malloc(channels*sizeof(float)); + y[2] = (float*) malloc(channels*sizeof(float)); + } + + while (1) { + frames_in = frames_out = 0; + if (setparams(phandle, chandle, &latency) < 0) + break; + showlatency(latency); + if ((err = snd_pcm_link(chandle, phandle)) < 0) { + printf("Streams link error: %s\n", snd_strerror(err)); + exit(0); + } + if (snd_pcm_format_set_silence(format, buffer, latency*channels) < 0) { + fprintf(stderr, "silence error\n"); + break; + } + if (writebuf(phandle, buffer, latency, &frames_out) < 0) { + fprintf(stderr, "write error\n"); + break; + } + if (writebuf(phandle, buffer, latency, &frames_out) < 0) { + fprintf(stderr, "write error\n"); + break; + } + + if ((err = snd_pcm_start(chandle)) < 0) { + printf("Go error: %s\n", snd_strerror(err)); + exit(0); + } + gettimestamp(phandle, &p_tstamp); + gettimestamp(chandle, &c_tstamp); +#if 0 + printf("Playback:\n"); + showstat(phandle, frames_out); + printf("Capture:\n"); + showstat(chandle, frames_in); +#endif + + ok = 1; + in_max = 0; + while (ok && frames_in < loop_limit) { + if (use_poll) { + /* use poll to wait for next event */ + snd_pcm_wait(chandle, 1000); + } + if ((r = readbuf(chandle, buffer, latency, &frames_in, &in_max)) < 0) + ok = 0; + else { + if (effect) + applyeffect(buffer,r); + if (writebuf(phandle, buffer, r, &frames_out) < 0) + ok = 0; + } + } + if (ok) + printf("Success\n"); + else + printf("Failure\n"); + printf("Playback:\n"); + showstat(phandle, frames_out); + printf("Capture:\n"); + showstat(chandle, frames_in); + showinmax(in_max); + if (p_tstamp.tv_sec == p_tstamp.tv_sec && + p_tstamp.tv_usec == c_tstamp.tv_usec) + printf("Hardware sync\n"); + snd_pcm_drop(chandle); + snd_pcm_nonblock(phandle, 0); + snd_pcm_drain(phandle); + snd_pcm_nonblock(phandle, !block ? 1 : 0); + if (ok) { +#if 1 + printf("Playback time = %li.%i, Record time = %li.%i, diff = %li\n", + p_tstamp.tv_sec, + (int)p_tstamp.tv_usec, + c_tstamp.tv_sec, + (int)c_tstamp.tv_usec, + timediff(p_tstamp, c_tstamp)); +#endif + break; + } + snd_pcm_unlink(chandle); + snd_pcm_hw_free(phandle); + snd_pcm_hw_free(chandle); + } + snd_pcm_close(phandle); + snd_pcm_close(chandle); + return 0; +} diff --git a/test/lsb/Makefile.am b/test/lsb/Makefile.am new file mode 100644 index 0000000..ceb4d71 --- /dev/null +++ b/test/lsb/Makefile.am @@ -0,0 +1,7 @@ +TESTS = config +TESTS += midi_event +check_PROGRAMS = $(TESTS) +noinst_HEADERS = test.h + +AM_CFLAGS = -Wall -pipe +LDADD = ../../src/libasound.la diff --git a/test/lsb/Makefile.in b/test/lsb/Makefile.in new file mode 100644 index 0000000..28816ba --- /dev/null +++ b/test/lsb/Makefile.in @@ -0,0 +1,608 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +TESTS = config$(EXEEXT) midi_event$(EXEEXT) +check_PROGRAMS = $(am__EXEEXT_1) +subdir = test/lsb +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__EXEEXT_1 = config$(EXEEXT) midi_event$(EXEEXT) +config_SOURCES = config.c +config_OBJECTS = config.$(OBJEXT) +config_LDADD = $(LDADD) +config_DEPENDENCIES = ../../src/libasound.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +midi_event_SOURCES = midi_event.c +midi_event_OBJECTS = midi_event.$(OBJEXT) +midi_event_LDADD = $(LDADD) +midi_event_DEPENDENCIES = ../../src/libasound.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = config.c midi_event.c +DIST_SOURCES = config.c midi_event.c +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_HEADERS = test.h +AM_CFLAGS = -Wall -pipe +LDADD = ../../src/libasound.la +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/lsb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/lsb/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +config$(EXEEXT): $(config_OBJECTS) $(config_DEPENDENCIES) + @rm -f config$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(config_OBJECTS) $(config_LDADD) $(LIBS) +midi_event$(EXEEXT): $(midi_event_OBJECTS) $(midi_event_DEPENDENCIES) + @rm -f midi_event$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(midi_event_OBJECTS) $(midi_event_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midi_event.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/lsb/config.c b/test/lsb/config.c new file mode 100644 index 0000000..3503798 --- /dev/null +++ b/test/lsb/config.c @@ -0,0 +1,582 @@ +#include +#include +#include +#include "test.h" + +static int configs_equal(snd_config_t *c1, snd_config_t *c2); + +/* checks if all children of c1 also occur in c2 */ +static int subset_of(snd_config_t *c1, snd_config_t *c2) +{ + snd_config_iterator_t i, next; + snd_config_t *e1, *e2; + const char *id; + + snd_config_for_each(i, next, c1) { + e1 = snd_config_iterator_entry(i); + if (snd_config_get_id(e1, &id) < 0 || !id) + return 0; + if (snd_config_search(c2, id, &e2) < 0) + return 0; + if (!configs_equal(e1, e2)) + return 0; + } + return 1; +} + +/* checks if two configuration nodes are equal */ +static int configs_equal(snd_config_t *c1, snd_config_t *c2) +{ + long i1, i2; + long long i641, i642; + const char *s1, *s2; + + if (snd_config_get_type(c1) != snd_config_get_type(c2)) + return 0; + switch (snd_config_get_type(c1)) { + case SND_CONFIG_TYPE_INTEGER: + return snd_config_get_integer(c1, &i1) >= 0 && + snd_config_get_integer(c2, &i2) >= 0 && + i1 == i2; + case SND_CONFIG_TYPE_INTEGER64: + return snd_config_get_integer64(c1, &i641) >= 0 && + snd_config_get_integer64(c2, &i642) >= 0 && + i641 == i642; + case SND_CONFIG_TYPE_STRING: + return snd_config_get_string(c1, &s1) >= 0 && + snd_config_get_string(c2, &s2) >= 0 && + !s1 == !s2 && + (!s1 || !strcmp(s1, s2)); + case SND_CONFIG_TYPE_COMPOUND: + return subset_of(c1, c2) && subset_of(c2, c1); + default: + fprintf(stderr, "unknown configuration node type %d\n", + (int)snd_config_get_type(c1)); + return 0; + } +} + +static void test_top(void) +{ + snd_config_t *top; + const char *id; + + if (ALSA_CHECK(snd_config_top(&top)) < 0) + return; + + TEST_CHECK(snd_config_get_type(top) == SND_CONFIG_TYPE_COMPOUND); + TEST_CHECK(snd_config_iterator_first(top) == snd_config_iterator_end(top)); + TEST_CHECK(snd_config_get_id(top, &id) >= 0 && id == NULL); + + ALSA_CHECK(snd_config_delete(top)); +} + +static void test_load(void) +{ + const char *config_text1 = "s='world';"; + const char *config_text2 = "c.elem 0"; + snd_config_t *loaded, *made, *c, *c2; + snd_input_t *input; + + ALSA_CHECK(snd_config_top(&loaded)); + ALSA_CHECK(snd_config_imake_integer(&c, "i", 42)); + ALSA_CHECK(snd_config_add(loaded, c)); + ALSA_CHECK(snd_config_imake_string(&c, "s", "hello")); + ALSA_CHECK(snd_config_add(loaded, c)); + + ALSA_CHECK(snd_config_top(&made)); + ALSA_CHECK(snd_config_imake_string(&c, "s", "world")); + ALSA_CHECK(snd_config_add(made, c)); + ALSA_CHECK(snd_config_imake_integer(&c, "i", 42)); + ALSA_CHECK(snd_config_add(made, c)); + + ALSA_CHECK(snd_input_buffer_open(&input, config_text1, strlen(config_text1))); + ALSA_CHECK(snd_config_load(loaded, input)); + ALSA_CHECK(snd_input_close(input)); + TEST_CHECK(configs_equal(loaded, made)); + + ALSA_CHECK(snd_config_make_compound(&c, "c", 0)); + ALSA_CHECK(snd_config_add(made, c)); + ALSA_CHECK(snd_config_imake_integer(&c2, "elem", 0)); + ALSA_CHECK(snd_config_add(c, c2)); + + ALSA_CHECK(snd_input_buffer_open(&input, config_text2, strlen(config_text2))); + ALSA_CHECK(snd_config_load(loaded, input)); + ALSA_CHECK(snd_input_close(input)); + TEST_CHECK(configs_equal(loaded, made)); + + ALSA_CHECK(snd_config_delete(loaded)); + ALSA_CHECK(snd_config_delete(made)); +} + +static void test_save(void) +{ + const char *text = + "a.b.c 'x.y.z'\n" + "xxx = yyy;\n" + "q { qq=qqq }\n" + "a [ 1 2 3 4 5 '...' ]\n"; + snd_config_t *orig, *saved; + snd_input_t *input; + snd_output_t *output; + char *buf; + size_t buf_size; + + ALSA_CHECK(snd_input_buffer_open(&input, text, strlen(text))); + ALSA_CHECK(snd_config_top(&orig)); + ALSA_CHECK(snd_config_load(orig, input)); + ALSA_CHECK(snd_input_close(input)); + ALSA_CHECK(snd_output_buffer_open(&output)); + ALSA_CHECK(snd_config_save(orig, output)); + buf_size = snd_output_buffer_string(output, &buf); + ALSA_CHECK(snd_input_buffer_open(&input, buf, buf_size)); + ALSA_CHECK(snd_config_top(&saved)); + ALSA_CHECK(snd_config_load(saved, input)); + ALSA_CHECK(snd_input_close(input)); + ALSA_CHECK(snd_output_close(output)); + TEST_CHECK(configs_equal(orig, saved)); + ALSA_CHECK(snd_config_delete(orig)); + ALSA_CHECK(snd_config_delete(saved)); +} + +static void test_update(void) +{ + ALSA_CHECK(snd_config_update_free_global()); + TEST_CHECK(snd_config == NULL); + ALSA_CHECK(snd_config_update()); + TEST_CHECK(snd_config_get_type(snd_config) == SND_CONFIG_TYPE_COMPOUND); + ALSA_CHECK(snd_config_update()); + TEST_CHECK(snd_config_get_type(snd_config) == SND_CONFIG_TYPE_COMPOUND); + ALSA_CHECK(snd_config_update_free_global()); + TEST_CHECK(snd_config == NULL); +} + +static void test_search(void) +{ + const char *text = + "a 42\n" + "b {\n" + " c cee\n" + " d {\n" + " e 2.71828\n" + " }\n" + "}\n"; + snd_input_t *input; + snd_config_t *top, *c; + const char *id; + + ALSA_CHECK(snd_input_buffer_open(&input, text, strlen(text))); + ALSA_CHECK(snd_config_top(&top)); + ALSA_CHECK(snd_config_load(top, input)); + ALSA_CHECK(snd_input_close(input)); + + ALSA_CHECK(snd_config_search(top, "a", &c)); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "a")); + ALSA_CHECK(snd_config_search(top, "b.d.e", &c)); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "e")); + ALSA_CHECK(snd_config_search(top, "b.c", NULL)); + TEST_CHECK(snd_config_search(top, "x", NULL) == -ENOENT); + TEST_CHECK(snd_config_search(top, "b.y", &c) == -ENOENT); + TEST_CHECK(snd_config_search(top, "a.z", &c) == -ENOENT); + + ALSA_CHECK(snd_config_delete(top)); +} + +static void test_searchv(void) +{ + const char *text = + "a 42\n" + "b {\n" + " c cee\n" + " d {\n" + " e 2.71828\n" + " }\n" + "}\n"; + snd_input_t *input; + snd_config_t *top, *c; + const char *id; + + ALSA_CHECK(snd_input_buffer_open(&input, text, strlen(text))); + ALSA_CHECK(snd_config_top(&top)); + ALSA_CHECK(snd_config_load(top, input)); + ALSA_CHECK(snd_input_close(input)); + + ALSA_CHECK(snd_config_searchv(top, &c, "a", NULL)); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "a")); + ALSA_CHECK(snd_config_searchv(top, &c, "b", "d.e", NULL)); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "e")); + ALSA_CHECK(snd_config_searchv(top, NULL, "b.c", NULL)); + TEST_CHECK(snd_config_searchv(top, NULL, "x", NULL) == -ENOENT); + TEST_CHECK(snd_config_searchv(top, &c, "b.y", NULL) == -ENOENT); + TEST_CHECK(snd_config_searchv(top, &c, "a", "z", NULL) == -ENOENT); + + ALSA_CHECK(snd_config_delete(top)); +} + +static void test_add(void) +{ + snd_config_t *c1, *c2, *c3, *c4, *c5; + snd_config_iterator_t i; + unsigned int count = 0; + + ALSA_CHECK(snd_config_top(&c1)); + ALSA_CHECK(snd_config_imake_integer(&c2, "c2", 0xc2)); + ALSA_CHECK(snd_config_add(c1, c2)); + ALSA_CHECK(snd_config_imake_string(&c3, "c3", "c3")); + ALSA_CHECK(snd_config_add(c1, c3)); + for (i = snd_config_iterator_first(c1); + i != snd_config_iterator_end(c1); + i = snd_config_iterator_next(i)) + ++count; + TEST_CHECK(count == 2); + ALSA_CHECK(snd_config_search(c1, "c2", &c2)); + ALSA_CHECK(snd_config_search(c1, "c3", &c3)); + ALSA_CHECK(snd_config_top(&c4)); + TEST_CHECK(snd_config_add(c1, c4) == -EINVAL); + ALSA_CHECK(snd_config_imake_integer(&c5, "c5", 5)); + ALSA_CHECK(snd_config_add(c4, c5)); + TEST_CHECK(snd_config_add(c1, c5) == -EINVAL); + ALSA_CHECK(snd_config_delete(c4)); + ALSA_CHECK(snd_config_imake_integer(&c3, "c3", 333)); + TEST_CHECK(snd_config_add(c1, c3) == -EEXIST); + ALSA_CHECK(snd_config_delete(c3)); + ALSA_CHECK(snd_config_delete(c1)); +} + +static void test_delete(void) +{ + snd_config_t *c; + + ALSA_CHECK(snd_config_top(&c)); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_imake_string(&c, "s", "...")); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_copy(void) +{ + snd_config_t *c1, *c2, *c3; + long value; + + ALSA_CHECK(snd_config_imake_integer(&c1, "c1", 123)); + ALSA_CHECK(snd_config_copy(&c2, c1)); + ALSA_CHECK(snd_config_set_integer(c1, 456)); + TEST_CHECK(snd_config_get_type(c2) == SND_CONFIG_TYPE_INTEGER); + ALSA_CHECK(snd_config_get_integer(c2, &value)); + TEST_CHECK(value == 123); + ALSA_CHECK(snd_config_delete(c1)); + ALSA_CHECK(snd_config_delete(c2)); + ALSA_CHECK(snd_config_top(&c1)); + ALSA_CHECK(snd_config_imake_integer(&c2, "a", 1)); + ALSA_CHECK(snd_config_add(c1, c2)); + ALSA_CHECK(snd_config_copy(&c3, c1)); + ALSA_CHECK(snd_config_set_integer(c2, 2)); + TEST_CHECK(!configs_equal(c1, c3)); + ALSA_CHECK(snd_config_search(c3, "a", &c2)); + ALSA_CHECK(snd_config_set_integer(c2, 2)); + TEST_CHECK(configs_equal(c1, c3)); + ALSA_CHECK(snd_config_delete(c1)); + ALSA_CHECK(snd_config_delete(c3)); +} + +static void test_make_integer(void) +{ + snd_config_t *c; + const char *id; + long value; + + ALSA_CHECK(snd_config_make_integer(&c, "i")); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_INTEGER); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "i")); + ALSA_CHECK(snd_config_get_integer(c, &value)); + TEST_CHECK(value == 0); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_make_integer64(void) +{ + snd_config_t *c; + const char *id; + long long value; + + ALSA_CHECK(snd_config_make_integer64(&c, "i")); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_INTEGER64); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "i")); + ALSA_CHECK(snd_config_get_integer64(c, &value)); + TEST_CHECK(value == 0); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_make_string(void) +{ + snd_config_t *c; + const char *id; + const char *value; + + ALSA_CHECK(snd_config_make_string(&c, "s")); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_STRING); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "s")); + ALSA_CHECK(snd_config_get_string(c, &value)); + TEST_CHECK(value == NULL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_make_compound(void) +{ + snd_config_t *c; + const char *id; + + ALSA_CHECK(snd_config_make_compound(&c, "c", 0)); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_COMPOUND); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "c")); + TEST_CHECK(snd_config_iterator_first(c) == snd_config_iterator_end(c)); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_imake_integer(void) +{ + snd_config_t *c; + const char *id; + long value; + + ALSA_CHECK(snd_config_imake_integer(&c, "i", 123)); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_INTEGER); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "i")); + ALSA_CHECK(snd_config_get_integer(c, &value)); + TEST_CHECK(value == 123); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_imake_integer64(void) +{ + snd_config_t *c; + const char *id; + long long value; + + ALSA_CHECK(snd_config_imake_integer64(&c, "i", 123456789012345LL)); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_INTEGER64); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "i")); + ALSA_CHECK(snd_config_get_integer64(c, &value)); + TEST_CHECK(value == 123456789012345LL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_imake_string(void) +{ + snd_config_t *c; + const char *id; + const char *value; + + ALSA_CHECK(snd_config_imake_string(&c, "s", "xyzzy")); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_STRING); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "s")); + ALSA_CHECK(snd_config_get_string(c, &value)); + TEST_CHECK(!strcmp(value, "xyzzy")); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_get_type(void) +{ + snd_config_t *c; + + ALSA_CHECK(snd_config_top(&c)); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_COMPOUND); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_make_integer(&c, "i")); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_INTEGER); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_make_string(&c, "s")); + TEST_CHECK(snd_config_get_type(c) == SND_CONFIG_TYPE_STRING); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_set_integer(void) +{ + snd_config_t *c; + long value; + + ALSA_CHECK(snd_config_make_integer(&c, "i")); + ALSA_CHECK(snd_config_set_integer(c, 123)); + ALSA_CHECK(snd_config_get_integer(c, &value)); + TEST_CHECK(value == 123); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_make_string(&c, "s")); + TEST_CHECK(snd_config_set_integer(c, 123) == -EINVAL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_set_integer64(void) +{ + snd_config_t *c; + long long value; + + ALSA_CHECK(snd_config_make_integer64(&c, "i")); + ALSA_CHECK(snd_config_set_integer64(c, 123456789012345LL)); + ALSA_CHECK(snd_config_get_integer64(c, &value)); + TEST_CHECK(value == 123456789012345LL); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_make_string(&c, "s")); + TEST_CHECK(snd_config_set_integer64(c, 123) == -EINVAL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_set_string(void) +{ + snd_config_t *c; + const char *value; + + ALSA_CHECK(snd_config_make_string(&c, "s")); + ALSA_CHECK(snd_config_set_string(c, "string")); + ALSA_CHECK(snd_config_get_string(c, &value)); + TEST_CHECK(!strcmp(value, "string")); + ALSA_CHECK(snd_config_set_string(c, NULL)); + ALSA_CHECK(snd_config_get_string(c, &value)); + TEST_CHECK(value == NULL); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_make_integer(&c, "i")); + TEST_CHECK(snd_config_set_string(c, "") == -EINVAL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_set_ascii(void) +{ + snd_config_t *c; + const char *s; + long i; + + ALSA_CHECK(snd_config_make_string(&c, "s")); + ALSA_CHECK(snd_config_set_ascii(c, "foo")); + ALSA_CHECK(snd_config_get_string(c, &s)); + TEST_CHECK(!strcmp(s, "foo")); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_make_integer(&c, "i")); + ALSA_CHECK(snd_config_set_ascii(c, "23")); + ALSA_CHECK(snd_config_get_integer(c, &i)); + TEST_CHECK(i == 23); + TEST_CHECK(snd_config_set_ascii(c, "half blue") == -EINVAL); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_top(&c)); + TEST_CHECK(snd_config_set_ascii(c, "0") == -EINVAL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_get_id(void) +{ + snd_config_t *c; + const char *id; + + ALSA_CHECK(snd_config_make_integer(&c, "my_id")); + ALSA_CHECK(snd_config_get_id(c, &id)); + TEST_CHECK(!strcmp(id, "my_id")); + ALSA_CHECK(snd_config_delete(c)); +} + +#define test_get_integer test_set_integer +#define test_get_integer64 test_set_integer64 +#define test_get_string test_set_string + +static void test_get_ascii(void) +{ + snd_config_t *c; + char *value; + + ALSA_CHECK(snd_config_imake_integer(&c, "i", 123)); + ALSA_CHECK(snd_config_get_ascii(c, &value)); + TEST_CHECK(!strcmp(value, "123")); + free(value); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_imake_string(&c, "s", "bar")); + ALSA_CHECK(snd_config_get_ascii(c, &value)); + TEST_CHECK(!strcmp(value, "bar")); + free(value); + ALSA_CHECK(snd_config_delete(c)); + ALSA_CHECK(snd_config_top(&c)); + TEST_CHECK(snd_config_get_ascii(c, &value) == -EINVAL); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_iterators(void) +{ + snd_config_t *c, *c2; + snd_config_iterator_t i; + long v; + + ALSA_CHECK(snd_config_top(&c)); + i = snd_config_iterator_first(c); + TEST_CHECK(i == snd_config_iterator_end(c)); + ALSA_CHECK(snd_config_imake_integer(&c2, "one", 1)); + ALSA_CHECK(snd_config_add(c, c2)); + i = snd_config_iterator_first(c); + TEST_CHECK(i != snd_config_iterator_end(c)); + c2 = snd_config_iterator_entry(i); + ALSA_CHECK(snd_config_get_integer(c2, &v)); + TEST_CHECK(v == 1); + i = snd_config_iterator_next(i); + TEST_CHECK(i == snd_config_iterator_end(c)); + ALSA_CHECK(snd_config_delete(c)); +} + +static void test_for_each(void) +{ + snd_config_t *c, *c2; + snd_config_iterator_t i, next; + long v; + unsigned int count = 0; + + ALSA_CHECK(snd_config_top(&c)); + ALSA_CHECK(snd_config_imake_integer(&c2, "one", 1)); + ALSA_CHECK(snd_config_add(c, c2)); + snd_config_for_each(i, next, c) { + TEST_CHECK(i != snd_config_iterator_end(c)); + c2 = snd_config_iterator_entry(i); + ALSA_CHECK(snd_config_get_integer(c2, &v)); + TEST_CHECK(v == 1); + ++count; + } + TEST_CHECK(count == 1); + ALSA_CHECK(snd_config_delete(c)); +} + +int main(void) +{ + test_top(); + test_load(); + test_save(); + test_update(); + test_search(); + test_searchv(); + test_add(); + test_delete(); + test_copy(); + test_make_integer(); + test_make_integer64(); + test_make_string(); + test_make_compound(); + test_imake_integer(); + test_imake_integer64(); + test_imake_string(); + test_get_type(); + test_set_integer(); + test_set_integer64(); + test_set_string(); + test_set_ascii(); + test_get_id(); + test_get_integer(); + test_get_integer64(); + test_get_string(); + test_get_ascii(); + test_iterators(); + test_for_each(); + return TEST_EXIT_CODE(); +} diff --git a/test/lsb/midi_event.c b/test/lsb/midi_event.c new file mode 100644 index 0000000..2ae90a7 --- /dev/null +++ b/test/lsb/midi_event.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include +#include "test.h" + +/* + * Checks whether the regular expression matches the entire MIDI data, printed + * as hex. + */ +static int midi_matches_regex(unsigned char *midi, int count, const char *regex) +{ + char *text; + regex_t re; + regmatch_t match; + int i; + + text = malloc(2 * count + 1); + if (!text) + return 0; + for (i = 0; i < count; ++i) + sprintf(text + 2 * i, "%02x", midi[i]); + if (regcomp(&re, regex, REG_EXTENDED) != 0) { + free(text); + return 0; + } + i = regexec(&re, text, 1, &match, 0); + i = i == 0 && match.rm_so == 0 && match.rm_eo == strlen(text); + regfree(&re); + free(text); + return i; +} + +static void test_decode(void) +{ + snd_midi_event_t *midi_event; + snd_seq_event_t ev; + unsigned char buf[50]; + int count; + + if (ALSA_CHECK(snd_midi_event_new(256 /* ? */, &midi_event)) < 0) + return; + +#define DECODE() snd_midi_event_decode(midi_event, buf, sizeof(buf), &ev) +#define BUF_MATCHES(str) midi_matches_regex(buf, count, str) +#define DECODES_TO(str) ((count = DECODE()), BUF_MATCHES(str)) + + snd_seq_ev_clear(&ev); + + snd_seq_ev_set_fixed(&ev); + ev.type = SND_SEQ_EVENT_NONE; + TEST_CHECK(DECODE() == -ENOENT); + + snd_seq_ev_set_noteoff(&ev, 1, 2, 3); + TEST_CHECK(DECODES_TO("810203")); + + snd_seq_ev_set_noteon(&ev, 4, 5, 6); + TEST_CHECK(DECODES_TO("940506")); + + snd_seq_ev_set_keypress(&ev, 7, 8, 9); + TEST_CHECK(DECODES_TO("a70809")); + + snd_seq_ev_set_controller(&ev, 10, 11, 12); + TEST_CHECK(DECODES_TO("ba0b0c")); + + snd_seq_ev_set_pgmchange(&ev, 13, 14); + TEST_CHECK(DECODES_TO("cd0e")); + + snd_seq_ev_set_chanpress(&ev, 15, 16); + TEST_CHECK(DECODES_TO("df10")); + + snd_seq_ev_set_pitchbend(&ev, 1, 0x222); + TEST_CHECK(DECODES_TO("e12244")); + + snd_seq_ev_set_sysex(&ev, 6, "\xf0\x7e\x7f\x06\x01\xf7"); + TEST_CHECK(DECODES_TO("f07e7f0601f7")); + + snd_seq_ev_set_fixed(&ev); + ev.type = SND_SEQ_EVENT_QFRAME; + ev.data.control.value = 3; + TEST_CHECK(DECODES_TO("f103")); + + ev.type = SND_SEQ_EVENT_SONGPOS; + ev.data.control.value = 0x444; + TEST_CHECK(DECODES_TO("f24408")); + + ev.type = SND_SEQ_EVENT_SONGSEL; + ev.data.control.value = 5; + TEST_CHECK(DECODES_TO("f305")); + + ev.type = SND_SEQ_EVENT_TUNE_REQUEST; + TEST_CHECK(DECODES_TO("f6")); + + ev.type = SND_SEQ_EVENT_CLOCK; + TEST_CHECK(DECODES_TO("f8")); + + ev.type = SND_SEQ_EVENT_START; + TEST_CHECK(DECODES_TO("fa")); + + ev.type = SND_SEQ_EVENT_CONTINUE; + TEST_CHECK(DECODES_TO("fb")); + + ev.type = SND_SEQ_EVENT_STOP; + TEST_CHECK(DECODES_TO("fc")); + + ev.type = SND_SEQ_EVENT_SENSING; + TEST_CHECK(DECODES_TO("fe")); + + ev.type = SND_SEQ_EVENT_RESET; + TEST_CHECK(DECODES_TO("ff")); + + ev.type = SND_SEQ_EVENT_CONTROL14; + ev.data.control.channel = 6; + ev.data.control.param = 7; + ev.data.control.value = 0x888; + /* + * This regular expression catches all allowed combinations of LSB/MSB + * order and running status. + */ + TEST_CHECK(DECODES_TO("b6(0711(b6)?2708|2708(b6)?0711)")); + + ev.type = SND_SEQ_EVENT_NONREGPARAM; + ev.data.control.channel = 9; + ev.data.control.param = 0xaaa; + ev.data.control.value = 0xbbb; + TEST_CHECK(DECODES_TO("b9(622a(b9)?6315|6315(b9)?622a)(b9)?(0617(b9)?263b|263b(b9)?0617)")); + + ev.type = SND_SEQ_EVENT_REGPARAM; + ev.data.control.channel = 12; + ev.data.control.param = 0xddd; + ev.data.control.value = 0xeee; + TEST_CHECK(DECODES_TO("bc(645d(bc)?651b|651b(bc)?645d)(bc)?(061d(bc)?266e|266e(bc)?061d)")); + + /* no running status after SysEx */ + snd_seq_ev_set_pgmchange(&ev, 0, 0x11); + TEST_CHECK(DECODES_TO("c011")); + snd_seq_ev_set_sysex(&ev, 6, "\xf0\x7e\x7f\x09\x02\xf7"); + TEST_CHECK(DECODES_TO("f07e7f0902f7")); + snd_seq_ev_set_pgmchange(&ev, 0, 0x11); + TEST_CHECK(DECODES_TO("c011")); + + /* no running status for non-realtime common messages */ + ev.type = SND_SEQ_EVENT_QFRAME; + ev.data.control.value = 0x11; + TEST_CHECK(DECODES_TO("f111")); + TEST_CHECK(DECODES_TO("f111")); + + /* buffer overflow */ + TEST_CHECK(snd_midi_event_decode(midi_event, buf, 1, &ev) == -ENOMEM); + + snd_midi_event_free(midi_event); +} + +static void test_reset_decode(void) +{ + snd_midi_event_t *midi_event; + snd_seq_event_t ev; + unsigned char buf[50]; + int count; + + if (ALSA_CHECK(snd_midi_event_new(256 /* ? */, &midi_event)) < 0) + return; + + snd_seq_ev_clear(&ev); + + snd_seq_ev_set_noteon(&ev, 1, 2, 3); + TEST_CHECK(DECODES_TO("910203")); + + snd_midi_event_reset_decode(midi_event); + + TEST_CHECK(DECODES_TO("910203")); + + snd_midi_event_free(midi_event); +} + +static void test_encode(void) +{ + snd_midi_event_t *midi_event; + snd_seq_event_t ev; + + if (ALSA_CHECK(snd_midi_event_new(256, &midi_event)) < 0) + return; + +#define ENCODE(str) snd_midi_event_encode(midi_event, \ + (const unsigned char *)str, \ + sizeof(str) - 1, &ev) + TEST_CHECK(ENCODE("\x81\x02\x03") == 3); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NOTEOFF); + TEST_CHECK((ev.flags & SND_SEQ_EVENT_LENGTH_MASK) == SND_SEQ_EVENT_LENGTH_FIXED); + TEST_CHECK(ev.data.note.channel == 1); + TEST_CHECK(ev.data.note.note == 2); + TEST_CHECK(ev.data.note.velocity == 3); + + TEST_CHECK(ENCODE("\x94\x05\x06") == 3); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NOTEON); + TEST_CHECK(ev.data.note.channel == 4); + TEST_CHECK(ev.data.note.note == 5); + TEST_CHECK(ev.data.note.velocity == 6); + + TEST_CHECK(ENCODE("\xa7\x08\x09") == 3); + TEST_CHECK(ev.type == SND_SEQ_EVENT_KEYPRESS); + TEST_CHECK(ev.data.note.channel == 7); + TEST_CHECK(ev.data.note.note == 8); + TEST_CHECK(ev.data.note.velocity == 9); + + TEST_CHECK(ENCODE("\xba\x0b\x0c") == 3); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CONTROLLER); + TEST_CHECK(ev.data.control.channel == 10); + TEST_CHECK(ev.data.control.param == 11); + TEST_CHECK(ev.data.control.value == 12); + + TEST_CHECK(ENCODE("\xcd\x0e") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_PGMCHANGE); + TEST_CHECK(ev.data.control.channel == 13); + TEST_CHECK(ev.data.control.value == 14); + + TEST_CHECK(ENCODE("\xdf\x10") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CHANPRESS); + TEST_CHECK(ev.data.control.channel == 15); + TEST_CHECK(ev.data.control.value == 16); + + TEST_CHECK(ENCODE("\xe1\x22\x33") == 3); + TEST_CHECK(ev.type == SND_SEQ_EVENT_PITCHBEND); + TEST_CHECK(ev.data.control.channel == 1); + TEST_CHECK(ev.data.control.value == -1630); + + TEST_CHECK(ENCODE("\xf0\x7f\x7f\x04\x01\x7f\x7f\xf7") == 8); + TEST_CHECK(ev.type == SND_SEQ_EVENT_SYSEX); + TEST_CHECK((ev.flags & SND_SEQ_EVENT_LENGTH_MASK) == SND_SEQ_EVENT_LENGTH_VARIABLE); + TEST_CHECK(ev.data.ext.len == 8); + TEST_CHECK(!memcmp(ev.data.ext.ptr, "\xf0\x7f\x7f\x04\x01\x7f\x7f\xf7", 8)); + + TEST_CHECK(ENCODE("\xf1\x04") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_QFRAME); + TEST_CHECK(ev.data.control.value == 4); + + TEST_CHECK(ENCODE("\xf2\x55\x66") == 3); + TEST_CHECK(ev.type == SND_SEQ_EVENT_SONGPOS); + TEST_CHECK(ev.data.control.value == 13141); + + TEST_CHECK(ENCODE("\xf3\x07") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_SONGSEL); + TEST_CHECK(ev.data.control.value == 7); + + TEST_CHECK(ENCODE("\xf6") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_TUNE_REQUEST); + + TEST_CHECK(ENCODE("\xf8") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CLOCK); + + TEST_CHECK(ENCODE("\xfa") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_START); + + TEST_CHECK(ENCODE("\xfb") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CONTINUE); + + TEST_CHECK(ENCODE("\xfc") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_STOP); + + TEST_CHECK(ENCODE("\xfe") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_SENSING); + + TEST_CHECK(ENCODE("\xff") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_RESET); + + TEST_CHECK(ENCODE("\xc1\xf8") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CLOCK); + TEST_CHECK(ENCODE("\x22") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_PGMCHANGE); + TEST_CHECK(ev.data.control.channel == 1); + TEST_CHECK(ev.data.control.value == 0x22); + TEST_CHECK(ENCODE("\xf8") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CLOCK); + TEST_CHECK(ENCODE("\x33") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_PGMCHANGE); + TEST_CHECK(ev.data.control.channel == 1); + TEST_CHECK(ev.data.control.value == 0x33); + + TEST_CHECK(ENCODE("\xc1\xf6") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_TUNE_REQUEST); + TEST_CHECK(ENCODE("\x44\x44") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NONE); + + snd_midi_event_free(midi_event); +} + +static void test_reset_encode(void) +{ + snd_midi_event_t *midi_event; + snd_seq_event_t ev; + + if (ALSA_CHECK(snd_midi_event_new(256, &midi_event)) < 0) + return; + + TEST_CHECK(ENCODE("\x91\x02") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NONE); + + snd_midi_event_reset_encode(midi_event); + + TEST_CHECK(ENCODE("\x03") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NONE); + + snd_midi_event_free(midi_event); +} + +static void test_init(void) +{ + snd_midi_event_t *midi_event; + snd_seq_event_t ev; + unsigned char buf[50]; + int count; + + if (ALSA_CHECK(snd_midi_event_new(256, &midi_event)) < 0) + return; + + snd_seq_ev_set_noteon(&ev, 1, 2, 3); + TEST_CHECK(DECODES_TO("910203")); + + TEST_CHECK(ENCODE("\x94\x05") == 2); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NONE); + + snd_midi_event_init(midi_event); + + snd_seq_ev_set_noteon(&ev, 1, 2, 3); + TEST_CHECK(DECODES_TO("910203")); + + TEST_CHECK(ENCODE("\x06") == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NONE); + + snd_midi_event_free(midi_event); +} + +static void test_encode_byte(void) +{ + snd_midi_event_t *midi_event; + snd_seq_event_t ev; + + if (ALSA_CHECK(snd_midi_event_new(256, &midi_event)) < 0) + return; + +#define ENCODE_BYTE(c) snd_midi_event_encode_byte(midi_event, c, &ev) + TEST_CHECK(ENCODE_BYTE(0x81) == 0); + TEST_CHECK(ENCODE_BYTE(0x02) == 0); + TEST_CHECK(ENCODE_BYTE(0x03) == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NOTEOFF); + TEST_CHECK((ev.flags & SND_SEQ_EVENT_LENGTH_MASK) == SND_SEQ_EVENT_LENGTH_FIXED); + TEST_CHECK(ev.data.note.channel == 1); + TEST_CHECK(ev.data.note.note == 2); + TEST_CHECK(ev.data.note.velocity == 3); + TEST_CHECK(ENCODE_BYTE(0x04) == 0); + TEST_CHECK(ENCODE_BYTE(0xf8) == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_CLOCK); + TEST_CHECK(ENCODE_BYTE(0x05) == 1); + TEST_CHECK(ev.type == SND_SEQ_EVENT_NOTEOFF); + TEST_CHECK(ev.data.note.channel == 1); + TEST_CHECK(ev.data.note.note == 4); + TEST_CHECK(ev.data.note.velocity == 5); + + snd_midi_event_free(midi_event); +} + +int main(void) +{ + test_decode(); + test_reset_decode(); + test_encode(); + test_reset_encode(); + test_encode_byte(); + test_init(); + return TEST_EXIT_CODE(); +} diff --git a/test/lsb/test.h b/test/lsb/test.h new file mode 100644 index 0000000..ff697c5 --- /dev/null +++ b/test/lsb/test.h @@ -0,0 +1,29 @@ +#ifndef TEST_H_INCLUDED +#define TEST_H_INCLUDED + +#include +#include + +/* XXX this variable definition does not belong in a header file */ +static int any_test_failed; + +#define TEST_CHECK(cond) do \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: test failed: %s\n", __FILE__, __LINE__, #cond); \ + any_test_failed = 1; \ + } \ + while (0) + +#define ALSA_CHECK(fn) ({ \ + int err = fn; \ + if (err < 0) { \ + fprintf(stderr, "%s:%d: ALSA function call failed (%s): %s\n", \ + __FILE__, __LINE__, snd_strerror(err), #fn); \ + any_test_failed = 1; \ + } \ + err; \ + }) + +#define TEST_EXIT_CODE() any_test_failed + +#endif diff --git a/test/midifile.3 b/test/midifile.3 new file mode 100644 index 0000000..3aadb6d --- /dev/null +++ b/test/midifile.3 @@ -0,0 +1,336 @@ +.TH MIDIFILE 3 +.SH NAME +mfread,mfwrite \- read and write a standard MIDI file +.SH SYNOPSIS +\fC#include "mfread.h" + +mfread () + +.nf +int (*Mf_getc) (); +int (*Mf_putc) (); +int (*Mf_error) (char *msg); +int (*Mf_header) (int format, int ntrks, int division); +int (*Mf_trackstart) (); +int (*Mf_trackend) (); +int (*Mf_noteon) (int chan, int pitch, int vol); +int (*Mf_noteoff) (int chan, int pitch, int vol); +int (*Mf_pressure) (int chan, int pitch, int pressure); +int (*Mf_parameter) (int chan, int control, int value); +int (*Mf_pitchbend) (int chan, int msb, int lsb); +int (*Mf_program) (int chan, int program); +int (*Mf_chanpressure) (int chan, int pressure); +int (*Mf_sysex) (int leng, char *msg); +int (*Mf_metamisc) (int type, int leng, int msg); +int (*Mf_seqspecific) (int type, int leng, int msg); +int (*Mf_seqnum) (int num); +int (*Mf_text) (int type, int leng, int msg); +int (*Mf_eot) (); +int (*Mf_timesig) (int numer, int denom, int clocks, int qnotes); +int (*Mf_smpte) (int hour, int min, int sec, int frame, int fract); +int (*Mf_tempo) (int microsecs); +int (*Mf_keysig) (int sharpflat, int minor); +int (*Mf_arbitrary) (int leng, int msg); +int Mf_nomerge; +long Mf_currtime; +.fi +.sp 1 +mfwrite(int format, int ntracks, int division, FILE *fp) +.sp 1 +.nf +int (*Mf_writetrack)(int track); +int (*Mf_writetempotrack)(); + +void mf_write_midi_event(delta, type, chan, data, size) +unsigned long delta; +unsigned int type,chan,size; +char *data; + +void mf_write_meta_event(delta, type, data, size) +unsigned long delta; +unsigned int type,chan,size; +char *data; + +void mf_write_tempo(tempo) +unsigned long tempo; + +unsigned long mf_sec2ticks(float seconds, int division, int tempo) +float seconds; +int division; +unsigned int tempo; + +float mf_ticks2sec(ticks, division, tempo) +unsigned long ticks; +int division; +unsigned int tempo; +.fi + +.SH DESCRIPTION +The \fCmfread\fR function reads and interprets a standard MIDI file. +To use it you need to understand the general form of a +MIDI file and the type of information it contains, but you don't +need to know much, if anything, about the detailed format of the file +and the mechanics of reading it reliably and portably. + +The \fCmfwrite\fR function writes a standard MIDI file making +use of user-defined functions that access the program's +data structure. To use it you need to define your own Mf_writetrack +routine and then make use of the write_* family of routines to +write out the MIDI data. The \fCmfwrite\fR routine takes +care of the file format and writing the file and track chunk headers. + +.SH READING STANDARD MIDI FILES +A single call to \fCmfread\fR will read an entire MIDI file. +The interface to \fCmfread\fR is a set of external variables +named \fCMf_*\fR, most of which are function pointers to be called +from within \fCmfread\fR during the process of parsing the MIDI file. +Before calling \fCmfread\fR, the only +requirement is that you assign a value +to \fCMf_getc\fR - a pointer to a function that will return +characters from the MIDI file, using \-1 to indicate EOF. +All the rest of the function +pointers are initialized to NULL, and the default action for each +is to do nothing. The following is a complete program using \fCmfread\fR +that could serve as a 'syntax checker' for MIDI files: + +.in +1i +.ft C +.nf +#include +#include "midifile.h" + +mygetc() +{ + /* use standard input */ + return(getchar()); +} + +main() +{ + Mf_getc = mygetc; + mfread(); + exit(0); +} +.fi +.ft R +.in -1i + +This takes advantage of the default action when an error is detected, which +is to exit silently with a return code of 1. An error function of your +own can be used by giving a value to \fCMf_error\fR; the function will be +called with the error message as an argument. +The other \fCMf_* variables can similarly be used to call arbitrary +functions while parsing the MIDI file. The descriptions below +of the information passed to these functions is sparse; refer to +the MIDI file standard for the complete descriptions. + +\fCMf_header\fR is the first function to be called, and its arguments +contain information from the MIDI file's header; the format (0,1, or 2), +the number of tracks, and the division of a quarter-note that defines +the times units. +\fCMf_trackstart\fR and +\fCMf_trackend\fR are called at the beginning and end of each track. + +Once inside a track, each separate message causes a function to be called. +For example, each note-on message causes \fCMf_noteon\fR to be called +with the channel, pitch, and volume as arguments. The time at which +the message occurred is stored in \fCMf_currtime\fR - one of the few +external variables that isn't a function pointer. The other channel messages +are handled in a similar and obvious fashion - +\fCMf_noteoff\fR, +\fCMf_pressure\fR, +\fCMf_parameter\fR, +\fCMf_pitchbend\fR, +\fCMf_program\fR, +and \fCMf_chanpressure\fR. See the declarations above for the arguments +that are passed to each. + +System exclusive messages are handled by calling \fCMf_sysex\fR, passing +as arguments the message length and a pointer to a static buffer containing +the entire message. +The buffer is expanded when necessary; memory availability is the only limit +to its size. Normally, 'continued' system exclusives are automatically +merged, and \fCMf_sysex\fR is only called once. It you want to disable this +you can set \fCMf_nomerge\fR to 1, causing \fCMf_sysex\fR to be called +once for each part of the message. + +\fCMf_seqnum\fR is called by the \fImeta\fR message that provides +a sequence number, +which if present must appear at the beginning of a track. +The tempo \fImeta\fR message causes \fCMf_tempo\fR to be called; its +argument is the number of microseconds per MIDI quarter-note (24 MIDI clocks). +The end-of-track \fImeta\fR message causes \fCMf_eot\fR to be called. +The key signature \fImeta\fR message causes \fCMf_keysig\fR to be called; +the first argument conveys the number of sharps or flats, the second +argument is 1 if the key is minor. + +The \fCMf_timesig\fR and \fCMf_smpte\fR functions are called when the +corresponding \fImeta\fR messages are seen. See the MIDI file standard +for a description of their arguments. + +The \fItext\fR messages in the MIDI file standard are of the following +types: + +.in +1i +.nf +0x01 Text Event +0x02 Copyright +0x03 Sequence/Track Name +0x04 Instrument +0x05 Lyric +0x06 Marker +0x07 Cue Point +0x08-0x0F Reserved but Undefined +.fi +.in -1i + +\fCMf_text\fR is called for each of these; the arguments are +the type number, the message length, and a pointer to the message buffer. + +Miscellaneous \fImeta\fR messages are handled by \fCMf_metamisc\fR, +sequencer-specific messages are handled by \fCMf_seqspecific\fR, and +arbitrary "escape" messages (started with 0xF7) are handled by +\fCMf_arbitrary\fR. +.SH READING EXAMPLE +The following is a \fCstrings\fR-like program for MIDI files: + +.in +1i +.ft C +.nf +#include +#include +#include "midifile.h" + +FILE *F; + +mygetc() { return(getc(F)); } + +mytext(type,leng,msg) +char *msg; +{ + char *p; + char *ep = msg + leng; + + for ( p=msg; p 1 ) + F = fopen(argv[1],"r"); + else + F = stdin; + + Mf_getc = mygetc; + Mf_text = mytext; + + mfread(); + + exit(0); +} +.fi +.ft R +.in -1i +.sp +.SH WRITING STANDARD MIDI FILES +A single call to \fCmfwrite\fR will write an entire MIDI file. Before +calling \fCmfwrite\fR, you must assign values to function pointers +\fCMf_writetrack\fR and \fCMf_putc\fR. The first is a routine to +access your MIDI data structure, which can make use of other library +routines to write the actual MIDI data. The routine +\fCMf_writetrack\fR will be passed a single parameter which is the +number of the track to be written. The pointer \fCMf_putc\fR should be +set to point to a routine that accepts a character as input, writes that +character to a file, and returns the value that was written. In the +case of a format 1 file, a routine has to be written to write a tempo +map, and assigned to the function pointer \fCMf_writetempotrack\fR. +This is because format 1 files assume the first track written is a +tempo track. + +\fCmf_write_midi_event\fR and \fCmf_write_meta_event\fR are routines +that should be called from your \fCMf_writetrack\fR routine to write +out MIDI events. The delta time param is the number of ticks since the +last event. The int "type" is the type of MIDI message. The int "chan" +is the MIDI channel, which can be between 1 and 16. The char pointer +"data" points to an array containing the data bytes, if any exist. The +int "size" is the number of data bytes. + +\fCmf_sec2ticks\fR and \fCmf_ticks2sec\fR are utility routines +to help you convert between the MIDI file parameter of ticks +and the more standard seconds. The int "division" is the same +division parameter from the file header, and tempo is expressed +in microseconds per MIDI quarter-note, or "24ths of a microsecond +per MIDI clock". The division has two meanings, depending on +whether bit 15 is set or not. If bit 15 of division is zero, +bits 14 through 0 represent the number of delta-time "ticks" +which make up a quarter note. If bit 15 of division is a one, +delta-times in a file correspond to subdivisions of a second +similar to SMPTE and MIDI time code. In this format bits +14 through 8 contain one of four values \-24, \-25, \-29, or \-30, +corresponding to the four standard SMPTE and MIDI time code +frame per second formats, where \-29 represents 30 drop frame. +The second byte consisting of bits 7 through 0 corresponds +the the resolution within a frame. Refer the Standard MIDI Files +1.0 spec for more details. + +.SH WRITING EXAMPLE +The following is a simple program to demonstrate writing MIDI files. +The track would consist of a series of quarter notes from lowest to +highest in pitch at constant velocity, each separated by a quarter-note +rest. +.sp +.in +1i +.ft C +.nf +#include +#include +#include "midifile.h" + +FILE *fp; +myputc(c) { return(putc(c,fp));} + +int mywritetrack(track) +int track; +{ + int i; + char data[2]; + + /* 120 beats/per/second */ + mf_write_tempo((long)500000); + + for(i = 1 ; i < 128; i++){ + data[0] = i; /* note number */ + data[1] = 64; /* velocity */ + if(!mf_write_midi_event(480,note_on,1,data,2)) + return(\-1); + if(!mf_write_midi_event(480,note_off,1,data,2)) + return(\-1); + } + + return(1); +} /* end of write_track() */ + +main(argc,argv) +char **argv; +{ + if((fp = fopen(argv[1],"w")) == 0L) + exit(1); + + Mf_putc = myputc; + Mf_writetrack = mywritetrack; + + /* write a single track */ + mfwrite(0,1,480,fp); +} +.sp +.fi +.ft R +.in -1i +.sp +.SH AUTHOR +Tim Thompson (att!twitch!glimmer!tjt) +.SH CONTRIBUTORS +Michael Czeiszperger (mike@pan.com) diff --git a/test/midifile.c b/test/midifile.c new file mode 100644 index 0000000..8d6ba90 --- /dev/null +++ b/test/midifile.c @@ -0,0 +1,1173 @@ +/* + * midifile 1.11 + * + * Read and write a MIDI file. Externally-assigned function pointers are + * called upon recognizing things in the file. + * + * Original release ? + * June 1989 - Added writing capability, M. Czeiszperger. + * + * The file format implemented here is called + * Standard MIDI Files, and is part of the Musical + * instrument Digital Interface specification. + * The spec is available from: + * + * International MIDI Association + * 5316 West 57th Street + * Los Angeles, CA 90056 + * + * An in-depth description of the spec can also be found + * in the article "Introducing Standard MIDI Files", published + * in Electronic Musician magazine, April, 1989. + * + * February 1993 - Minor adjustments, Greg Lee: + * (1) can now set the global variable Mf_interactive to 1 to prevent the + * reading functions from looking for file and track headers + * (2) can now write system exclusive data with + * mf_write_midi_event(delta_time, system_exclusive, 0, data, size) + * (3) changed definition of 'sequencer_specific' in midifile.h to 0x7f + * (4) changed mf_write_tempo to take additional delta_time as first argument + * (since delta need not be zero) + * (5) added function mf_write_seqnum(unsigned long delta_time, unsigned seqnum) + * (6) changed mf_write_midi_event to use running status + * (7) removed the code to write an end of track meta event automatically + * -- this must now be done by the user of the library (I changed + * it because I need to be able to control the time delta of this + * meta event) + * (8) added global variables Mf_division, Mf_currtempo, Mf_realtime, which + * are updated by the reading functions. Mf_realtime is useful, + * because Mf_currtime does not really measure time at all, since + * its units change value at every tempo change. Mf_realtime is + * the midi-time elapsed in units of 1/16 of a centisecond (but it + * does not handle SMPTE times) + * (9) maintains a history of tempo settings to update Mf_currtempo, + * to handle tempo tracks. + * (10) if there is an Mf_error function, the error routine no longer + * exits, leaving it to the application to do this. + * (11) chanmessage skips over invalid c1 command bytes > 127 and + * adjusts invalid c2 argument byte > 127 to 127. + * (12) readmt returns EOF when it encounters a 0 or 0x1a byte instead of an expected + * header string (some midi files have padding at end). + */ +#define NO_LC_DEFINES +#include "midifile.h" +#ifdef NO_LC_DEFINES +#define system_exclusive 0xf0 +#define meta_event 0xFF +#define set_tempo 0x51 +#define lowerbyte(x) ((unsigned char)(x & 0xff)) +#define upperbyte(x) ((unsigned char)((x & 0xff00)>>8)) +#endif + +#define NULLFUNC 0 +#if 0 +#define NULL 0 +#endif + +#define THINK + +#ifdef THINK +#include +#endif + +#include +#include + +#include +/*void exit(), free();*/ + +/* public stuff */ + +/* Functions to be called while processing the MIDI file. */ +int (*Mf_getc) () = NULLFUNC; +void (*Mf_error) () = NULLFUNC; +void (*Mf_header) () = NULLFUNC; +void (*Mf_trackstart) () = NULLFUNC; +void (*Mf_trackend) () = NULLFUNC; +void (*Mf_noteon) () = NULLFUNC; +void (*Mf_noteoff) () = NULLFUNC; +void (*Mf_pressure) () = NULLFUNC; +void (*Mf_parameter) () = NULLFUNC; +void (*Mf_pitchbend) () = NULLFUNC; +void (*Mf_program) () = NULLFUNC; +void (*Mf_chanpressure) () = NULLFUNC; +void (*Mf_sysex) () = NULLFUNC; +void (*Mf_arbitrary) () = NULLFUNC; +void (*Mf_metamisc) () = NULLFUNC; +void (*Mf_seqnum) () = NULLFUNC; +void (*Mf_eot) () = NULLFUNC; +void (*Mf_smpte) () = NULLFUNC; +void (*Mf_tempo) () = NULLFUNC; +void (*Mf_timesig) () = NULLFUNC; +void (*Mf_keysig) () = NULLFUNC; +void (*Mf_seqspecific) () = NULLFUNC; +void (*Mf_text) () = NULLFUNC; + +/* Functions to implement in order to write a MIDI file */ +int (*Mf_putc) () = NULLFUNC; +int (*Mf_writetrack) () = NULLFUNC; +int (*Mf_writetempotrack) () = NULLFUNC; + +int Mf_nomerge = 0; /* 1 => continue'ed system exclusives are */ + /* not collapsed. */ +int Mf_interactive = 0; /* 1 => file and track headers are not required */ +unsigned long Mf_currtime = 0L; /* current time in delta-time units */ +unsigned long Mf_realtime = 0L; /* current time in 1/16 centisecond-time units */ +static double Mf_f_realtime = 0;/* as above, floating */ +static double old_f_realtime = 0; +int Mf_division = 96; +unsigned long Mf_currtempo = 500000; +static unsigned long old_currtempo = 500000; +static unsigned long old_realtime = 0; +static unsigned long old_currtime = 0; +static unsigned long revised_time = 0; +static unsigned long tempo_change_time = 0; + +#define MAX_HISTORY 512 +static unsigned long tempo_history[MAX_HISTORY]; +static unsigned long tempo_history_time[MAX_HISTORY]; +static int tempo_history_count = 0; + +/* private stuff */ +static long Mf_toberead = 0L; +static long Mf_numbyteswritten = 0L; + +static long readvarinum (); +static long read32bit (); +static long to32bit (); +static int read16bit (); +static int to16bit (); +static char *msg (); +static void readheader (); +static int readtrack (); +static void badbyte (); +static void metaevent (); +static void sysex (); +static void chanmessage (); +static void msginit (); +static int msgleng (); +static void msgadd (); +static void biggermsg (); +static int eputc (unsigned char c); + +double mf_ticks2sec (unsigned long ticks, int division, unsigned long tempo); +int mf_write_meta_event (); +void mf_write_tempo (); +void mf_write_seqnum (); +void WriteVarLen (); + +#ifdef READ_MODS +#include "mp_mod.c" +static int mod_file_flag = 0; +#endif /* READ_MODS */ +static int force_exit; + +void +mfread () +{ + force_exit = 0; + if (Mf_getc == NULLFUNC) + mferror ("mfread() called without setting Mf_getc"); + + readheader (); +#ifdef READ_MODS + if (mod_file_flag) + do_module(); + else +#endif + while (readtrack () && !force_exit) + ; +} + +/* for backward compatibility with the original lib */ +void +midifile () +{ + mfread (); +} + +static +int +readmt (s) /* read through the "MThd" or "MTrk" header string */ + char *s; +{ + int n = 0; + char *p = s; + int c; + + while (n++ < 4 && (c = (*Mf_getc) ()) != EOF) + { + if (c != *p++) + { + char buff[32]; + if (!c) return(EOF); + if (c == 0x1a) return(EOF); + (void) strcpy (buff, "expecting "); + (void) strcat (buff, s); + mferror (buff); + break; + } + } + return (c); +} + +static +int +egetc () /* read a single character and abort on EOF */ +{ + int c = (*Mf_getc) (); + + if (c == EOF) { + mferror ("premature EOF"); + force_exit = 1; + } + Mf_toberead--; + return (c); +} + +static +void +readheader () /* read a header chunk */ +{ + int format, ntrks, division; + + + Mf_division = 96; + Mf_currtempo = 500000; + old_currtempo = 500000; + tempo_history_count = 0; + tempo_history[tempo_history_count] = Mf_currtempo; + tempo_history_time[tempo_history_count] = 0; + + if (Mf_interactive) + { + Mf_toberead = 0; + format = 0; + ntrks = 1; + division = 96; + } + else +#ifdef READ_MODS + if (!strncmp(Mf_file_contents, "MThd", 4)) +#endif + { + if (readmt ("MThd") == EOF) + return; + + Mf_toberead = read32bit (); + format = read16bit (); + ntrks = read16bit (); + Mf_division = division = read16bit (); + } +#ifdef READ_MODS + else + { + format = 0; + ntrks = 1; + division = Mf_division; + Mf_toberead = 0; + mod_file_flag = 1; + } +#endif + + if (Mf_header) + (*Mf_header) (format, ntrks, division); + + /* flush any extra stuff, in case the length of header is not 6 */ + while (Mf_toberead > 0 && !force_exit) + (void) egetc (); +} + + +/*#define DEBUG_TIMES*/ +static +unsigned long +find_tempo() +{ + int i; + unsigned long old_tempo = Mf_currtempo; + unsigned long new_tempo = Mf_currtempo; + + for (i = 0; i <= tempo_history_count; i++) { + if (tempo_history_time[i] <= Mf_currtime) old_tempo = tempo_history[i]; + new_tempo = tempo_history[i]; + if (tempo_history_time[i] > revised_time) break; + } + if (i > tempo_history_count || tempo_history_time[i] > Mf_currtime) { +#ifdef DEBUG_TIMES +printf("[past %d, old_tempo %d]\n", tempo_history_time[i], old_tempo); +#endif + revised_time = Mf_currtime; + return(old_tempo); + } + tempo_change_time = revised_time = tempo_history_time[i]; +#ifdef DEBUG_TIMES +printf("[revised_time %d, new_tempo %d]\n", revised_time, new_tempo); +#endif + return(new_tempo); +} + +static +int +readtrack () /* read a track chunk */ +{ + /* This array is indexed by the high half of a status byte. It's */ + /* value is either the number of bytes needed (1 or 2) for a channel */ + /* message, or 0 (meaning it's not a channel message). */ + static int chantype[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ + 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ + }; + long lookfor; + int c, c1, type; + int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ + int running = 0; /* 1 when running status used */ + int status = 0; /* status value (e.g. 0x90==note-on) */ + int needed; + + if (Mf_interactive) + { + Mf_toberead = MAXINT; + } + else + { + if (readmt ("MTrk") == EOF) + return (0); + + Mf_toberead = read32bit (); + } + Mf_currtime = Mf_realtime = 0; + Mf_f_realtime = old_f_realtime = 0; + old_currtime = old_realtime = 0; + Mf_currtempo = find_tempo(); + + if (Mf_trackstart) + (*Mf_trackstart) (); + + while (!force_exit && (Mf_interactive || Mf_toberead > 0)) + { + + if (Mf_interactive) + Mf_currtime += 1; + else + { + double delta_secs; + unsigned long delta_ticks = readvarinum (); + revised_time = Mf_currtime; + Mf_currtime += delta_ticks; /* delta time */ + +/* + * Step through each tempo change from old_currtime up to now, + * revising Mf_realtime after each change. + */ + + while (revised_time < Mf_currtime) { + unsigned long save_time = revised_time; + unsigned long save_tempo = Mf_currtempo; + Mf_currtempo = find_tempo(); + + if (Mf_currtempo != old_currtempo) { + old_currtempo = Mf_currtempo; + old_realtime = Mf_realtime; + if (revised_time != tempo_change_time) { + old_f_realtime = Mf_f_realtime; + old_currtime = save_time; + } + delta_secs = mf_ticks2sec (revised_time-old_currtime, Mf_division, save_tempo); +#ifdef DEBUG_TIMES +printf("d(rev %d - old %d, div %d, tempo %d) = %.3f\n", +revised_time, old_currtime, Mf_division, save_tempo, delta_secs * 1600.0); +#endif + Mf_f_realtime = old_f_realtime + delta_secs * 1600.0; + Mf_realtime = (unsigned long)(0.5 + Mf_f_realtime); +#ifdef DEBUG_TIMES +printf("\tt=%d ticks ( = %d csec/16 < old %.2f + %.2f)\n", Mf_currtime, Mf_realtime, +old_f_realtime, delta_secs * 1600.0); +#endif + if (revised_time == tempo_change_time) { + old_currtime = revised_time; + old_f_realtime = Mf_f_realtime; + } + } + else { + delta_secs = mf_ticks2sec (revised_time-old_currtime, Mf_division, Mf_currtempo); +#ifdef DEBUG_TIMES +printf("d(rev %d - old %d, div %d, tempo %d) = %.3f\n", +revised_time, old_currtime, Mf_division, Mf_currtempo, delta_secs * 1600.0); +#endif + Mf_f_realtime = old_f_realtime + delta_secs * 1600.0; + Mf_realtime = (unsigned long)(0.5 + Mf_f_realtime); +#ifdef DEBUG_TIMES +printf("\tt=%d ticks ( = %d csec/16 < old %.2f + %.2f)\n", Mf_currtime, Mf_realtime, +old_f_realtime, delta_secs * 1600.0); +#endif + } + + + } + } + + c = egetc (); + + if (sysexcontinue && c != 0xf7) + mferror ("didn't find expected continuation of a sysex"); + + if ((c & 0x80) == 0) + { /* running status? */ + if (status == 0) + mferror ("unexpected running status"); + running = 1; + } + else + { + status = c; + running = 0; + } + + needed = chantype[(status >> 4) & 0xf]; + + if (needed) + { /* ie. is it a channel message? */ + + if (running) + c1 = c; + else + c1 = egetc (); + chanmessage (status, c1, (needed > 1) ? egetc () : 0); + continue;; + } + + switch (c) + { + + case 0xff: /* meta event */ + + type = egetc (); + lookfor = Mf_toberead - readvarinum (); + msginit (); + + while (Mf_toberead > lookfor) + msgadd (egetc ()); + + metaevent (type); + break; + + case 0xf0: /* start of system exclusive */ + + lookfor = Mf_toberead - readvarinum (); + msginit (); + msgadd (0xf0); + + while (Mf_toberead > lookfor) + msgadd (c = egetc ()); + + if (c == 0xf7 || Mf_nomerge == 0) + sysex (); + else + sysexcontinue = 1; /* merge into next msg */ + break; + + case 0xf7: /* sysex continuation or arbitrary stuff */ + + lookfor = Mf_toberead - readvarinum (); + + if (!sysexcontinue) + msginit (); + + while (Mf_toberead > lookfor) + msgadd (c = egetc ()); + + if (!sysexcontinue) + { + if (Mf_arbitrary) + (*Mf_arbitrary) (msgleng (), msg ()); + } + else if (c == 0xf7) + { + sysex (); + sysexcontinue = 0; + } + break; + default: + badbyte (c); + break; + } + } + if (Mf_trackend) + (*Mf_trackend) (); + return (1); +} + +static +void +badbyte (c) + int c; +{ + char buff[32]; + + (void) sprintf (buff, "unexpected byte: 0x%02x", c); + mferror (buff); +} + +static +void +metaevent (int type) +{ + int leng = msgleng (); + char *m = msg (); + + switch (type) + { + case 0x00: + if (Mf_seqnum) + (*Mf_seqnum) (to16bit (m[0], m[1])); + break; + case 0x01: /* Text event */ + case 0x02: /* Copyright notice */ + case 0x03: /* Sequence/Track name */ + case 0x04: /* Instrument name */ + case 0x05: /* Lyric */ + case 0x06: /* Marker */ + case 0x07: /* Cue point */ + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + /* These are all text events */ + if (Mf_text) + (*Mf_text) (type, leng, m); + break; + case 0x2f: /* End of Track */ + if (Mf_eot) + (*Mf_eot) (); + break; + case 0x51: /* Set tempo */ + if (Mf_tempo) + (*Mf_tempo) (Mf_currtempo = to32bit (0, m[0], m[1], m[2])); + if (tempo_history[tempo_history_count] == Mf_currtempo) break; + if (tempo_history_time[tempo_history_count] > Mf_currtime) break; + if (tempo_history_count < MAX_HISTORY - 1) tempo_history_count++; + tempo_history[tempo_history_count] = Mf_currtempo; + tempo_history_time[tempo_history_count] = Mf_currtime; + break; + case 0x54: + if (Mf_smpte) + (*Mf_smpte) (m[0], m[1], m[2], m[3], m[4]); + break; + case 0x58: + if (Mf_timesig) + (*Mf_timesig) (m[0], m[1], m[2], m[3]); + break; + case 0x59: + if (Mf_keysig) + (*Mf_keysig) (m[0], m[1]); + break; + case 0x7f: + if (Mf_seqspecific) + (*Mf_seqspecific) (leng, m); + break; + default: + if (Mf_metamisc) + (*Mf_metamisc) (type, leng, m); + } +} + +static +void +sysex () +{ + if (Mf_sysex) + (*Mf_sysex) (msgleng (), msg ()); +} + +static +void +chanmessage (status, c1, c2) + int status; + int c1, c2; +{ + int chan = status & 0xf; + + /* I found a midi file with Mod Wheel values 128. --gl */ + + if (c1 > 127) /*mferror("chanmessage: bad c1") ??*/ return; + if (c2 > 127) c2 = 127; + + switch (status & 0xf0) + { + case 0x80: + if (Mf_noteoff) + (*Mf_noteoff) (chan, c1, c2); + break; + case 0x90: + if (Mf_noteon) + (*Mf_noteon) (chan, c1, c2); + break; + case 0xa0: + if (Mf_pressure) + (*Mf_pressure) (chan, c1, c2); + break; + case 0xb0: + if (Mf_parameter) + (*Mf_parameter) (chan, c1, c2); + break; + case 0xe0: + if (Mf_pitchbend) + (*Mf_pitchbend) (chan, c1, c2); + break; + case 0xc0: + if (Mf_program) + (*Mf_program) (chan, c1); + break; + case 0xd0: + if (Mf_chanpressure) + (*Mf_chanpressure) (chan, c1); + break; + } +} + +/* readvarinum - read a varying-length number, and return the */ +/* number of characters it took. */ + +static long +readvarinum () +{ + long value; + int c; + + c = egetc (); + value = c; + if (c & 0x80) + { + value &= 0x7f; + do + { + c = egetc (); + value = (value << 7) + (c & 0x7f); + } + while (c & 0x80); + } + return (value); +} + +static long +to32bit (int c1, int c2, int c3, int c4) +{ + long value = 0L; + + value = (c1 & 0xff); + value = (value << 8) + (c2 & 0xff); + value = (value << 8) + (c3 & 0xff); + value = (value << 8) + (c4 & 0xff); + return (value); +} + +static int +to16bit (c1, c2) + int c1, c2; +{ + return ((c1 & 0xff) << 8) + (c2 & 0xff); +} + +static long +read32bit () +{ + int c1, c2, c3, c4; + + c1 = egetc (); + c2 = egetc (); + c3 = egetc (); + c4 = egetc (); + return to32bit (c1, c2, c3, c4); +} + +static int +read16bit () +{ + int c1, c2; + c1 = egetc (); + c2 = egetc (); + return to16bit (c1, c2); +} + +/* static */ +void +mferror (s) + char *s; +{ + if (Mf_error) + (*Mf_error) (s); + else exit (1); +} + +/* The code below allows collection of a system exclusive message of */ +/* arbitrary length. The Msgbuff is expanded as necessary. The only */ +/* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */ + +#define MSGINCREMENT 128 +static char *Msgbuff = NULL; /* message buffer */ +static int Msgsize = 0; /* Size of currently allocated Msg */ +static int Msgindex = 0; /* index of next available location in Msg */ + +static +void +msginit () +{ + Msgindex = 0; +} + +static char * +msg () +{ + return (Msgbuff); +} + +static +int +msgleng () +{ + return (Msgindex); +} + +static +void +msgadd (c) + int c; +{ + /* If necessary, allocate larger message buffer. */ + if (Msgindex >= Msgsize) + biggermsg (); + Msgbuff[Msgindex++] = c; +} + +static +void +biggermsg () +{ +/* char *malloc(); */ + char *newmess; + char *oldmess = Msgbuff; + int oldleng = Msgsize; + + Msgsize += MSGINCREMENT; + newmess = (char *) malloc ((unsigned) (sizeof (char) * Msgsize)); + + if (newmess == NULL) + mferror ("malloc error!"); + + /* copy old message into larger new one */ + if (oldmess != NULL) + { + register char *p = newmess; + register char *q = oldmess; + register char *endq = &oldmess[oldleng]; + + for (; q != endq; p++, q++) + *p = *q; + free (oldmess); + } + Msgbuff = newmess; +} + +static int laststatus = 0; + +/* + * mfwrite() - The only function you'll need to call to write out + * a midi file. + * + * format 0 - Single multi-channel track + * 1 - Multiple simultaneous tracks + * 2 - One or more sequentially independent + * single track patterns + * ntracks The number of tracks in the file. + * division This is kind of tricky, it can represent two + * things, depending on whether it is positive or negative + * (bit 15 set or not). If bit 15 of division is zero, + * bits 14 through 0 represent the number of delta-time + * "ticks" which make up a quarter note. If bit 15 of + * division is a one, delta-times in a file correspond to + * subdivisions of a second similar to SMPTE and MIDI + * time code. In this format bits 14 through 8 contain + * one of four values - 24, -25, -29, or -30, + * corresponding to the four standard SMPTE and MIDI + * time code frame per second formats, where -29 + * represents 30 drop frame. The second byte + * consisting of bits 7 through 0 corresponds the the + * resolution within a frame. Refer the Standard MIDI + * Files 1.0 spec for more details. + * fp This should be the open file pointer to the file you + * want to write. It will have be a global in order + * to work with Mf_putc. + */ +void +mfwrite (format, ntracks, division, fp) + int format, ntracks, division; + FILE *fp; +{ + int i; + void mf_write_track_chunk (), mf_write_header_chunk (); + + if (Mf_putc == NULLFUNC) + mferror ("mfmf_write() called without setting Mf_putc"); + + if (Mf_writetrack == NULLFUNC) + mferror ("mfmf_write() called without setting Mf_mf_writetrack"); + + laststatus = 0; + + /* every MIDI file starts with a header */ + mf_write_header_chunk (format, ntracks, division); + + laststatus = 0; + + /* In format 1 files, the first track is a tempo map */ + if (format == 1 && (Mf_writetempotrack)) + { + (*Mf_writetempotrack) (); + } + + /* The rest of the file is a series of tracks */ + for (i = 0; i < ntracks; i++) + mf_write_track_chunk (i, fp); +} + +void +mf_write_track_chunk (which_track, fp) + int which_track; + FILE *fp; +{ + unsigned long trkhdr, trklength; + long offset, place_marker; + void write16bit (), write32bit (); + + + laststatus = 0; + + trkhdr = MTrk; + trklength = 0; + + /* Remember where the length was written, because we don't + know how long it will be until we've finished writing */ + offset = ftell (fp); + +#ifdef DEBUG + printf ("offset = %d\n", (int) offset); +#endif + + /* Write the track chunk header */ + write32bit (trkhdr); + write32bit (trklength); + + Mf_numbyteswritten = 0L; /* the header's length doesn't count */ + + if (Mf_writetrack) + { + (*Mf_writetrack) (which_track); + } + + /* mf_write End of track meta event */ +/* but this does not necessarily have a delta of 0, so + * I don't want to do it -- leave it up to the user of the + * library functions to do + * --gl + eputc(0); + eputc(laststatus = meta_event); + eputc(end_of_track); + + eputc(0); + */ + + /* It's impossible to know how long the track chunk will be beforehand, + so the position of the track length data is kept so that it can + be written after the chunk has been generated */ + place_marker = ftell (fp); + + /* This method turned out not to be portable because the + parameter returned from ftell is not guaranteed to be + in bytes on every machine */ + /* track.length = place_marker - offset - (long) sizeof(track); */ + +#ifdef DEBUG + printf ("length = %d\n", (int) trklength); +#endif + + if (fseek (fp, offset, 0) < 0) + mferror ("error seeking during final stage of write"); + + trklength = Mf_numbyteswritten; + + /* Re-mf_write the track chunk header with right length */ + write32bit (trkhdr); + write32bit (trklength); + + fseek (fp, place_marker, 0); +} /* End gen_track_chunk() */ + + +void +mf_write_header_chunk (format, ntracks, division) + int format, ntracks, division; +{ + unsigned long ident, length; + void write16bit (), write32bit (); + + ident = MThd; /* Head chunk identifier */ + length = 6; /* Chunk length */ + + /* individual bytes of the header must be written separately + to preserve byte order across cpu types :-( */ + write32bit (ident); + write32bit (length); + write16bit (format); + write16bit (ntracks); + write16bit (division); +} /* end gen_header_chunk() */ + + +/* + * mf_write_midi_event() + * + * Library routine to mf_write a single MIDI track event in the standard MIDI + * file format. The format is: + * + * + * + * In this case, event can be any multi-byte midi message, such as + * "note on", "note off", etc. + * + * delta_time - the time in ticks since the last event. + * type - the type of meta event. + * chan - The midi channel. + * data - A pointer to a block of chars containing the META EVENT, + * data. + * size - The length of the meta-event data. + */ +int +mf_write_midi_event (delta_time, type, chan, data, size) + unsigned long delta_time; + int chan, type; + unsigned long size; + char *data; +{ + int i; + unsigned char c; + + WriteVarLen (delta_time); + + /* all MIDI events start with the type in the first four bits, + and the channel in the lower four bits */ + if (type == system_exclusive || type == 0xf7) + { + c = type; + laststatus = 0; + } + else + c = type | chan; + + if (chan > 15) + perror ("error: MIDI channel greater than 16\n"); + + if (laststatus != c) + eputc (laststatus = c); + + if (type == system_exclusive || type == 0xf7) + WriteVarLen (size); + + /* write out the data bytes */ + for (i = 0; i < (int)size; i++) + eputc (data[i]); + + return (size); +} /* end mf_write MIDI event */ + +/* + * mf_write_meta_event() + * + * Library routine to mf_write a single meta event in the standard MIDI + * file format. The format of a meta event is: + * + * + * + * delta_time - the time in ticks since the last event. + * type - the type of meta event. + * data - A pointer to a block of chars containing the META EVENT, + * data. + * size - The length of the meta-event data. + */ +int +mf_write_meta_event (delta_time, type, data, size) + unsigned long delta_time; + unsigned char *data, type; + unsigned long size; +{ + int i; + + WriteVarLen (delta_time); + + /* This marks the fact we're writing a meta-event */ + eputc (laststatus = meta_event); + + /* The type of meta event */ + eputc (type); + + /* The length of the data bytes to follow */ + WriteVarLen (size); + + for (i = 0; i < (int)size; i++) + { + if (eputc (data[i]) != data[i]) + return (-1); + } + return (size); +} /* end mf_write_meta_event */ + +void +mf_write_tempo (delta_time, tempo) + unsigned long delta_time; + unsigned long tempo; +{ + /* Write tempo */ + /* all tempos are written as 120 beats/minute, */ + /* expressed in microseconds/quarter note */ + + WriteVarLen (delta_time); + eputc (laststatus = meta_event); + eputc (set_tempo); + + eputc (3); + eputc ((unsigned) (0xff & (tempo >> 16))); + eputc ((unsigned) (0xff & (tempo >> 8))); + eputc ((unsigned) (0xff & tempo)); +} + +void +mf_write_seqnum (delta_time, seqnum) + unsigned long delta_time; + unsigned seqnum; +{ + + WriteVarLen (delta_time); + eputc (laststatus = meta_event); + eputc (0); + + eputc ((unsigned) (0xff & (seqnum >> 8))); + eputc ((unsigned) (0xff & seqnum)); +} + +unsigned long +mf_sec2ticks (secs, division, tempo) + int division; + unsigned long tempo; + double secs; +{ + return (unsigned long) (((secs * 1000.0) / 4.0 * division) / tempo); +} + +/* + * Write multi-length bytes to MIDI format files + */ +void +WriteVarLen (value) + unsigned long value; +{ + unsigned long buffer; + + buffer = value & 0x7f; + while ((value >>= 7) > 0) + { + buffer <<= 8; + buffer |= 0x80; + buffer += (value & 0x7f); + } + while (1) + { + eputc ((unsigned) (buffer & 0xff)); + + if (buffer & 0x80) + buffer >>= 8; + else + return; + } +} /* end of WriteVarLen */ + +/* + * This routine converts delta times in ticks into seconds. The + * else statement is needed because the formula is different for tracks + * based on notes and tracks based on SMPTE times. + * + */ +double +mf_ticks2sec (ticks, division, tempo) + int division; + unsigned long tempo; + unsigned long ticks; +{ + double smpte_format, smpte_resolution; + + if (division > 0) + return ((double) (((double) (ticks) * (double) (tempo)) / ((double) (division) * 1000000.0))); + else + { + smpte_format = upperbyte (division); + smpte_resolution = lowerbyte (division); + return (double) ((double) ticks / (smpte_format * smpte_resolution * 1000000.0)); + } +} /* end of ticks2sec() */ + + +/* + * write32bit() + * write16bit() + * + * These routines are used to make sure that the byte order of + * the various data types remains constant between machines. This + * helps make sure that the code will be portable from one system + * to the next. It is slightly dangerous that it assumes that longs + * have at least 32 bits and ints have at least 16 bits, but this + * has been true at least on PCs, UNIX machines, and Macintosh's. + * + */ +void +write32bit (data) + unsigned long data; +{ + eputc ((unsigned) ((data >> 24) & 0xff)); + eputc ((unsigned) ((data >> 16) & 0xff)); + eputc ((unsigned) ((data >> 8) & 0xff)); + eputc ((unsigned) (data & 0xff)); +} + +void +write16bit (data) + int data; +{ + eputc ((unsigned) ((data & 0xff00) >> 8)); + eputc ((unsigned) (data & 0xff)); +} + +/* write a single character and abort on error */ +static int +eputc (c) + unsigned char c; +{ + int return_val; + + if ((Mf_putc) == NULLFUNC) + { + mferror ("Mf_putc undefined"); + return (-1); + } + + return_val = (*Mf_putc) (c); + + if (return_val == EOF) + mferror ("error writing"); + + Mf_numbyteswritten++; + return (return_val); +} diff --git a/test/midifile.h b/test/midifile.h new file mode 100644 index 0000000..7dd4626 --- /dev/null +++ b/test/midifile.h @@ -0,0 +1,132 @@ +/* definitions for MIDI file parsing code */ +extern int (*Mf_getc)(); +extern void (*Mf_header)(); +extern void (*Mf_trackstart)(); +extern void (*Mf_trackend)(); +extern void (*Mf_noteon)(); +extern void (*Mf_noteoff)(); +extern void (*Mf_pressure)(); +extern void (*Mf_parameter)(); +extern void (*Mf_pitchbend)(); +extern void (*Mf_program)(); +extern void (*Mf_chanpressure)(); +extern void (*Mf_sysex)(); +extern void (*Mf_metamisc)(); +extern void (*Mf_seqspecific)(); +extern void (*Mf_seqnum)(); +extern void (*Mf_text)(); +extern void (*Mf_eot)(); +extern void (*Mf_timesig)(); +extern void (*Mf_smpte)(); +extern void (*Mf_tempo)(); +extern void (*Mf_keysig)(); +extern void (*Mf_arbitrary)(); +extern void (*Mf_error)(); +extern unsigned long Mf_currtime; +extern unsigned long Mf_realtime; +extern unsigned long Mf_currtempo; +extern int Mf_division; +extern int Mf_nomerge; +#ifdef READ_MODS +extern unsigned char *Mf_file_contents; +extern int Mf_file_size; +#endif + +/* definitions for MIDI file writing code */ +extern int (*Mf_putc)(); +extern int (*Mf_writetrack)(); +extern int (*Mf_writetempotrack)(); + +extern void midifile(); +extern unsigned long mf_sec2ticks(); +extern void mfwrite(); +extern int mf_write_meta_event(); +extern int mf_write_midi_event(unsigned long delta_time, int type, + int chan, char *data, unsigned long size); +extern double mf_ticks2sec(unsigned long ticks,int division,unsigned long tempo); +extern void mf_write_tempo(); +extern void mf_write_seqnum(); +extern void mfread(); +extern void mferror(char *s); + +#ifndef NO_LC_DEFINES +/* MIDI status commands most significant bit is 1 */ +#define note_off 0x80 +#define note_on 0x90 +#define poly_aftertouch 0xa0 +#define control_change 0xb0 +#define program_chng 0xc0 +#define channel_aftertouch 0xd0 +#define pitch_wheel 0xe0 +#define system_exclusive 0xf0 +#define delay_packet (1111) + +/* 7 bit controllers */ +#define damper_pedal 0x40 +#define portamento 0x41 +#define sustenuto 0x42 +#define soft_pedal 0x43 +#define general_4 0x44 +#define hold_2 0x45 +#define general_5 0x50 +#define general_6 0x51 +#define general_7 0x52 +#define general_8 0x53 +#ifndef PLAYMIDI +#define tremolo_depth 0x5c +#define ctrl_chorus_depth 0x5d +#define detune 0x5e +#define phaser_depth 0x5f +#endif + +/* parameter values */ +#define data_inc 0x60 +#define data_dec 0x61 + +/* parameter selection */ +#define non_reg_lsb 0x62 +#define non_reg_msb 0x63 +#define reg_lsb 0x64 +#define reg_msb 0x65 + +/* Standard MIDI Files meta event definitions */ +#define meta_event 0xFF +#define sequence_number 0x00 +#define text_event 0x01 +#define copyright_notice 0x02 +#define sequence_name 0x03 +#define instrument_name 0x04 +#define lyric 0x05 +#define marker 0x06 +#define cue_point 0x07 +#define channel_prefix 0x20 +#define end_of_track 0x2f +#define set_tempo 0x51 +#define smpte_offset 0x54 +#define time_signature 0x58 +#define key_signature 0x59 +#define sequencer_specific 0x74 + +/* Manufacturer's ID number */ +#define Seq_Circuits (0x01) /* Sequential Circuits Inc. */ +#define Big_Briar (0x02) /* Big Briar Inc. */ +#define Octave (0x03) /* Octave/Plateau */ +#define Moog (0x04) /* Moog Music */ +#define Passport (0x05) /* Passport Designs */ +#define Lexicon (0x06) /* Lexicon */ +#define Tempi (0x20) /* Bon Tempi */ +#define Siel (0x21) /* S.I.E.L. */ +#define Kawai (0x41) +#define Roland (0x42) +#define Korg (0x42) +#define Yamaha (0x43) +#endif + +/* miscellaneous definitions */ +#define MThd 0x4d546864 +#define MTrk 0x4d54726b + +#ifndef NO_LC_DEFINES +#define lowerbyte(x) ((unsigned char)(x & 0xff)) +#define upperbyte(x) ((unsigned char)((x & 0xff00)>>8)) +#endif diff --git a/test/midiloop.c b/test/midiloop.c new file mode 100644 index 0000000..31fbcd3 --- /dev/null +++ b/test/midiloop.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include "../include/asoundlib.h" +#include +#include + +static void usage(void) +{ + fprintf(stderr, "Usage: midiloop [options]\n"); + fprintf(stderr, " options:\n"); + fprintf(stderr, " -v: verbose mode\n"); + fprintf(stderr, " -i : test input device\n"); + fprintf(stderr, " -o : test output device\n"); +} + +int stop = 0; + +void sighandler(int dummy ATTRIBUTE_UNUSED) +{ + stop=1; +} + +long long timediff(struct timeval t1, struct timeval t2) +{ + signed long l; + + t1.tv_sec -= t2.tv_sec; + l = (signed long) t1.tv_usec - (signed long) t2.tv_usec; + if (l < 0) { + t1.tv_sec--; + l = -l; + l %= 1000000; + } + return ((long long)t1.tv_sec * (long long)1000000) + (long long)l; +} + +int writepattern(snd_rawmidi_t *handle_out, unsigned char *obuf) +{ + int patsize, i; + + patsize = 0; + for (i = 0; i < 15; i++) { + obuf[patsize++] = 0x90 + i; + obuf[patsize++] = 0x40; + obuf[patsize++] = 0x3f; + obuf[patsize++] = 0xb0 + i; + obuf[patsize++] = 0x2e; + obuf[patsize++] = 0x7a; + obuf[patsize++] = 0x80 + i; + obuf[patsize++] = 0x23; + obuf[patsize++] = 0x24; + obuf[patsize++] = 0xf0; + obuf[patsize++] = i; + obuf[patsize++] = 0xf7; + } + i = snd_rawmidi_write(handle_out, obuf, patsize); + if (i != patsize) { + printf("Written only %i bytes from %i bytes\n", i, patsize); + exit(EXIT_FAILURE); + } + return patsize; +} + +int main(int argc, char** argv) +{ + int i, j, k, opos, ipos, patsize; + int err; + int verbose = 0; + snd_rawmidi_t *handle_in = NULL, *handle_out = NULL; + unsigned char ibuf[512], obuf[512]; + char *iname = "hw:0,0", *oname = "hw:0,0"; + struct timeval start, end; + long long diff; + snd_rawmidi_status_t *istat, *ostat; + + for (i = 1 ; i 0) { + printf("Read ahead: %i\n", i); + for (j = 0; j < i; j++) + printf("%02x:", ibuf[j]); + printf("\n"); + exit(EXIT_FAILURE); + } + + snd_rawmidi_nonblock(handle_in, 0); + + patsize = writepattern(handle_out, obuf); + gettimeofday(&start, NULL); + patsize = writepattern(handle_out, obuf); + + k = ipos = opos = err = 0; + while (!stop) { + i = snd_rawmidi_read(handle_in, ibuf, sizeof(ibuf)); + for (j = 0; j < i; j++, ipos++) + if (obuf[k] != ibuf[j]) { + printf("ipos = %i, i[0x%x] != o[0x%x]\n", ipos, ibuf[j], obuf[k]); + if (opos > 0) + stop = 1; + } else { + printf("match success: ipos = %i, opos = %i [%i:0x%x]\n", ipos, opos, k, obuf[k]); + k++; opos++; + if (k >= patsize) { + patsize = writepattern(handle_out, obuf); + k = 0; + } + } + } + + gettimeofday(&end, NULL); + + printf("End...\n"); + + snd_rawmidi_status_alloca(&istat); + snd_rawmidi_status_alloca(&ostat); + err = snd_rawmidi_status(handle_in, istat); + if (err < 0) + fprintf(stderr, "input stream status error: %d\n", err); + err = snd_rawmidi_status(handle_out, ostat); + if (err < 0) + fprintf(stderr, "output stream status error: %d\n", err); + printf("input.status.avail = %i\n", snd_rawmidi_status_get_avail(istat)); + printf("input.status.xruns = %i\n", snd_rawmidi_status_get_xruns(istat)); + printf("output.status.avail = %i\n", snd_rawmidi_status_get_avail(ostat)); + printf("output.status.xruns = %i\n", snd_rawmidi_status_get_xruns(ostat)); + + diff = timediff(end, start); + printf("Time diff: %Liusec (%Li bytes/sec)\n", diff, ((long long)opos * 1000000) / diff); + + if (verbose) { + fprintf(stderr,"Closing\n"); + } + + snd_rawmidi_drain(handle_in); + snd_rawmidi_close(handle_in); + snd_rawmidi_drain(handle_out); + snd_rawmidi_close(handle_out); + + return 0; +} diff --git a/test/namehint.c b/test/namehint.c new file mode 100644 index 0000000..e978d5c --- /dev/null +++ b/test/namehint.c @@ -0,0 +1,22 @@ +#include "../include/asoundlib.h" +#include + +int main(int argc, char *argv[]) +{ + const char *iface = "pcm"; + char **hints, **n; + int err; + + if (argc > 1) + iface = argv[1]; + err = snd_device_name_hint(-1, iface, &hints); + if (err < 0) + errx(1, "snd_device_name_hint error: %s", snd_strerror(err)); + n = hints; + while (*n != NULL) { + printf("%s\n", *n); + n++; + } + snd_device_name_free_hint(hints); + return 0; +} diff --git a/test/oldapi.c b/test/oldapi.c new file mode 100644 index 0000000..e325f4c --- /dev/null +++ b/test/oldapi.c @@ -0,0 +1,42 @@ +/* + * Old PCM API compilation test + * + * Author: Jaroslav Kysela + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#define ALSA_PCM_OLD_HW_PARAMS_API +#define ALSA_PCM_OLD_SW_PARAMS_API +#include "../include/asoundlib.h" +#include + +typedef void (myfcn)(void *); + +int main(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) +{ + myfcn *fcn; + snd_pcm_hw_params_get_access(NULL); + fcn = &snd_pcm_hw_params_get_access; + return 0; +} diff --git a/test/pcm.c b/test/pcm.c new file mode 100644 index 0000000..abb83e4 --- /dev/null +++ b/test/pcm.c @@ -0,0 +1,925 @@ +/* + * This small demo sends a simple sinusoidal wave to your speakers. + */ + +#include +#include +#include +#include +#include +#include +#include "../include/asoundlib.h" +#include +#include + +static char *device = "plughw:0,0"; /* playback device */ +static snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */ +static unsigned int rate = 44100; /* stream rate */ +static unsigned int channels = 1; /* count of channels */ +static unsigned int buffer_time = 500000; /* ring buffer length in us */ +static unsigned int period_time = 100000; /* period time in us */ +static double freq = 440; /* sinusoidal wave frequency in Hz */ +static int verbose = 0; /* verbose flag */ +static int resample = 1; /* enable alsa-lib resampling */ +static int period_event = 0; /* produce poll event after each period */ + +static snd_pcm_sframes_t buffer_size; +static snd_pcm_sframes_t period_size; +static snd_output_t *output = NULL; + +static void generate_sine(const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + int count, double *_phase) +{ + static double max_phase = 2. * M_PI; + double phase = *_phase; + double step = max_phase*freq/(double)rate; + unsigned char *samples[channels]; + int steps[channels]; + unsigned int chn; + int format_bits = snd_pcm_format_width(format); + unsigned int maxval = (1 << (format_bits - 1)) - 1; + int bps = format_bits / 8; /* bytes per sample */ + int phys_bps = snd_pcm_format_physical_width(format) / 8; + int big_endian = snd_pcm_format_big_endian(format) == 1; + int to_unsigned = snd_pcm_format_unsigned(format) == 1; + int is_float = (format == SND_PCM_FORMAT_FLOAT_LE || + format == SND_PCM_FORMAT_FLOAT_BE); + + /* verify and prepare the contents of areas */ + for (chn = 0; chn < channels; chn++) { + if ((areas[chn].first % 8) != 0) { + printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first); + exit(EXIT_FAILURE); + } + samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8)); + if ((areas[chn].step % 16) != 0) { + printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step); + exit(EXIT_FAILURE); + } + steps[chn] = areas[chn].step / 8; + samples[chn] += offset * steps[chn]; + } + /* fill the channel areas */ + while (count-- > 0) { + union { + float f; + int i; + } fval; + int res, i; + if (is_float) { + fval.f = sin(phase) * maxval; + res = fval.i; + } else + res = sin(phase) * maxval; + if (to_unsigned) + res ^= 1U << (format_bits - 1); + for (chn = 0; chn < channels; chn++) { + /* Generate data in native endian format */ + if (big_endian) { + for (i = 0; i < bps; i++) + *(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff; + } else { + for (i = 0; i < bps; i++) + *(samples[chn] + i) = (res >> i * 8) & 0xff; + } + samples[chn] += steps[chn]; + } + phase += step; + if (phase >= max_phase) + phase -= max_phase; + } + *_phase = phase; +} + +static int set_hwparams(snd_pcm_t *handle, + snd_pcm_hw_params_t *params, + snd_pcm_access_t access) +{ + unsigned int rrate; + snd_pcm_uframes_t size; + int err, dir; + + /* choose all parameters */ + err = snd_pcm_hw_params_any(handle, params); + if (err < 0) { + printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); + return err; + } + /* set hardware resampling */ + err = snd_pcm_hw_params_set_rate_resample(handle, params, resample); + if (err < 0) { + printf("Resampling setup failed for playback: %s\n", snd_strerror(err)); + return err; + } + /* set the interleaved read/write format */ + err = snd_pcm_hw_params_set_access(handle, params, access); + if (err < 0) { + printf("Access type not available for playback: %s\n", snd_strerror(err)); + return err; + } + /* set the sample format */ + err = snd_pcm_hw_params_set_format(handle, params, format); + if (err < 0) { + printf("Sample format not available for playback: %s\n", snd_strerror(err)); + return err; + } + /* set the count of channels */ + err = snd_pcm_hw_params_set_channels(handle, params, channels); + if (err < 0) { + printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); + return err; + } + /* set the stream rate */ + rrate = rate; + err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); + if (err < 0) { + printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); + return err; + } + if (rrate != rate) { + printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); + return -EINVAL; + } + /* set the buffer time */ + err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); + if (err < 0) { + printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_get_buffer_size(params, &size); + if (err < 0) { + printf("Unable to get buffer size for playback: %s\n", snd_strerror(err)); + return err; + } + buffer_size = size; + /* set the period time */ + err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); + if (err < 0) { + printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); + return err; + } + err = snd_pcm_hw_params_get_period_size(params, &size, &dir); + if (err < 0) { + printf("Unable to get period size for playback: %s\n", snd_strerror(err)); + return err; + } + period_size = size; + /* write the parameters to device */ + err = snd_pcm_hw_params(handle, params); + if (err < 0) { + printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); + return err; + } + return 0; +} + +static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) +{ + int err; + + /* get the current swparams */ + err = snd_pcm_sw_params_current(handle, swparams); + if (err < 0) { + printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); + return err; + } + /* start the transfer when the buffer is almost full: */ + /* (buffer_size / avail_min) * avail_min */ + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); + if (err < 0) { + printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); + return err; + } + /* allow the transfer when at least period_size samples can be processed */ + /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ + err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size); + if (err < 0) { + printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); + return err; + } + /* enable period events when requested */ + if (period_event) { + err = snd_pcm_sw_params_set_period_event(handle, swparams, 1); + if (err < 0) { + printf("Unable to set period event: %s\n", snd_strerror(err)); + return err; + } + } + /* write the parameters to the playback device */ + err = snd_pcm_sw_params(handle, swparams); + if (err < 0) { + printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); + return err; + } + return 0; +} + +/* + * Underrun and suspend recovery + */ + +static int xrun_recovery(snd_pcm_t *handle, int err) +{ + if (verbose) + printf("stream recovery\n"); + if (err == -EPIPE) { /* under-run */ + err = snd_pcm_prepare(handle); + if (err < 0) + printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); + return 0; + } else if (err == -ESTRPIPE) { + while ((err = snd_pcm_resume(handle)) == -EAGAIN) + sleep(1); /* wait until the suspend flag is released */ + if (err < 0) { + err = snd_pcm_prepare(handle); + if (err < 0) + printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); + } + return 0; + } + return err; +} + +/* + * Transfer method - write only + */ + +static int write_loop(snd_pcm_t *handle, + signed short *samples, + snd_pcm_channel_area_t *areas) +{ + double phase = 0; + signed short *ptr; + int err, cptr; + + while (1) { + generate_sine(areas, 0, period_size, &phase); + ptr = samples; + cptr = period_size; + while (cptr > 0) { + err = snd_pcm_writei(handle, ptr, cptr); + if (err == -EAGAIN) + continue; + if (err < 0) { + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + break; /* skip one period */ + } + ptr += err * channels; + cptr -= err; + } + } +} + +/* + * Transfer method - write and wait for room in buffer using poll + */ + +static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count) +{ + unsigned short revents; + + while (1) { + poll(ufds, count, -1); + snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents); + if (revents & POLLERR) + return -EIO; + if (revents & POLLOUT) + return 0; + } +} + +static int write_and_poll_loop(snd_pcm_t *handle, + signed short *samples, + snd_pcm_channel_area_t *areas) +{ + struct pollfd *ufds; + double phase = 0; + signed short *ptr; + int err, count, cptr, init; + + count = snd_pcm_poll_descriptors_count (handle); + if (count <= 0) { + printf("Invalid poll descriptors count\n"); + return count; + } + + ufds = malloc(sizeof(struct pollfd) * count); + if (ufds == NULL) { + printf("No enough memory\n"); + return -ENOMEM; + } + if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) { + printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err)); + return err; + } + + init = 1; + while (1) { + if (!init) { + err = wait_for_poll(handle, ufds, count); + if (err < 0) { + if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN || + snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) { + err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + init = 1; + } else { + printf("Wait for poll failed\n"); + return err; + } + } + } + + generate_sine(areas, 0, period_size, &phase); + ptr = samples; + cptr = period_size; + while (cptr > 0) { + err = snd_pcm_writei(handle, ptr, cptr); + if (err < 0) { + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + init = 1; + break; /* skip one period */ + } + if (snd_pcm_state(handle) == SND_PCM_STATE_RUNNING) + init = 0; + ptr += err * channels; + cptr -= err; + if (cptr == 0) + break; + /* it is possible, that the initial buffer cannot store */ + /* all data from the last period, so wait awhile */ + err = wait_for_poll(handle, ufds, count); + if (err < 0) { + if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN || + snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) { + err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + init = 1; + } else { + printf("Wait for poll failed\n"); + return err; + } + } + } + } +} + +/* + * Transfer method - asynchronous notification + */ + +struct async_private_data { + signed short *samples; + snd_pcm_channel_area_t *areas; + double phase; +}; + +static void async_callback(snd_async_handler_t *ahandler) +{ + snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); + struct async_private_data *data = snd_async_handler_get_callback_private(ahandler); + signed short *samples = data->samples; + snd_pcm_channel_area_t *areas = data->areas; + snd_pcm_sframes_t avail; + int err; + + avail = snd_pcm_avail_update(handle); + while (avail >= period_size) { + generate_sine(areas, 0, period_size, &data->phase); + err = snd_pcm_writei(handle, samples, period_size); + if (err < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + if (err != period_size) { + printf("Write error: written %i expected %li\n", err, period_size); + exit(EXIT_FAILURE); + } + avail = snd_pcm_avail_update(handle); + } +} + +static int async_loop(snd_pcm_t *handle, + signed short *samples, + snd_pcm_channel_area_t *areas) +{ + struct async_private_data data; + snd_async_handler_t *ahandler; + int err, count; + + data.samples = samples; + data.areas = areas; + data.phase = 0; + err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, &data); + if (err < 0) { + printf("Unable to register async handler\n"); + exit(EXIT_FAILURE); + } + for (count = 0; count < 2; count++) { + generate_sine(areas, 0, period_size, &data.phase); + err = snd_pcm_writei(handle, samples, period_size); + if (err < 0) { + printf("Initial write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + if (err != period_size) { + printf("Initial write error: written %i expected %li\n", err, period_size); + exit(EXIT_FAILURE); + } + } + if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) { + err = snd_pcm_start(handle); + if (err < 0) { + printf("Start error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + } + + /* because all other work is done in the signal handler, + suspend the process */ + while (1) { + sleep(1); + } +} + +/* + * Transfer method - asynchronous notification + direct write + */ + +static void async_direct_callback(snd_async_handler_t *ahandler) +{ + snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); + struct async_private_data *data = snd_async_handler_get_callback_private(ahandler); + const snd_pcm_channel_area_t *my_areas; + snd_pcm_uframes_t offset, frames, size; + snd_pcm_sframes_t avail, commitres; + snd_pcm_state_t state; + int first = 0, err; + + while (1) { + state = snd_pcm_state(handle); + if (state == SND_PCM_STATE_XRUN) { + err = xrun_recovery(handle, -EPIPE); + if (err < 0) { + printf("XRUN recovery failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + } else if (state == SND_PCM_STATE_SUSPENDED) { + err = xrun_recovery(handle, -ESTRPIPE); + if (err < 0) { + printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + } + avail = snd_pcm_avail_update(handle); + if (avail < 0) { + err = xrun_recovery(handle, avail); + if (err < 0) { + printf("avail update failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + continue; + } + if (avail < period_size) { + if (first) { + first = 0; + err = snd_pcm_start(handle); + if (err < 0) { + printf("Start error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + } else { + break; + } + continue; + } + size = period_size; + while (size > 0) { + frames = size; + err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); + if (err < 0) { + if ((err = xrun_recovery(handle, err)) < 0) { + printf("MMAP begin avail error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + } + generate_sine(my_areas, offset, frames, &data->phase); + commitres = snd_pcm_mmap_commit(handle, offset, frames); + if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { + if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { + printf("MMAP commit error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + } + size -= frames; + } + } +} + +static int async_direct_loop(snd_pcm_t *handle, + signed short *samples ATTRIBUTE_UNUSED, + snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED) +{ + struct async_private_data data; + snd_async_handler_t *ahandler; + const snd_pcm_channel_area_t *my_areas; + snd_pcm_uframes_t offset, frames, size; + snd_pcm_sframes_t commitres; + int err, count; + + data.samples = NULL; /* we do not require the global sample area for direct write */ + data.areas = NULL; /* we do not require the global areas for direct write */ + data.phase = 0; + err = snd_async_add_pcm_handler(&ahandler, handle, async_direct_callback, &data); + if (err < 0) { + printf("Unable to register async handler\n"); + exit(EXIT_FAILURE); + } + for (count = 0; count < 2; count++) { + size = period_size; + while (size > 0) { + frames = size; + err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); + if (err < 0) { + if ((err = xrun_recovery(handle, err)) < 0) { + printf("MMAP begin avail error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + } + generate_sine(my_areas, offset, frames, &data.phase); + commitres = snd_pcm_mmap_commit(handle, offset, frames); + if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { + if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { + printf("MMAP commit error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + } + size -= frames; + } + } + err = snd_pcm_start(handle); + if (err < 0) { + printf("Start error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + + /* because all other work is done in the signal handler, + suspend the process */ + while (1) { + sleep(1); + } +} + +/* + * Transfer method - direct write only + */ + +static int direct_loop(snd_pcm_t *handle, + signed short *samples ATTRIBUTE_UNUSED, + snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED) +{ + double phase = 0; + const snd_pcm_channel_area_t *my_areas; + snd_pcm_uframes_t offset, frames, size; + snd_pcm_sframes_t avail, commitres; + snd_pcm_state_t state; + int err, first = 1; + + while (1) { + state = snd_pcm_state(handle); + if (state == SND_PCM_STATE_XRUN) { + err = xrun_recovery(handle, -EPIPE); + if (err < 0) { + printf("XRUN recovery failed: %s\n", snd_strerror(err)); + return err; + } + first = 1; + } else if (state == SND_PCM_STATE_SUSPENDED) { + err = xrun_recovery(handle, -ESTRPIPE); + if (err < 0) { + printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); + return err; + } + } + avail = snd_pcm_avail_update(handle); + if (avail < 0) { + err = xrun_recovery(handle, avail); + if (err < 0) { + printf("avail update failed: %s\n", snd_strerror(err)); + return err; + } + first = 1; + continue; + } + if (avail < period_size) { + if (first) { + first = 0; + err = snd_pcm_start(handle); + if (err < 0) { + printf("Start error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + } else { + err = snd_pcm_wait(handle, -1); + if (err < 0) { + if ((err = xrun_recovery(handle, err)) < 0) { + printf("snd_pcm_wait error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + } + } + continue; + } + size = period_size; + while (size > 0) { + frames = size; + err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); + if (err < 0) { + if ((err = xrun_recovery(handle, err)) < 0) { + printf("MMAP begin avail error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + } + generate_sine(my_areas, offset, frames, &phase); + commitres = snd_pcm_mmap_commit(handle, offset, frames); + if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { + if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { + printf("MMAP commit error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + first = 1; + } + size -= frames; + } + } +} + +/* + * Transfer method - direct write only using mmap_write functions + */ + +static int direct_write_loop(snd_pcm_t *handle, + signed short *samples, + snd_pcm_channel_area_t *areas) +{ + double phase = 0; + signed short *ptr; + int err, cptr; + + while (1) { + generate_sine(areas, 0, period_size, &phase); + ptr = samples; + cptr = period_size; + while (cptr > 0) { + err = snd_pcm_mmap_writei(handle, ptr, cptr); + if (err == -EAGAIN) + continue; + if (err < 0) { + if (xrun_recovery(handle, err) < 0) { + printf("Write error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + break; /* skip one period */ + } + ptr += err * channels; + cptr -= err; + } + } +} + +/* + * + */ + +struct transfer_method { + const char *name; + snd_pcm_access_t access; + int (*transfer_loop)(snd_pcm_t *handle, + signed short *samples, + snd_pcm_channel_area_t *areas); +}; + +static struct transfer_method transfer_methods[] = { + { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop }, + { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop }, + { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop }, + { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop }, + { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop }, + { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop }, + { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop }, + { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL } +}; + +static void help(void) +{ + int k; + printf( +"Usage: pcm [OPTION]... [FILE]...\n" +"-h,--help help\n" +"-D,--device playback device\n" +"-r,--rate stream rate in Hz\n" +"-c,--channels count of channels in stream\n" +"-f,--frequency sine wave frequency in Hz\n" +"-b,--buffer ring buffer size in us\n" +"-p,--period period size in us\n" +"-m,--method transfer method\n" +"-o,--format sample format\n" +"-v,--verbose show the PCM setup parameters\n" +"-n,--noresample do not resample\n" +"-e,--pevent enable poll event after each period\n" +"\n"); + printf("Recognized sample formats are:"); + for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) { + const char *s = snd_pcm_format_name(k); + if (s) + printf(" %s", s); + } + printf("\n"); + printf("Recognized transfer methods are:"); + for (k = 0; transfer_methods[k].name; k++) + printf(" %s", transfer_methods[k].name); + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + struct option long_option[] = + { + {"help", 0, NULL, 'h'}, + {"device", 1, NULL, 'D'}, + {"rate", 1, NULL, 'r'}, + {"channels", 1, NULL, 'c'}, + {"frequency", 1, NULL, 'f'}, + {"buffer", 1, NULL, 'b'}, + {"period", 1, NULL, 'p'}, + {"method", 1, NULL, 'm'}, + {"format", 1, NULL, 'o'}, + {"verbose", 1, NULL, 'v'}, + {"noresample", 1, NULL, 'n'}, + {"pevent", 1, NULL, 'e'}, + {NULL, 0, NULL, 0}, + }; + snd_pcm_t *handle; + int err, morehelp; + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + int method = 0; + signed short *samples; + unsigned int chn; + snd_pcm_channel_area_t *areas; + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + + morehelp = 0; + while (1) { + int c; + if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0) + break; + switch (c) { + case 'h': + morehelp++; + break; + case 'D': + device = strdup(optarg); + break; + case 'r': + rate = atoi(optarg); + rate = rate < 4000 ? 4000 : rate; + rate = rate > 196000 ? 196000 : rate; + break; + case 'c': + channels = atoi(optarg); + channels = channels < 1 ? 1 : channels; + channels = channels > 1024 ? 1024 : channels; + break; + case 'f': + freq = atoi(optarg); + freq = freq < 50 ? 50 : freq; + freq = freq > 5000 ? 5000 : freq; + break; + case 'b': + buffer_time = atoi(optarg); + buffer_time = buffer_time < 1000 ? 1000 : buffer_time; + buffer_time = buffer_time > 1000000 ? 1000000 : buffer_time; + break; + case 'p': + period_time = atoi(optarg); + period_time = period_time < 1000 ? 1000 : period_time; + period_time = period_time > 1000000 ? 1000000 : period_time; + break; + case 'm': + for (method = 0; transfer_methods[method].name; method++) + if (!strcasecmp(transfer_methods[method].name, optarg)) + break; + if (transfer_methods[method].name == NULL) + method = 0; + break; + case 'o': + for (format = 0; format < SND_PCM_FORMAT_LAST; format++) { + const char *format_name = snd_pcm_format_name(format); + if (format_name) + if (!strcasecmp(format_name, optarg)) + break; + } + if (format == SND_PCM_FORMAT_LAST) + format = SND_PCM_FORMAT_S16; + if (!snd_pcm_format_linear(format) && + !(format == SND_PCM_FORMAT_FLOAT_LE || + format == SND_PCM_FORMAT_FLOAT_BE)) { + printf("Invalid (non-linear/float) format %s\n", + optarg); + return 1; + } + break; + case 'v': + verbose = 1; + break; + case 'n': + resample = 0; + break; + case 'e': + period_event = 1; + break; + } + } + + if (morehelp) { + help(); + return 0; + } + + err = snd_output_stdio_attach(&output, stdout, 0); + if (err < 0) { + printf("Output failed: %s\n", snd_strerror(err)); + return 0; + } + + printf("Playback device is %s\n", device); + printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels); + printf("Sine wave rate is %.4fHz\n", freq); + printf("Using transfer method: %s\n", transfer_methods[method].name); + + if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + printf("Playback open error: %s\n", snd_strerror(err)); + return 0; + } + + if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access)) < 0) { + printf("Setting of hwparams failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + if ((err = set_swparams(handle, swparams)) < 0) { + printf("Setting of swparams failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + + if (verbose > 0) + snd_pcm_dump(handle, output); + + samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8); + if (samples == NULL) { + printf("No enough memory\n"); + exit(EXIT_FAILURE); + } + + areas = calloc(channels, sizeof(snd_pcm_channel_area_t)); + if (areas == NULL) { + printf("No enough memory\n"); + exit(EXIT_FAILURE); + } + for (chn = 0; chn < channels; chn++) { + areas[chn].addr = samples; + areas[chn].first = chn * snd_pcm_format_physical_width(format); + areas[chn].step = channels * snd_pcm_format_physical_width(format); + } + + err = transfer_methods[method].transfer_loop(handle, samples, areas); + if (err < 0) + printf("Transfer failed: %s\n", snd_strerror(err)); + + free(areas); + free(samples); + snd_pcm_close(handle); + return 0; +} + diff --git a/test/pcm_min.c b/test/pcm_min.c new file mode 100644 index 0000000..e971405 --- /dev/null +++ b/test/pcm_min.c @@ -0,0 +1,51 @@ +/* + * This extra small demo sends a random samples to your speakers. + */ + +#include "../include/asoundlib.h" + +static char *device = "default"; /* playback device */ + +snd_output_t *output = NULL; +unsigned char buffer[16*1024]; /* some random data */ + +int main(void) +{ + int err; + unsigned int i; + snd_pcm_t *handle; + snd_pcm_sframes_t frames; + + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = random() & 0xff; + + if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + printf("Playback open error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + if ((err = snd_pcm_set_params(handle, + SND_PCM_FORMAT_U8, + SND_PCM_ACCESS_RW_INTERLEAVED, + 1, + 48000, + 1, + 500000)) < 0) { /* 0.5sec */ + printf("Playback open error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + + for (i = 0; i < 16; i++) { + frames = snd_pcm_writei(handle, buffer, sizeof(buffer)); + if (frames < 0) + frames = snd_pcm_recover(handle, frames, 0); + if (frames < 0) { + printf("snd_pcm_writei failed: %s\n", snd_strerror(err)); + break; + } + if (frames > 0 && frames < (long)sizeof(buffer)) + printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames); + } + + snd_pcm_close(handle); + return 0; +} diff --git a/test/playmidi1.c b/test/playmidi1.c new file mode 100644 index 0000000..a7f3a63 --- /dev/null +++ b/test/playmidi1.c @@ -0,0 +1,617 @@ +/* + * MIDI file player for ALSA sequencer + * (type 0 only!, the library that is used doesn't support merging of tracks) + * + * Copyright (c) 1998 by Frank van de Pol + * + * Modified so that this uses alsa-lib + * 1999 Jan. by Isaku Yamahata + * + * 19990604 Takashi Iwai + * - use blocking mode + * - fix tempo event bug + * - add command line options + * + * 19990827 Takashi Iwai + * - use snd_seq_alloc_queue() + * + * 19990916 Takashi Iwai + * - use middle-level sequencer routines and macros + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "midifile.h" /* SMF library header */ +#include "midifile.c" /* SMF library code */ + +#include "../include/asoundlib.h" + +/* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */ +static int use_realtime = 0; + +/* control the event buffering by using a blocking mode */ +static int use_blocking_mode = 1; + +/* default destination queue, client and port numbers */ +#define DEST_CLIENT_NUMBER 65 +#define DEST_PORT_NUMBER 0 + +/* event pool size */ +#define WRITE_POOL_SIZE 200 +#define WRITE_POOL_SPACE 10 +#define READ_POOL_SIZE 10 /* we need to read the pool only for echoing */ + +static FILE *F; +static snd_seq_t *seq_handle = NULL; +static int ppq = 96; +static int slave_ppq = 96; + +static double local_secs = 0; +static int local_ticks = 0; +static int local_tempo = 500000; + +static int dest_queue = -1; +static int shared_queue = 0; +static int tick_offset = 0; +static int dest_client = DEST_CLIENT_NUMBER; +static int dest_port = DEST_PORT_NUMBER; +static int my_port = 0; + +static int verbose = 0; +static int slave = 0; /* allow external sync */ + +#define VERB_INFO 1 +#define VERB_MUCH 2 +#define VERB_EVENT 3 + +static void alsa_start_timer(void); +static void alsa_stop_timer(void); +static void wait_start(void); + + +static inline double tick2time_dbl(int tick) +{ + return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq); +} + +static void tick2time(snd_seq_real_time_t * tm, int tick) +{ + double secs = tick2time_dbl(tick); + tm->tv_sec = secs; + tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9; +} + +static void write_ev(snd_seq_event_t *ev) +{ + int rc; + + if (use_blocking_mode) { + rc = snd_seq_event_output(seq_handle, ev); + if (rc < 0) { + printf("written = %i (%s)\n", rc, snd_strerror(rc)); + exit(1); + } + return; + } + while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) { + int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLOUT); + struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); + snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLOUT); + if ((rc = poll(pfds, npfds, -1)) < 0) { + printf("poll error = %i (%s)\n", rc, snd_strerror(errno)); + exit(1); + } + } +} + +/* read the byte */ +static int mygetc(void) +{ + return getc(F); +} + +/* print out the text */ +static void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg) +{ + char *p; + char *ep = msg + leng; + + if (verbose >= VERB_INFO) { + for (p = msg; p < ep; p++) + putchar(isprint(*p) ? *p : '?'); + putchar('\n'); + } +} + +static void do_header(int format, int ntracks, int division) +{ + snd_seq_queue_tempo_t *tempo; + + if (verbose >= VERB_INFO) + printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division); + ppq = division; + + if (format != 0 || ntracks != 1) { + printf("This player does not support merging of tracks.\n"); + if (! shared_queue) + alsa_stop_timer(); + exit(1); + } + /* set the ppq */ + snd_seq_queue_tempo_alloca(&tempo); + /* ppq must be set before starting the timer */ + if (snd_seq_get_queue_tempo(seq_handle, dest_queue, tempo) < 0) { + perror("get_queue_tempo"); + exit(1); + } + if ((slave_ppq = snd_seq_queue_tempo_get_ppq(tempo)) != ppq) { + snd_seq_queue_tempo_set_ppq(tempo, ppq); + if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) { + perror("set_queue_tempo"); + if (!slave && !shared_queue) + exit(1); + else + printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq); + } else + slave_ppq = ppq; + if (verbose >= VERB_INFO) + printf("ALSA Timer updated, PPQ = %d\n", snd_seq_queue_tempo_get_ppq(tempo)); + } + + /* start playing... */ + if (slave) { + if (verbose >= VERB_INFO) + printf("Wait till timer starts...\n"); + wait_start(); + if (verbose >= VERB_INFO) + printf("Go!\n"); + } else if (shared_queue) { + snd_seq_queue_status_t *stat; + snd_seq_queue_status_alloca(&stat); + snd_seq_get_queue_status(seq_handle, dest_queue, stat); + tick_offset = snd_seq_queue_status_get_tick_time(stat); + fprintf(stderr, "tick offset = %d\n", tick_offset); + } else { + alsa_start_timer(); + tick_offset = 0; + } +} + +/* fill the event time */ +static void set_event_time(snd_seq_event_t *ev, unsigned int currtime) +{ + if (use_realtime) { + snd_seq_real_time_t rtime; + if (ppq != slave_ppq) + currtime = (currtime * slave_ppq) / ppq; + tick2time(&rtime, currtime); + snd_seq_ev_schedule_real(ev, dest_queue, 0, &rtime); + } else { + if (ppq != slave_ppq) + currtime = (currtime * slave_ppq) / ppq; + currtime += tick_offset; + snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime); + } +} + +/* fill the normal event header */ +static void set_event_header(snd_seq_event_t *ev) +{ + snd_seq_ev_clear(ev); + snd_seq_ev_set_dest(ev, dest_client, dest_port); + snd_seq_ev_set_source(ev, my_port); + set_event_time(ev, Mf_currtime); +} + +/* start the timer */ +static void alsa_start_timer(void) +{ + snd_seq_start_queue(seq_handle, dest_queue, NULL); +} + +/* stop the timer */ +static void alsa_stop_timer(void) +{ + snd_seq_event_t ev; + set_event_header(&ev); + snd_seq_stop_queue(seq_handle, dest_queue, &ev); +} + +/* change the tempo */ +static void do_tempo(int us) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_MUCH) { + double bpm; + bpm = 60.0E6 / (double) us; + printf("Tempo %d us/beat, %.2f bpm\n", us, bpm); + } + + /* store the new tempo and timestamp of the tempo change */ + local_secs = tick2time_dbl(Mf_currtime); + local_ticks = Mf_currtime; + local_tempo = us; + + set_event_header(&ev); + if (!slave) + snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev); +} + +static void do_noteon(int chan, int pitch, int vol) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: NoteOn (%d) %d %d\n", Mf_currtime, chan, pitch, vol); + set_event_header(&ev); + snd_seq_ev_set_noteon(&ev, chan, pitch, vol); + write_ev(&ev); +} + + +static void do_noteoff(int chan, int pitch, int vol) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: NoteOff (%d) %d %d\n", Mf_currtime, chan, pitch, vol); + set_event_header(&ev); + snd_seq_ev_set_noteoff(&ev, chan, pitch, vol); + write_ev(&ev); +} + + +static void do_program(int chan, int program) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: Program (%d) %d\n", Mf_currtime, chan, program); + set_event_header(&ev); + snd_seq_ev_set_pgmchange(&ev, chan, program); + write_ev(&ev); +} + + +static void do_parameter(int chan, int control, int value) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: Control (%d) %d %d\n", Mf_currtime, chan, control, value); + set_event_header(&ev); + snd_seq_ev_set_controller(&ev, chan, control, value); + write_ev(&ev); +} + + +static void do_pitchbend(int chan, int lsb, int msb) +{ /* !@#$% lsb & msb are in the wrong order in docs */ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: Pitchbend (%d) %d %d\n", Mf_currtime, chan, lsb, msb); + set_event_header(&ev); + snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192); + write_ev(&ev); +} + +static void do_pressure(int chan, int pitch, int pressure) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: KeyPress (%d) %d %d\n", Mf_currtime, chan, pitch, pressure); + set_event_header(&ev); + snd_seq_ev_set_keypress(&ev, chan, pitch, pressure); + write_ev(&ev); +} + +static void do_chanpressure(int chan, int pressure) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_EVENT) + printf("%ld: ChanPress (%d) %d\n", Mf_currtime, chan, pressure); + set_event_header(&ev); + snd_seq_ev_set_chanpress(&ev, chan, pressure); + write_ev(&ev); +} + +static void do_sysex(int len, char *msg) +{ + snd_seq_event_t ev; + + if (verbose >= VERB_MUCH) { + int c; + printf("%ld: Sysex, len=%d\n", Mf_currtime, len); + for (c = 0; c < len; c++) { + printf(" %02x", (unsigned char)msg[c]); + if (c % 16 == 15) + putchar('\n'); + } + if (c % 16 != 15) + putchar('\n'); + } + + set_event_header(&ev); + snd_seq_ev_set_sysex(&ev, len, msg); + write_ev(&ev); +} + +static snd_seq_event_t *wait_for_event(void) +{ + int left; + snd_seq_event_t *input_event; + + if (use_blocking_mode) { + /* read the event - blocked until any event is read */ + left = snd_seq_event_input(seq_handle, &input_event); + } else { + /* read the event - using select syscall */ + while ((left = snd_seq_event_input(seq_handle, &input_event)) >= 0 && + input_event == NULL) { + int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); + struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); + snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN); + if ((left = poll(pfds, npfds, -1)) < 0) { + printf("poll error = %i (%s)\n", errno, snd_strerror(errno)); + exit(1); + } + } + } + + if (left < 0) { + printf("alsa_sync error!:%s\n", snd_strerror(left)); + return NULL; + } + + return input_event; +} + +/* synchronize to the end of the event */ +static void alsa_sync(void) +{ + /* send the echo event to the self client. */ + if (verbose >= VERB_MUCH) + printf("alsa_sync syncing...\n"); + /* dump the buffer */ + snd_seq_drain_output(seq_handle); + snd_seq_sync_output_queue(seq_handle); + if (verbose >= VERB_MUCH) + printf("alsa_sync synced\n"); + sleep(1); /* give a time for note releasing.. */ +} + + +/* wait for the start of the queue */ +static void wait_start(void) +{ + snd_seq_event_t *input_event; + + /* wait for the start event from the system timer */ + for (;;) { + input_event = wait_for_event(); + if (input_event) { + if (verbose >= VERB_MUCH) + printf("wait_start got event. type=%d, flags=%d\n", + input_event->type, input_event->flags); + if (input_event->type == SND_SEQ_EVENT_START && + input_event->data.queue.queue == dest_queue) { + snd_seq_free_event(input_event); + break; + } + snd_seq_free_event(input_event); + } + } + if (verbose >= VERB_MUCH) + printf("start received\n"); +} + + +/* print the usage */ +static void usage(void) +{ + fprintf(stderr, "usage: playmidi1 [options] [file]\n"); + fprintf(stderr, " options:\n"); + fprintf(stderr, " -v: verbose mode\n"); + fprintf(stderr, " -a client:port : set destination address (default=%d:%d)\n", + DEST_CLIENT_NUMBER, DEST_PORT_NUMBER); + fprintf(stderr, " -q queue: use the specified queue\n"); + fprintf(stderr, " -s queue: slave mode (allow external clock synchronization)\n"); + fprintf(stderr, " -r : play on real-time mode\n"); + fprintf(stderr, " -b : play on non-blocking mode\n"); +} + +int main(int argc, char *argv[]) +{ + int tmp; + int c; + snd_seq_addr_t dest_addr; + const char *addr = "65:0"; + + while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) { + switch (c) { + case 'v': + verbose++; + break; + case 'a': + case 'p': + addr = optarg; + break; + case 'q': + dest_queue = atoi(optarg); + if (dest_queue < 0) { + fprintf(stderr, "invalid queue number %d\n", dest_queue); + exit(1); + } + break; + case 's': + slave = 1; + dest_queue = atoi(optarg); + if (dest_queue < 0) { + fprintf(stderr, "invalid queue number %d\n", dest_queue); + exit(1); + } + break; + case 'r': + use_realtime = 1; + break; + case 'b': + use_blocking_mode = 0; + break; + default: + usage(); + exit(1); + } + } + + if (verbose >= VERB_INFO) { + if (use_realtime) + printf("ALSA MIDI Player, feeding events to real-time queue\n"); + else + printf("ALSA MIDI Player, feeding events to song queue\n"); + } + + /* open the sequencer device */ + /* Here we open the device in read/write for slave mode. */ + tmp = snd_seq_open(&seq_handle, "hw", slave ? SND_SEQ_OPEN_DUPLEX : SND_SEQ_OPEN_OUTPUT, 0); + if (tmp < 0) { + perror("open /dev/snd/seq"); + exit(1); + } + + tmp = snd_seq_nonblock(seq_handle, !use_blocking_mode); + if (tmp < 0) { + perror("block_mode"); + exit(1); + } + + /* set the name */ + /* set the event filter to receive only the echo event */ + /* if running in slave mode, also listen for a START event */ + if (slave) + snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START); + snd_seq_set_client_name(seq_handle, "MIDI file player"); + + /* create the port */ + my_port = snd_seq_create_simple_port(seq_handle, "Port 0", + SND_SEQ_PORT_CAP_WRITE | + SND_SEQ_PORT_CAP_READ, + SND_SEQ_PORT_TYPE_MIDI_GENERIC); + if (my_port < 0) { + perror("create port"); + exit(1); + } + + if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) { + perror("invalid destination address"); + exit(1); + } + dest_client = dest_addr.client; + dest_port = dest_addr.port; + + /* set the queue */ + if (dest_queue >= 0) { + shared_queue = 1; + if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) { + perror("use queue"); + exit(1); + } + } else { + shared_queue = 0; + dest_queue = snd_seq_alloc_queue(seq_handle); + if (dest_queue < 0) { + perror("alloc queue"); + exit(1); + } + } + + /* set the subscriber */ + tmp = snd_seq_connect_to(seq_handle, my_port, dest_client, dest_port); + if (tmp < 0) { + perror("subscribe"); + exit(1); + } + + /* subscribe for the timer START event */ + if (slave) { + tmp = snd_seq_connect_from(seq_handle, my_port, + SND_SEQ_CLIENT_SYSTEM, + dest_queue + 16 /*snd_seq_queue_sync_port(dest_queue)*/); + if (tmp < 0) { + perror("subscribe"); + exit(1); + } + } + + /* change the pool size */ + if (snd_seq_set_client_pool_output(seq_handle, WRITE_POOL_SIZE) < 0 || + snd_seq_set_client_pool_input(seq_handle, READ_POOL_SIZE) < 0 || + snd_seq_set_client_pool_output_room(seq_handle, WRITE_POOL_SPACE) < 0) { + perror("pool"); + exit(1); + } + + if (optind < argc) { + F = fopen(argv[optind], "r"); + if (F == NULL) { + fprintf(stderr, "playmidi1: can't open file %s\n", argv[optind]); + exit(1); + } + } else + F = stdin; + + Mf_header = do_header; + Mf_tempo = do_tempo; + Mf_getc = mygetc; + Mf_text = mytext; + + Mf_noteon = do_noteon; + Mf_noteoff = do_noteoff; + Mf_program = do_program; + Mf_parameter = do_parameter; + Mf_pitchbend = do_pitchbend; + Mf_pressure = do_pressure; + Mf_chanpressure = do_chanpressure; + Mf_sysex = do_sysex; + + /* go.. go.. go.. */ + mfread(); + + alsa_sync(); + if (! shared_queue) + alsa_stop_timer(); + + snd_seq_close(seq_handle); + + if (verbose >= VERB_INFO) { + printf("Stopping at %f s, tick %f\n", + tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1)); + } + + exit(0); +} diff --git a/test/queue_timer.c b/test/queue_timer.c new file mode 100644 index 0000000..c4ffb19 --- /dev/null +++ b/test/queue_timer.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include + +void normalize(struct timeval *tv) +{ + if (tv->tv_sec == 0) { + while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; } + while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; } + } else if (tv->tv_sec < 0) { + while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; } + while (tv->tv_usec > 0) { tv->tv_usec -= 1000000; ++tv->tv_sec; } + } else { + while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; } + while (tv->tv_usec < 0) { tv->tv_usec += 1000000; --tv->tv_sec; } + } +} + +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + snd_seq_t *handle; + int portid; + /* int npfd; + struct pollfd *pfd; + */ + int queue; + /* int i; + int rval;' + */ + struct timeval starttv, prevdiff; + int countdown = -1; + /* snd_seq_queue_timer_t *timer; + snd_timer_id_t *timerid; + */ + + if (snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) { + fprintf(stderr, "failed to open ALSA sequencer interface\n"); + return 1; + } + + snd_seq_set_client_name(handle, "generator"); + + if ((portid = snd_seq_create_simple_port + (handle, "generator", + SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, 0)) < 0) { + fprintf(stderr, "failed to create ALSA sequencer port\n"); + return 1; + } + + if ((queue = snd_seq_alloc_queue(handle)) < 0) { + fprintf(stderr, "failed to create ALSA sequencer queue\n"); + return 1; + } +/* + snd_seq_queue_timer_alloca(&timer); + snd_seq_get_queue_timer(handle, queue, timer); + snd_timer_id_alloca(&timerid); + snd_timer_id_set_class(timerid, SND_TIMER_CLASS_PCM); + snd_timer_id_set_sclass(timerid, SND_TIMER_SCLASS_NONE); + snd_timer_id_set_card(timerid, 0); + snd_timer_id_set_device(timerid, 0); + snd_timer_id_set_subdevice(timerid, 0); + snd_seq_queue_timer_set_id(timer, timerid); + snd_seq_set_queue_timer(handle, queue, timer); +*/ + snd_seq_start_queue(handle, queue, 0); + snd_seq_drain_output(handle); + + gettimeofday(&starttv, 0); + prevdiff.tv_sec = 0; + prevdiff.tv_usec = 0; + + while (countdown != 0) { + + snd_seq_queue_status_t *status; + const snd_seq_real_time_t *rtime; + struct timeval tv, diff, diffdiff; + struct timespec ts; + + snd_seq_queue_status_alloca(&status); + + snd_seq_get_queue_status(handle, queue, status); + rtime = snd_seq_queue_status_get_real_time(status); + + gettimeofday(&tv, 0); + + tv.tv_sec -= starttv.tv_sec; + tv.tv_usec -= starttv.tv_usec; + normalize(&tv); + + diff.tv_sec = tv.tv_sec - rtime->tv_sec; + diff.tv_usec = tv.tv_usec - rtime->tv_nsec / 1000; + normalize(&diff); + + diffdiff.tv_sec = diff.tv_sec - prevdiff.tv_sec; + diffdiff.tv_usec = diff.tv_usec - prevdiff.tv_usec; + normalize(&diffdiff); + prevdiff = diff; + + fprintf(stderr, " real time: %12ld sec %8ld usec\nqueue time: %12ld sec %8ld usec\n diff: %12ld sec %8ld usec\n diffdiff: %12ld sec %8ld usec\n", + tv.tv_sec, tv.tv_usec, + (long)rtime->tv_sec, (long)rtime->tv_nsec / 1000, + diff.tv_sec, diff.tv_usec, + (long)diffdiff.tv_sec, (long)diffdiff.tv_usec); + + if (diffdiff.tv_usec > 5000 || + diffdiff.tv_usec < -5000) { + fprintf(stderr, "oops! queue slipped\n"); + if (tv.tv_sec < 5) { + fprintf(stderr, "(ignoring in first few seconds)\n"); + } else { + countdown = 2; + } + } else { + if (countdown > 0) --countdown; + } + + fprintf(stderr, "\n"); +// sleep(1); + ts.tv_sec = 0; + ts.tv_nsec = 500000000; + nanosleep(&ts, 0); + } + return EXIT_SUCCESS; +} + diff --git a/test/rawmidi.c b/test/rawmidi.c new file mode 100644 index 0000000..67f585b --- /dev/null +++ b/test/rawmidi.c @@ -0,0 +1,241 @@ +#include +#include +#include +#include "../include/asoundlib.h" +#include + +static void usage(void) +{ + fprintf(stderr, "usage: rawmidi [options]\n"); + fprintf(stderr, " options:\n"); + fprintf(stderr, " -v: verbose mode\n"); + fprintf(stderr, " -i device-id : test ALSA input device\n"); + fprintf(stderr, " -o device-id : test ALSA output device\n"); + fprintf(stderr, " -I node : test input node\n"); + fprintf(stderr, " -O node : test output node\n"); + fprintf(stderr, " -t: test midi thru\n"); + fprintf(stderr, " example:\n"); + fprintf(stderr, " rawmidi -i hw:0,0 -O /dev/midi1\n"); + fprintf(stderr, " tests input for card 0, device 0, using snd_rawmidi API\n"); + fprintf(stderr, " and /dev/midi1 using file descriptors\n"); +} + +int stop=0; + +void sighandler(int dum) +{ + stop=1; +} + +int main(int argc,char** argv) +{ + int i; + int err; + int thru=0; + int verbose = 0; + char *device_in = NULL; + char *device_out = NULL; + char *node_in = NULL; + char *node_out = NULL; + + int fd_in = -1,fd_out = -1; + snd_rawmidi_t *handle_in = 0,*handle_out = 0; + + if (argc==1) { + usage(); + exit(0); + } + + for (i = 1 ; i>> Type = %d, flags = 0x%x", ev->type, ev->flags); + switch (ev->flags & SND_SEQ_TIME_STAMP_MASK) { + case SND_SEQ_TIME_STAMP_TICK: + printf(", time = %d ticks", + ev->time.tick); + break; + case SND_SEQ_TIME_STAMP_REAL: + printf(", time = %d.%09d", + (int)ev->time.time.tv_sec, + (int)ev->time.time.tv_nsec); + break; + } + printf("\n%sSource = %d.%d, dest = %d.%d, queue = %d\n", + space, + ev->source.client, + ev->source.port, + ev->dest.client, + ev->dest.port, + ev->queue); + + if (event_names[ev->type]) + printf("%sEvent = %s", space, event_names[ev->type]); + else + printf("%sEvent = Reserved %d\n", space, ev->type); + /* decode the actual event data... */ + switch (ev->type) { + case SND_SEQ_EVENT_NOTE: + printf("; ch=%d, note=%d, velocity=%d, off_velocity=%d, duration=%d\n", + ev->data.note.channel, + ev->data.note.note, + ev->data.note.velocity, + ev->data.note.off_velocity, + ev->data.note.duration); + break; + + case SND_SEQ_EVENT_NOTEON: + case SND_SEQ_EVENT_NOTEOFF: + case SND_SEQ_EVENT_KEYPRESS: + printf("; ch=%d, note=%d, velocity=%d\n", + ev->data.note.channel, + ev->data.note.note, + ev->data.note.velocity); + break; + + case SND_SEQ_EVENT_CONTROLLER: + printf("; ch=%d, param=%i, value=%i\n", + ev->data.control.channel, + ev->data.control.param, + ev->data.control.value); + break; + + case SND_SEQ_EVENT_PGMCHANGE: + printf("; ch=%d, program=%i\n", + ev->data.control.channel, + ev->data.control.value); + break; + + case SND_SEQ_EVENT_CHANPRESS: + case SND_SEQ_EVENT_PITCHBEND: + printf("; ch=%d, value=%i\n", + ev->data.control.channel, + ev->data.control.value); + break; + + case SND_SEQ_EVENT_SYSEX: + { + unsigned char *sysex = (unsigned char *) ev + sizeof(snd_seq_event_t); + unsigned int c; + + printf("; len=%d [", ev->data.ext.len); + + for (c = 0; c < ev->data.ext.len; c++) { + printf("%02x%s", sysex[c], c < ev->data.ext.len - 1 ? ":" : ""); + } + printf("]\n"); + } + break; + + case SND_SEQ_EVENT_QFRAME: + printf("; frame=0x%02x\n", ev->data.control.value); + break; + + case SND_SEQ_EVENT_CLOCK: + case SND_SEQ_EVENT_START: + case SND_SEQ_EVENT_CONTINUE: + case SND_SEQ_EVENT_STOP: + printf("; queue = %i\n", ev->data.queue.queue); + break; + + case SND_SEQ_EVENT_SENSING: + printf("\n"); + break; + + case SND_SEQ_EVENT_ECHO: + { + int i; + + printf("; "); + for (i = 0; i < 8; i++) { + printf("%02i%s", ev->data.raw8.d[i], i < 7 ? ":" : "\n"); + } + } + break; + + case SND_SEQ_EVENT_CLIENT_START: + case SND_SEQ_EVENT_CLIENT_EXIT: + case SND_SEQ_EVENT_CLIENT_CHANGE: + printf("; client=%i\n", ev->data.addr.client); + break; + + case SND_SEQ_EVENT_PORT_START: + case SND_SEQ_EVENT_PORT_EXIT: + case SND_SEQ_EVENT_PORT_CHANGE: + printf("; client=%i, port = %i\n", ev->data.addr.client, ev->data.addr.port); + break; + + case SND_SEQ_EVENT_PORT_SUBSCRIBED: + case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: + printf("; %i:%i -> %i:%i\n", + ev->data.connect.sender.client, ev->data.connect.sender.port, + ev->data.connect.dest.client, ev->data.connect.dest.port); + break; + + default: + printf("; not implemented\n"); + } + + + switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) { + case SND_SEQ_EVENT_LENGTH_FIXED: + return sizeof(snd_seq_event_t); + + case SND_SEQ_EVENT_LENGTH_VARIABLE: + return sizeof(snd_seq_event_t) + ev->data.ext.len; + } + + return 0; +} + +void event_decoder_start_timer(snd_seq_t *handle, int queue, + int client ATTRIBUTE_UNUSED, + int port ATTRIBUTE_UNUSED) +{ + int err; + + if ((err = snd_seq_start_queue(handle, queue, NULL))<0) + fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err)); + while (snd_seq_drain_output(handle)>0) + sleep(1); +} + +void event_decoder(snd_seq_t *handle, int argc, char *argv[]) +{ + snd_seq_event_t *ev; + snd_seq_port_info_t *pinfo; + snd_seq_port_subscribe_t *sub; + snd_seq_addr_t addr; + int client, port, queue, max, err, v1, v2; + char *ptr; + struct pollfd *pfds; + + if ((client = snd_seq_client_id(handle))<0) { + fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client)); + return; + } + printf("Client ID = %i\n", client); + if ((queue = snd_seq_alloc_queue(handle))<0) { + fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue)); + return; + } + printf("Queue ID = %i\n", queue); + if ((err = snd_seq_nonblock(handle, 1))<0) + fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err)); + snd_seq_port_info_alloca(&pinfo); + snd_seq_port_info_set_name(pinfo, "Input"); + snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC); + snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE); + if ((err = snd_seq_create_port(handle, pinfo)) < 0) { + fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err)); + return; + } + port = snd_seq_port_info_get_port(pinfo); + event_decoder_start_timer(handle, queue, client, port); + + snd_seq_port_subscribe_alloca(&sub); + addr.client = SND_SEQ_CLIENT_SYSTEM; + addr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; + snd_seq_port_subscribe_set_sender(sub, &addr); + addr.client = client; + addr.port = port; + snd_seq_port_subscribe_set_dest(sub, &addr); + snd_seq_port_subscribe_set_queue(sub, queue); + snd_seq_port_subscribe_set_time_update(sub, 1); + snd_seq_port_subscribe_set_time_real(sub, 1); + if ((err = snd_seq_subscribe_port(handle, sub))<0) { + fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err)); + return; + } + + addr.client = SND_SEQ_CLIENT_SYSTEM; + addr.port = SND_SEQ_PORT_SYSTEM_TIMER; + snd_seq_port_subscribe_set_sender(sub, &addr); + if ((err = snd_seq_subscribe_port(handle, sub))<0) { + fprintf(stderr, "Cannot subscribe timer port: %s\n", snd_strerror(err)); + return; + } + + for (max = 0; max < argc; max++) { + ptr = argv[max]; + if (!ptr) + continue; + snd_seq_port_subscribe_set_time_real(sub, 0); + if (tolower(*ptr) == 'r') { + snd_seq_port_subscribe_set_time_real(sub, 1); + ptr++; + } + if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) { + fprintf(stderr, "Wrong argument '%s'...\n", argv[max]); + return; + } + addr.client = v1; + addr.port = v2; + snd_seq_port_subscribe_set_sender(sub, &addr); + if ((err = snd_seq_subscribe_port(handle, sub))<0) { + fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err)); + return; + } + } + + max = snd_seq_poll_descriptors_count(handle, POLLIN); + pfds = alloca(sizeof(*pfds) * max); + while (1) { + snd_seq_poll_descriptors(handle, pfds, max, POLLIN); + if (poll(pfds, max, -1) < 0) + break; + do { + if ((err = snd_seq_event_input(handle, &ev))<0) + break; + if (!ev) + continue; + decode_event(ev); + snd_seq_free_event(ev); + } while (err > 0); + } +} diff --git a/test/seq-sender.c b/test/seq-sender.c new file mode 100644 index 0000000..5d8ac92 --- /dev/null +++ b/test/seq-sender.c @@ -0,0 +1,272 @@ + +#ifdef USE_PCM // XXX not yet +/* + * PCM timer layer + */ + +int pcard = 0; +int pdevice = 0; +int period_size = 1024; + +void set_hwparams(snd_pcm_t *phandle) +{ + int err; + snd_pcm_hw_params_t *params; + + err = snd_output_stdio_attach(&log, stderr, 0); + if (err < 0) { + fprintf(stderr, "cannot attach output stdio\n"); + exit(0); + } + + snd_pcm_hw_params_alloca(¶ms); + err = snd_pcm_hw_params_any(phandle, params); + if (err < 0) { + fprintf(stderr, "Broken configuration for this PCM: no configurations available\n"); + exit(0); + } + + err = snd_pcm_hw_params_set_access(phandle, params, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + fprintf(stderr, "Access type not available\n"); + exit(0); + } + err = snd_pcm_hw_params_set_format(phandle, params, SND_PCM_FORMAT_S16_LE); + if (err < 0) { + fprintf(stderr, "cannot set format\n"); + exit(0); + } + err = snd_pcm_hw_params_set_channels(phandle, params, 2); + if (err < 0) { + fprintf(stderr, "cannot set channels 2\n"); + exit(0); + } + err = snd_pcm_hw_params_set_rate_near(phandle, params, 44100, 0); + if (err < 0) { + fprintf(stderr, "cannot set rate\n"); + exit(0); + } + err = snd_pcm_hw_params_set_period_size_near(phandle, params, period_size); + if (err < 0) { + fprintf(stderr, "cannot set period size\n"); + exit(0); + } + err = snd_pcm_hw_params(phandle, params); + if (err < 0) { + fprintf(stderr, "Unable to install hw params:\n"); + exit(0); + } + snd_pcm_hw_params_dump(params, log); +} + +#endif +/* + * Simple event sender + */ + +void event_sender_start_timer(snd_seq_t *handle, + int client ATTRIBUTE_UNUSED, + int queue, + snd_pcm_t *phandle ATTRIBUTE_UNUSED) +{ + int err; + +#ifdef USE_PCM + if (phandle) { + snd_pcm_playback_info_t pinfo; + snd_seq_queue_timer_t qtimer; + + if ((err = snd_pcm_playback_info(phandle, &pinfo)) < 0) { + fprintf(stderr, "Playback info error: %s\n", snd_strerror(err)); + exit(0); + } + bzero(&qtimer, sizeof(qtimer)); + qtimer.type = SND_SEQ_TIMER_MASTER; + /* note: last bit from the subdevices specifies playback */ + /* or capture direction for the timer specification */ + qtimer.number = SND_TIMER_PCM(pcard, pdevice, pinfo.subdevice << 1); + if ((err = snd_seq_set_queue_timer(handle, queue, &qtimer)) < 0) { + fprintf(stderr, "Sequencer PCM timer setup failed: %s\n", snd_strerror(err)); + exit(0); + } + } +#endif + if ((err = snd_seq_start_queue(handle, queue, NULL))<0) + fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err)); + snd_seq_drain_output(handle); +} + +void event_sender_filter(snd_seq_t *handle) +{ + int err; + + if ((err = snd_seq_set_client_event_filter(handle, SND_SEQ_EVENT_ECHO)) < 0) { + fprintf(stderr, "Unable to set client info: %s\n", snd_strerror(err)); + return; + } +} + +void send_event(snd_seq_t *handle, int queue, int client, int port, + snd_seq_addr_t *dest, int *time) +{ + int err; + snd_seq_event_t ev; + + bzero(&ev, sizeof(ev)); + ev.queue = queue; + ev.source.client = ev.dest.client = client; + ev.source.port = ev.dest.port = port; + ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS; + ev.time.time.tv_sec = *time; (*time)++; + ev.type = SND_SEQ_EVENT_ECHO; + if ((err = snd_seq_event_output(handle, &ev))<0) + fprintf(stderr, "Event output error: %s\n", snd_strerror(err)); + ev.dest = *dest; + ev.type = SND_SEQ_EVENT_PGMCHANGE; + ev.data.control.channel = 0; + ev.data.control.value = 16; + if ((err = snd_seq_event_output(handle, &ev))<0) + fprintf(stderr, "Event output error: %s\n", snd_strerror(err)); + ev.type = SND_SEQ_EVENT_NOTE; + ev.data.note.channel = 0; + ev.data.note.note = 64 + (queue*2); + ev.data.note.velocity = 127; + ev.data.note.off_velocity = 127; + ev.data.note.duration = 500; /* 0.5sec */ + if ((err = snd_seq_event_output(handle, &ev))<0) + fprintf(stderr, "Event output error: %s\n", snd_strerror(err)); + if ((err = snd_seq_drain_output(handle))<0) + fprintf(stderr, "Event drain error: %s\n", snd_strerror(err)); +} + +void event_sender(snd_seq_t *handle, int argc, char *argv[]) +{ + snd_seq_event_t *ev; + snd_seq_port_info_t *pinfo; + snd_seq_port_subscribe_t *sub; + snd_seq_addr_t addr; + struct pollfd *pfds; + int client, port, queue, max, err, v1, v2, time = 0, pcm_flag = 0; + char *ptr; + snd_pcm_t *phandle = NULL; + + if (argc < 1) { + fprintf(stderr, "Invalid destination...\n"); + return; + } + + if ((client = snd_seq_client_id(handle))<0) { + fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client)); + return; + } + printf("Client ID = %i\n", client); + if ((queue = snd_seq_alloc_queue(handle))<0) { + fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue)); + return; + } + printf("Queue ID = %i\n", queue); + event_sender_filter(handle); + if ((err = snd_seq_nonblock(handle, 1))<0) + fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err)); + + snd_seq_port_info_alloca(&pinfo); + snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ); + snd_seq_port_info_set_name(pinfo, "Output"); + if ((err = snd_seq_create_port(handle, pinfo)) < 0) { + fprintf(stderr, "Cannot create output port: %s\n", snd_strerror(err)); + return; + } + port = snd_seq_port_info_get_port(pinfo); + + snd_seq_port_subscribe_alloca(&sub); + addr.client = client; + addr.port = port; + snd_seq_port_subscribe_set_sender(sub, &addr); + + for (max = 0; max < argc; max++) { + ptr = argv[max]; + if (!ptr) + continue; + if (!strcmp(ptr, "pcm")) { + pcm_flag = 1; + continue; + } + if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) { + fprintf(stderr, "Wrong argument '%s'...\n", argv[max]); + return; + } + addr.client = v1; + addr.port = v2; + snd_seq_port_subscribe_set_dest(sub, &addr); + if ((err = snd_seq_subscribe_port(handle, sub))<0) { + fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err)); + return; + } + } + + printf("Destination client = %i, port = %i\n", addr.client, addr.port); + +#ifdef USE_PCM + if (pcm_flag) { + if ((err = snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + fprintf(stderr, "Playback open error: %s\n", snd_strerror(err)); + exit(0); + } + set_hwparams(phandle); + pbuf = calloc(1, period_size * 4); + if (pbuf == NULL) { + fprintf(stderr, "No enough memory...\n"); + exit(0); + } + } +#endif + event_sender_start_timer(handle, client, queue, phandle); + + /* send the first event */ + send_event(handle, queue, client, port, &addr, &time); +#ifdef USE_PCM + if (phandle) + max += snd_pcm_poll_descriptors_count(phandle); +#endif + pfds = alloca(sizeof(*pfds) * max); + while (1) { + int nseqs = snd_seq_poll_descriptors_count(handle, POLLOUT|POLLIN); + if (snd_seq_event_output_pending(handle)) + snd_seq_poll_descriptors(handle, pfds, nseqs, POLLOUT|POLLIN); + else + snd_seq_poll_descriptors(handle, pfds, nseqs, POLLIN); + max = nseqs; +#ifdef USE_PCM + if (phandle) { + int pmax = snd_pcm_poll_descriptors_count(phandle); + snd_seq_poll_descriptors(phandle, pfds + max, pmax); + max += pmax; + } +#endif + if (poll(pfds, max, -1) < 0) + break; +#ifdef USE_PCM + if (phandle && (pfds[nseqs].revents & POLLOUT)) { + if (snd_pcm_writei(phandle, pbuf, period_size) != period_size) { + fprintf(stderr, "Playback write error!!\n"); + exit(0); + } + } +#endif + if (pfds[0].revents & POLLOUT) + snd_seq_drain_output(handle); + if (pfds[0].revents & POLLIN) { + do { + if ((err = snd_seq_event_input(handle, &ev))<0) + break; + if (!ev) + continue; + if (ev->type == SND_SEQ_EVENT_ECHO) + send_event(handle, queue, client, port, &addr, &time); + decode_event(ev); + snd_seq_free_event(ev); + } while (err > 0); + } + } +} diff --git a/test/seq.c b/test/seq.c new file mode 100644 index 0000000..34b000f --- /dev/null +++ b/test/seq.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include "../include/asoundlib.h" + +#include "seq-decoder.c" +#include "seq-sender.c" + +#define SEQ_VERSION "0.0.1" + +#define HELPID_HELP 1000 +#define HELPID_DEBUG 1001 +#define HELPID_VERBOSE 1002 +#define HELPID_VERSION 1003 + +int max_clients; +int max_ports; +int max_queues; +int debug = 0; +int verbose = 0; + +void set_name(snd_seq_t *handle) +{ + int err; + char name[64]; + + sprintf(name, "SeqUtil - %i", getpid()); + if ((err = snd_seq_set_client_name(handle, name)) < 0) { + fprintf(stderr, "Set client info error: %s\n", snd_strerror(err)); + exit(0); + } +} + +void system_info(snd_seq_t *handle) +{ + int err; + snd_seq_system_info_t *sysinfo; + + snd_seq_system_info_alloca(&sysinfo); + if ((err = snd_seq_system_info(handle, sysinfo))<0) { + fprintf(stderr, "System info error: %s\n", snd_strerror(err)); + exit(0); + } + max_clients = snd_seq_system_info_get_clients(sysinfo); + max_ports = snd_seq_system_info_get_ports(sysinfo); + max_queues = snd_seq_system_info_get_ports(sysinfo); +} + +void show_system_info(snd_seq_t *handle ATTRIBUTE_UNUSED) +{ + printf("System info\n"); + printf(" Max queues : %i\n", max_queues); + printf(" Max clients : %i\n", max_clients); + printf(" Max ports : %i\n", max_ports); +} + +void show_queue_status(snd_seq_t *handle, int queue) +{ + int err, idx, min, max; + snd_seq_queue_status_t *status; + + snd_seq_queue_status_alloca(&status); + min = queue < 0 ? 0 : queue; + max = queue < 0 ? max_queues : queue + 1; + for (idx = min; idx < max; idx++) { + if ((err = snd_seq_get_queue_status(handle, idx, status))<0) { + if (err == -ENOENT) + continue; + fprintf(stderr, "Client %i info error: %s\n", idx, snd_strerror(err)); + exit(0); + } + printf("Queue %i info\n", snd_seq_queue_status_get_queue(status)); + printf(" Tick : %u\n", snd_seq_queue_status_get_tick_time(status)); + printf(" Realtime : %i.%i\n", + snd_seq_queue_status_get_real_time(status)->tv_sec, + snd_seq_queue_status_get_real_time(status)->tv_nsec); + printf(" Flags : 0x%x\n", snd_seq_queue_status_get_status(status)); + } +} + +void show_port_info(snd_seq_t *handle, int client, int port) +{ + int err, idx, min, max; + snd_seq_port_info_t *info; + + snd_seq_port_info_alloca(&info); + min = port < 0 ? 0 : port; + max = port < 0 ? max_ports : port + 1; + for (idx = min; idx < max; idx++) { + if ((err = snd_seq_get_any_port_info(handle, client, idx, info))<0) { + if (err == -ENOENT) + continue; + fprintf(stderr, "Port %i/%i info error: %s\n", client, idx, snd_strerror(err)); + exit(0); + } + printf(" Port %i info\n", idx); + printf(" Client : %i\n", snd_seq_port_info_get_client(info)); + printf(" Port : %i\n", snd_seq_port_info_get_port(info)); + printf(" Name : %s\n", snd_seq_port_info_get_name(info)); + printf(" Capability : 0x%x\n", snd_seq_port_info_get_capability(info)); + printf(" Type : 0x%x\n", snd_seq_port_info_get_type(info)); + //printf(" Midi channels : %i\n", info.midi_channels); + //printf(" Synth voices : %i\n", info.synth_voices); + printf(" Output subs : %i\n", snd_seq_port_info_get_write_use(info)); + printf(" Input subs : %i\n", snd_seq_port_info_get_read_use(info)); + } +} + +void show_client_info(snd_seq_t *handle, int client) +{ + int err, idx, min, max; + snd_seq_client_info_t *info; + + snd_seq_client_info_alloca(&info); + min = client < 0 ? 0 : client; + max = client < 0 ? max_clients : client + 1; + for (idx = min; idx < max; idx++) { + if ((err = snd_seq_get_any_client_info(handle, idx, info))<0) { + if (err == -ENOENT) + continue; + fprintf(stderr, "Client %i info error: %s\n", idx, snd_strerror(err)); + exit(0); + } + printf("Client %i info\n", idx); + if (verbose) + printf(" Client : %i\n", snd_seq_client_info_get_client(info)); + printf(" Type : %s\n", snd_seq_client_info_get_type(info) == SND_SEQ_KERNEL_CLIENT ? "kernel" : "user"); + printf(" Name : %s\n", snd_seq_client_info_get_name(info)); + } +} + +static void help(void) +{ + printf("Usage: seq command\n"); + printf("\nAvailable options:\n"); + printf(" -h,--help this help\n"); + printf(" -d,--debug debug mode\n"); + printf(" -v,--verbose verbose mode\n"); + printf(" -V,--version print version of this program\n"); + printf("\nAvailable commands:\n"); + printf(" system show basic sequencer info\n"); + printf(" queue [#] show all queues or specified queue\n"); + printf(" client [#] show all clients or specified client\n"); + printf(" port [#] show all ports or specified port for specified client\n"); + printf(" decoder event decoder\n"); + printf(" sender [] ... event sender\n"); +} + +int main(int argc, char *argv[]) +{ + int morehelp, err, arg, arg1; + snd_seq_t *handle; + static struct option long_option[] = + { + {"help", 0, NULL, HELPID_HELP}, + {"debug", 0, NULL, HELPID_DEBUG}, + {"verbose", 0, NULL, HELPID_VERBOSE}, + {"version", 0, NULL, HELPID_VERSION}, + {NULL, 0, NULL, 0}, + }; + + morehelp = 0; + + while (1) { + int c; + + if ((c = getopt_long(argc, argv, "hdvV", long_option, NULL)) < 0) + break; + switch (c) { + case 'h': + case HELPID_HELP: + morehelp++; + break; + case 'd': + case HELPID_DEBUG: + debug = 1; + break; + case 'v': + case HELPID_VERBOSE: + verbose = 1; + break; + case 'V': + case HELPID_VERSION: + printf("alsactl version " SEQ_VERSION "\n"); + return 1; + default: + fprintf(stderr, "\07Invalid switch or option needs an argument.\n"); + morehelp++; + } + } + if (morehelp) { + help(); + return 1; + } + if (argc - optind <= 0) { + fprintf(stderr, "seq: Specify command...\n"); + return 0; + } + if ((err = snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0))<0) { + fprintf(stderr, "Open error: %s\n", snd_strerror(err)); + exit(0); + } + set_name(handle); + system_info(handle); + + if (!strcmp(argv[optind], "system")) { + show_system_info(handle); + } else if (!strcmp(argv[optind], "queue")) { + arg = argc - optind > 1 ? atoi(argv[optind + 1]) : -1; + show_queue_status(handle, arg); + } else if (!strcmp(argv[optind], "client")) { + arg = argc - optind > 1 ? atoi(argv[optind + 1]) : -1; + show_client_info(handle, arg); + } else if (!strcmp(argv[optind], "port")) { + arg = argc - optind > 1 ? atoi(argv[optind + 1]) : -1; + if (arg < 0) { + fprintf(stderr, "Specify port...\n"); + exit(0); + } + arg1 = argc - optind > 2 ? atoi(argv[optind + 2]) : -1; + show_port_info(handle, arg, arg1); + } else if (!strcmp(argv[optind], "decoder")) { + event_decoder(handle, argc - optind - 1, argv + optind + 1); + } else if (!strcmp(argv[optind], "sender")) { + event_sender(handle, argc - optind - 1, argv + optind + 1); + } else { + help(); + } + exit(1); +} diff --git a/test/timer.c b/test/timer.c new file mode 100644 index 0000000..b05eb2f --- /dev/null +++ b/test/timer.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include "../include/asoundlib.h" + +void show_status(void *handle) +{ + int err; + snd_timer_status_t *status; + + snd_timer_status_alloca(&status); + if ((err = snd_timer_status(handle, status)) < 0) { + fprintf(stderr, "timer status %i (%s)\n", err, snd_strerror(err)); + return; + } + printf("STATUS:\n"); + printf(" resolution = %li\n", snd_timer_status_get_resolution(status)); + printf(" lost = %li\n", snd_timer_status_get_lost(status)); + printf(" overrun = %li\n", snd_timer_status_get_overrun(status)); + printf(" queue = %li\n", snd_timer_status_get_queue(status)); +} + +void read_loop(void *handle, int master_ticks, int timeout) +{ + int count, err; + struct pollfd *fds; + snd_timer_read_t tr; + + count = snd_timer_poll_descriptors_count(handle); + fds = calloc(count, sizeof(struct pollfd)); + if (fds == NULL) { + fprintf(stderr, "malloc error\n"); + exit(EXIT_FAILURE); + } + while (master_ticks-- > 0) { + if ((err = snd_timer_poll_descriptors(handle, fds, count)) < 0) { + fprintf(stderr, "snd_timer_poll_descriptors error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + if ((err = poll(fds, count, timeout)) < 0) { + fprintf(stderr, "poll error %i (%s)\n", err, strerror(err)); + exit(EXIT_FAILURE); + } + if (err == 0) { + fprintf(stderr, "timer time out!!\n"); + exit(EXIT_FAILURE); + } + while (snd_timer_read(handle, &tr, sizeof(tr)) == sizeof(tr)) { + printf("TIMER: resolution = %uns, ticks = %u\n", + tr.resolution, tr.ticks); + } + } + free(fds); +} + +static void async_callback(snd_async_handler_t *ahandler) +{ + snd_timer_t *handle = snd_async_handler_get_timer(ahandler); + int *acount = snd_async_handler_get_callback_private(ahandler); + snd_timer_read_t tr; + + while (snd_timer_read(handle, &tr, sizeof(tr)) == sizeof(tr)) { + printf("TIMER: resolution = %uns, ticks = %u\n", + tr.resolution, tr.ticks); + } + (*acount)++; +} + +int main(int argc, char *argv[]) +{ + int idx, err; + int class = SND_TIMER_CLASS_GLOBAL; + int sclass = SND_TIMER_CLASS_NONE; + int card = 0; + int device = SND_TIMER_GLOBAL_SYSTEM; + int subdevice = 0; + int list = 0; + int async = 0; + int acount = 0; + snd_timer_t *handle; + snd_timer_id_t *id; + snd_timer_info_t *info; + snd_timer_params_t *params; + char timername[64]; + snd_async_handler_t *ahandler; + + snd_timer_id_alloca(&id); + snd_timer_info_alloca(&info); + snd_timer_params_alloca(¶ms); + + idx = 1; + while (idx < argc) { + if (!strncmp(argv[idx], "class=", 5)) { + class = atoi(argv[idx]+6); + } else if (!strncmp(argv[idx], "sclass=", 6)) { + sclass = atoi(argv[idx]+7); + } else if (!strncmp(argv[idx], "card=", 5)) { + card = atoi(argv[idx]+5); + } else if (!strncmp(argv[idx], "device=", 7)) { + device = atoi(argv[idx]+7); + } else if (!strncmp(argv[idx], "subdevice=", 10)) { + subdevice = atoi(argv[idx]+10); + } else if (!strcmp(argv[idx], "list")) { + list = 1; + } else if (!strcmp(argv[idx], "async")) { + async = 1; + } + idx++; + } + if (class == SND_TIMER_CLASS_SLAVE && sclass == SND_TIMER_SCLASS_NONE) { + fprintf(stderr, "slave class is not set\n"); + exit(EXIT_FAILURE); + } + if (list) { + snd_timer_query_t *qhandle; + if ((err = snd_timer_query_open(&qhandle, "hw", 0)) < 0) { + fprintf(stderr, "snd_timer_query_open error: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + snd_timer_id_set_class(id, SND_TIMER_CLASS_NONE); + while (1) { + if ((err = snd_timer_query_next_device(qhandle, id)) < 0) { + fprintf(stderr, "timer next device error: %s\n", snd_strerror(err)); + break; + } + if (snd_timer_id_get_class(id) < 0) + break; + printf("Timer device: class %i, sclass %i, card %i, device %i, subdevice %i\n", + snd_timer_id_get_class(id), + snd_timer_id_get_sclass(id), + snd_timer_id_get_card(id), + snd_timer_id_get_device(id), + snd_timer_id_get_subdevice(id)); + } + snd_timer_query_close(qhandle); + exit(EXIT_SUCCESS); + } + sprintf(timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i", class, sclass, card, device, subdevice); + if ((err = snd_timer_open(&handle, timername, SND_TIMER_OPEN_NONBLOCK))<0) { + fprintf(stderr, "timer open %i (%s)\n", err, snd_strerror(err)); + exit(EXIT_FAILURE); + } + printf("Using timer class %i, slave class %i, card %i, device %i, subdevice %i\n", class, sclass, card, device, subdevice); + if ((err = snd_timer_info(handle, info)) < 0) { + fprintf(stderr, "timer info %i (%s)\n", err, snd_strerror(err)); + exit(0); + } + printf("Timer info:\n"); + printf(" slave = %s\n", snd_timer_info_is_slave(info) ? "yes" : "no"); + printf(" card = %i\n", snd_timer_info_get_card(info)); + printf(" id = '%s'\n", snd_timer_info_get_id(info)); + printf(" name = '%s'\n", snd_timer_info_get_name(info)); + printf(" average resolution = %li\n", snd_timer_info_get_resolution(info)); + snd_timer_params_set_auto_start(params, 1); + if (!snd_timer_info_is_slave(info)) { + snd_timer_params_set_ticks(params, (1000000000 / snd_timer_info_get_resolution(info)) / 50); /* 50Hz */ + if (snd_timer_params_get_ticks(params) < 1) + snd_timer_params_set_ticks(params, 1); + printf("Using %li tick(s)\n", snd_timer_params_get_ticks(params)); + } else { + snd_timer_params_set_ticks(params, 1); + } + if ((err = snd_timer_params(handle, params)) < 0) { + fprintf(stderr, "timer params %i (%s)\n", err, snd_strerror(err)); + exit(0); + } + show_status(handle); + if (async) { + err = snd_async_add_timer_handler(&ahandler, handle, async_callback, &acount); + if (err < 0) { + fprintf(stderr, "unable to add async handler %i (%s)\n", err, snd_strerror(err)); + exit(EXIT_FAILURE); + } + } + if ((err = snd_timer_start(handle)) < 0) { + fprintf(stderr, "timer start %i (%s)\n", err, snd_strerror(err)); + exit(EXIT_FAILURE); + } + if (async) { + /* because all other work is done in the signal handler, + suspend the process */ + while (acount < 25) + sleep(1); + snd_timer_stop(handle); + } else { + read_loop(handle, 25, snd_timer_info_is_slave(info) ? 10000 : 25); + } + show_status(handle); + snd_timer_close(handle); + printf("Done\n"); + return EXIT_SUCCESS; +} diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 0000000..ee60f6c --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,13 @@ +if INSTALL_M4 +aclocaldir=$(datadir)/aclocal +aclocal_DATA=alsa.m4 +endif +EXTRA_DIST=alsa.m4 buildrpm alsa.pc.in + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = alsa.pc + +rpm: buildrpm alsa-lib.spec + VERSION=$(VERSION) $(srcdir)/buildrpm + +INCLUDES=-I$(top_srcdir)/include diff --git a/utils/Makefile.in b/utils/Makefile.in new file mode 100644 index 0000000..aea3a02 --- /dev/null +++ b/utils/Makefile.in @@ -0,0 +1,451 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = utils +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/alsa-lib.spec.in $(srcdir)/alsa.pc.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = alsa-lib.spec alsa.pc +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(aclocaldir)" \ + "$(DESTDIR)$(pkgconfigdir)" +DATA = $(aclocal_DATA) $(pkgconfig_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SND_LIB_EXTRAVER = @SND_LIB_EXTRAVER@ +SND_LIB_MAJOR = @SND_LIB_MAJOR@ +SND_LIB_MINOR = @SND_LIB_MINOR@ +SND_LIB_SUBMINOR = @SND_LIB_SUBMINOR@ +SND_LIB_VERSION = @SND_LIB_VERSION@ +STRIP = @STRIP@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@INSTALL_M4_TRUE@aclocaldir = $(datadir)/aclocal +@INSTALL_M4_TRUE@aclocal_DATA = alsa.m4 +EXTRA_DIST = alsa.m4 buildrpm alsa.pc.in +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = alsa.pc +INCLUDES = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign utils/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign utils/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +alsa-lib.spec: $(top_builddir)/config.status $(srcdir)/alsa-lib.spec.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +alsa.pc: $(top_builddir)/config.status $(srcdir)/alsa.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-aclocalDATA: $(aclocal_DATA) + @$(NORMAL_INSTALL) + test -z "$(aclocaldir)" || $(MKDIR_P) "$(DESTDIR)$(aclocaldir)" + @list='$(aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(aclocaldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(aclocaldir)" || exit $$?; \ + done + +uninstall-aclocalDATA: + @$(NORMAL_UNINSTALL) + @list='$(aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(aclocaldir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(aclocaldir)" && rm -f $$files +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(aclocaldir)" "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-aclocalDATA install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-aclocalDATA uninstall-pkgconfigDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-aclocalDATA \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgconfigDATA install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am uninstall uninstall-aclocalDATA uninstall-am \ + uninstall-pkgconfigDATA + + +rpm: buildrpm alsa-lib.spec + VERSION=$(VERSION) $(srcdir)/buildrpm + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/utils/alsa-lib.spec.in b/utils/alsa-lib.spec.in new file mode 100644 index 0000000..021cc75 --- /dev/null +++ b/utils/alsa-lib.spec.in @@ -0,0 +1,75 @@ +%define ver @SND_LIB_VERSION@ +%define rel 1 + +Summary: Advanced Linux Sound Architecture (ALSA) - Library +Name: alsa-lib +Version: %ver +Release: %rel +License: LGPL +Group: System/Libraries +Source: ftp://ftp.alsa-project.org/pub/lib/alsa-lib-%{ver}.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-%{version}-root +URL: http://www.alsa-project.org + +%description + +Advanced Linux Sound Architecture (ALSA) - Library + +%package -n alsa-lib-devel +Summary: ALSA Libraries Development Files +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description -n alsa-lib-devel +Development files for building applications which use the ALSA libraries. + +%changelog +* Sat Feb 22 2003 Ronny V. Vindenes +- split alsa-lib into alsa-lib and alsa-lib-devel +- changed which files are installed (now includes alsa.pc) +- use standard rpm macros for build and install +- changed BuildRoot from /var/tmp to %{_tmppath} + +* Tue Nov 20 2001 Jaroslav Kysela + +- changed BuildRoot from /tmp to /var/tmp +- use the standard RPM macros for prefix and paths +- added DESTDIR for make install + +* Sun Nov 11 2001 Miroslav Benes + +- dangerous command "rpm -rf $RPM_BUILD_ROOT" checks $RPM_BUILD_ROOT variable +- unset key "Docdir" - on some new systems are documentation in /usr/share/doc + +* Mon May 28 1998 Helge Jensen + +- Made SPEC file + +%prep +%setup +%build +%configure +make + +%install +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT +%makeinstall + +%clean +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-, root, root) +%{_bindir}/* +%{_libdir}/*.so.* +%{_datadir}/alsa +%doc doc/*.txt + +%files -n alsa-lib-devel +%defattr(-,root,root) +%{_includedir}/alsa +%{_includedir}/sys/* +%{_libdir}/*.la +%{_libdir}/*.so +%{_datadir}/aclocal/* +%{_libdir}/pkgconfig/* diff --git a/utils/alsa.m4 b/utils/alsa.m4 new file mode 100644 index 0000000..79a24ef --- /dev/null +++ b/utils/alsa.m4 @@ -0,0 +1,141 @@ +dnl Configure Paths for Alsa +dnl Some modifications by Richard Boulton +dnl Christopher Lansdown +dnl Jaroslav Kysela +dnl Last modification: $Id: alsa.m4,v 1.24 2004/09/15 18:48:07 tiwai Exp $ +dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for libasound, and define ALSA_CFLAGS and ALSA_LIBS as appropriate. +dnl enables arguments --with-alsa-prefix= +dnl --with-alsa-enc-prefix= +dnl --disable-alsatest +dnl +dnl For backwards compatibility, if ACTION_IF_NOT_FOUND is not specified, +dnl and the alsa libraries are not found, a fatal AC_MSG_ERROR() will result. +dnl +AC_DEFUN([AM_PATH_ALSA], +[dnl Save the original CFLAGS, LDFLAGS, and LIBS +alsa_save_CFLAGS="$CFLAGS" +alsa_save_LDFLAGS="$LDFLAGS" +alsa_save_LIBS="$LIBS" +alsa_found=yes + +dnl +dnl Get the cflags and libraries for alsa +dnl +AC_ARG_WITH(alsa-prefix, +[ --with-alsa-prefix=PFX Prefix where Alsa library is installed(optional)], +[alsa_prefix="$withval"], [alsa_prefix=""]) + +AC_ARG_WITH(alsa-inc-prefix, +[ --with-alsa-inc-prefix=PFX Prefix where include libraries are (optional)], +[alsa_inc_prefix="$withval"], [alsa_inc_prefix=""]) + +dnl FIXME: this is not yet implemented +AC_ARG_ENABLE(alsatest, +[ --disable-alsatest Do not try to compile and run a test Alsa program], +[enable_alsatest="$enableval"], +[enable_alsatest=yes]) + +dnl Add any special include directories +AC_MSG_CHECKING(for ALSA CFLAGS) +if test "$alsa_inc_prefix" != "" ; then + ALSA_CFLAGS="$ALSA_CFLAGS -I$alsa_inc_prefix" + CFLAGS="$CFLAGS -I$alsa_inc_prefix" +fi +AC_MSG_RESULT($ALSA_CFLAGS) + +dnl add any special lib dirs +AC_MSG_CHECKING(for ALSA LDFLAGS) +if test "$alsa_prefix" != "" ; then + ALSA_LIBS="$ALSA_LIBS -L$alsa_prefix" + LDFLAGS="$LDFLAGS $ALSA_LIBS" +fi + +dnl add the alsa library +ALSA_LIBS="$ALSA_LIBS -lasound -lm -ldl -lpthread" +LIBS="$ALSA_LIBS $LIBS" +AC_MSG_RESULT($ALSA_LIBS) + +dnl Check for a working version of libasound that is of the right version. +min_alsa_version=ifelse([$1], ,0.1.1,$1) +AC_MSG_CHECKING(for libasound headers version >= $min_alsa_version) +no_alsa="" + alsa_min_major_version=`echo $min_alsa_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + alsa_min_minor_version=`echo $min_alsa_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + alsa_min_micro_version=`echo $min_alsa_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + +AC_LANG_SAVE +AC_LANG_C +AC_TRY_COMPILE([ +#include +], [ +/* ensure backward compatibility */ +#if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR) +#define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR +#endif +#if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR) +#define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR +#endif +#if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR) +#define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR +#endif + +# if(SND_LIB_MAJOR > $alsa_min_major_version) + exit(0); +# else +# if(SND_LIB_MAJOR < $alsa_min_major_version) +# error not present +# endif + +# if(SND_LIB_MINOR > $alsa_min_minor_version) + exit(0); +# else +# if(SND_LIB_MINOR < $alsa_min_minor_version) +# error not present +# endif + +# if(SND_LIB_SUBMINOR < $alsa_min_micro_version) +# error not present +# endif +# endif +# endif +exit(0); +], + [AC_MSG_RESULT(found.)], + [AC_MSG_RESULT(not present.) + ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libasound not found.)]) + alsa_found=no] +) +AC_LANG_RESTORE + +dnl Now that we know that we have the right version, let's see if we have the library and not just the headers. +if test "x$enable_alsatest" = "xyes"; then +AC_CHECK_LIB([asound], [snd_ctl_open],, + [ifelse([$3], , [AC_MSG_ERROR(No linkable libasound was found.)]) + alsa_found=no] +) +fi + +if test "x$alsa_found" = "xyes" ; then + ifelse([$2], , :, [$2]) + LIBS=`echo $LIBS | sed 's/-lasound//g'` + LIBS=`echo $LIBS | sed 's/ //'` + LIBS="-lasound $LIBS" +fi +if test "x$alsa_found" = "xno" ; then + ifelse([$3], , :, [$3]) + CFLAGS="$alsa_save_CFLAGS" + LDFLAGS="$alsa_save_LDFLAGS" + LIBS="$alsa_save_LIBS" + ALSA_CFLAGS="" + ALSA_LIBS="" +fi + +dnl That should be it. Now just export out symbols: +AC_SUBST(ALSA_CFLAGS) +AC_SUBST(ALSA_LIBS) +]) + diff --git a/utils/alsa.pc.in b/utils/alsa.pc.in new file mode 100644 index 0000000..8de9859 --- /dev/null +++ b/utils/alsa.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: alsa +Description: Advanced Linux Sound Architecture (ALSA) - Library +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lasound +Libs.private: @ALSA_DEPLIBS@ +# -I${includedir}/alsa below is just for backward compatibility +# (it was set so mistakely in the older version) +Cflags: -I${includedir} -I${includedir}/alsa diff --git a/utils/buildrpm b/utils/buildrpm new file mode 100755 index 0000000..e6f44ba --- /dev/null +++ b/utils/buildrpm @@ -0,0 +1,46 @@ +#!/bin/bash + +source=. +version=`cat $source/../version` +package=$source/../../alsa-lib-$version.tar.bz2 +packagedir=/usr/src/redhat +xrpmbuild=rpm +rpmbuild --usage 2> /dev/null > /dev/null && xrpmbuild=rpmbuild + +if [ -d /usr/src/packages ]; then + packagedir=/usr/src/packages +fi + +make -C .. clean +make -C .. dist + +if [ ! -r $package ]; then + package=$source/../alsa-lib-$version.tar.bz2 + if [ ! -r $package ]; then + echo "Error: wrong package: $package" + exit 1 + fi +fi + +cp -fv $package ${packagedir}/SOURCES + +if [ ! -r $source/buildrpm ]; then + echo "Error: invalid directory: $source" + exit 1 +fi + +if [ ! -d ${packagedir} ]; then + echo "Error: ${packagedir} directory not found" + exit 1 +fi + +if [ ! -r $source/alsa-lib.spec ]; then + cd $source/.. + ./configure + cd utils +fi + +cp -fv $source/alsa-lib.spec ${packagedir}/SPECS +cd ${packagedir}/SPECS +$xrpmbuild -ba alsa-lib.spec +cd ${packagedir} diff --git a/version b/version new file mode 100644 index 0000000..62c9266 --- /dev/null +++ b/version @@ -0,0 +1 @@ +1.0.24.1 -- 2.7.4