From 4a16fb5865b69c4020f33768a3a8630ac0dc423d Mon Sep 17 00:00:00 2001 From: Packit Date: Aug 31 2020 13:22:25 +0000 Subject: alsa-lib-1.2.1.2 base --- diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..ae23fcf --- /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. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..a2427e0 --- /dev/null +++ b/INSTALL @@ -0,0 +1,133 @@ + + ALSA library installation + ========================= + +Installation from tarball +------------------------- + +For installation you can use these commands: + + ./configure + make install + + +Compilation from Git-sources +--------------------------- + +Requirements: + * automake + * libtool + +To compile alsa-lib from source: + + ./gitcompile + +If you do not want to use the supplied gitcompile-script, you can +compile alsa-lib manually by using these steps: + + libtoolize --force --copy --automake + aclocal + autoheader + automake --foreign --copy --add-missing + autoconf + ./configure + make + + +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 --host=arm-linux + +You can omit setting 'CC' variable and cross-compiler will be guessed too. + +So simplest version would be: + +./configure --host=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. + +Thread-safety option +-------------------- + +As default, major PCM functions of alsa-lib are built to be +thread-safe with pthread mutex (while this wasn't present in the +versions earlier than 1.1.2). If you want to build without this +thread-safety support but reduce the overhead, pass +--disable-thread-safety configure option. + +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..c484d4d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,40 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS=doc include src +if BUILD_TOPOLOGY +SUBDIRS += src/topology +endif +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 + +AM_CPPFLAGS=-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..3a68c32 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,843 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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_TOPOLOGY_TRUE@am__append_1 = src/topology +@BUILD_MODULES_TRUE@am__append_2 = modules +@BUILD_PCM_PLUGIN_SHM_TRUE@am__append_3 = aserver +@BUILD_ALISP_TRUE@@BUILD_MIXER_TRUE@am__append_4 = alsalisp +subdir = . +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) +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_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir distdir-am dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +DIST_SUBDIRS = doc include src src/topology modules aserver alsalisp \ + test utils +am__DIST_COMMON = $(srcdir)/Makefile.in COPYING ChangeLog INSTALL TODO \ + compile config.guess config.sub install-sh ltconfig ltmain.sh \ + missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_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 +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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) $(am__append_4) test utils +EXTRA_DIST = ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ + depcomp version MEMORY-LEAK m4/attributes.m4 + +AUTOMAKE_OPTIONS = foreign +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_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*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(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/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(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__post_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: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { 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: + 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-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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-hook dist-lzip 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-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +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..6a76f56 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1178 @@ +# generated automatically by aclocal 1.16.1 -*- Autoconf -*- + +# Copyright (C) 1996-2018 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_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +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'.])]) + +# Copyright (C) 2002-2018 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.16' +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.16.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.16.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-2018 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], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2018 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_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$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-2018 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. + + +# 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", "OBJC", "OBJCXX", "UPC", or "GJC". +# 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 + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" 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". + rm -rf conftest.dir + 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 10 /bin/sh. + echo '/* dummy */' > 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 + ;; + msvc7 | msvc7msys | 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], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2018 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_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf 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. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk +} +])# _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. +# This creates each '.Po' and '.Plo' makefile fragment that we'll 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" MAKE="${MAKE-make}"])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2018 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 macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# 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.65])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], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +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], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [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([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). 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])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro 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 + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +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-2018 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+set}" != 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-2018 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. + +# 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])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2018 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_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2018 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_MAKE_INCLUDE() +# ----------------- +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. +AC_DEFUN([AM_MAKE_INCLUDE], +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2018 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_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 is modern enough. +# If it is, 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 --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2018 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_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])]) + +# Copyright (C) 1999-2018 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_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2018 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_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2018 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_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# 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 ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + 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 + 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 + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + 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]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2018 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_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], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +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 +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2018 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-2018 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_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-2018 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_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. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + 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([m4/attributes.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) +m4_include([acinclude.m4]) diff --git a/alsalisp/Makefile.am b/alsalisp/Makefile.am new file mode 100644 index 0000000..8e3e015 --- /dev/null +++ b/alsalisp/Makefile.am @@ -0,0 +1,8 @@ +noinst_PROGRAMS = alsalisp + +alsalisp_SOURCES = alsalisp.c +alsalisp_LDADD = ../src/libasound.la + +all: alsalisp + +AM_CPPFLAGS=-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..debf6e6 --- /dev/null +++ b/alsalisp/Makefile.in @@ -0,0 +1,611 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/alsalisp.Po +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_CC_1 = +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_CCLD_1 = +SOURCES = $(alsalisp_SOURCES) +DIST_SOURCES = $(alsalisp_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/alisp +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) $(EXTRA_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@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/alsalisp.Po + -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 -f ./$(DEPDIR)/alsalisp.Po + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \ + ctags ctags-am 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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..d1e1bce --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..fbdb94c --- /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 + +AM_CPPFLAGS=-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..ad628d5 --- /dev/null +++ b/aserver/Makefile.in @@ -0,0 +1,658 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/aserver.Po +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_CC_1 = +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_CCLD_1 = +SOURCES = $(aserver_SOURCES) +DIST_SOURCES = $(aserver_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp COPYING +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/pcm +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + 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) $(EXTRA_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@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/aserver.Po + -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 -f ./$(DEPDIR)/aserver.Po + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ + ctags ctags-am 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 tags-am uninstall uninstall-am uninstall-binPROGRAMS + +.PRECIOUS: Makefile + + +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..2838702 --- /dev/null +++ b/aserver/aserver.c @@ -0,0 +1,1091 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + putc('\n', stderr); \ +} while (0) +#else +#define ERROR(args...) do {\ + fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \ + 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"); + close(sock); + 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; + } + + memset(&addr, 0, sizeof(addr)); + 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"); + close(sock); + 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); + break; + } + 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, result, sockn = -1, socki = -1; + unsigned int k; + long open_max; + + 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) { + sockn = make_local_socket(sockname); + if (sockn < 0) + return sockn; + if (fcntl(sockn, F_SETFL, O_NONBLOCK) < 0) { + result = -errno; + SYSERROR("fcntl O_NONBLOCK failed"); + goto _end; + } + if (listen(sockn, 4) < 0) { + result = -errno; + SYSERROR("listen failed"); + goto _end; + } + add_waiter(sockn, POLLIN, local_handler, NULL); + } + if (port >= 0) { + socki = make_inet_socket(port); + if (socki < 0) + return socki; + if (fcntl(socki, F_SETFL, O_NONBLOCK) < 0) { + result = -errno; + SYSERROR("fcntl failed"); + goto _end; + } + if (listen(socki, 4) < 0) { + result = -errno; + SYSERROR("listen failed"); + goto _end; + } + add_waiter(socki, 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: + if (sockn >= 0) + close(sockn); + if (socki >= 0) + close(socki); + 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; + long port = -1; + int err; + char *srvname; + + 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) + 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 (!sockname && port < 0) { + ERROR("either socket or port need to be defined"); + return 1; + } + server(sockname, port); + return 0; +} diff --git a/compile b/compile new file mode 100755 index 0000000..99e5052 --- /dev/null +++ b/compile @@ -0,0 +1,348 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2018 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, 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. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + 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'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +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 $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +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 's|^.*[\\/]||; s|^[a-zA-Z]:||; 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 + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..256083a --- /dev/null +++ b/config.guess @@ -0,0 +1,1476 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-03-08' + +# 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 3 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, 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. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -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 1992-2018 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 + +case "$UNAME_SYSTEM" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval "$set_cc_for_build" + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi + ;; +esac + +# 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 tuples: *-*-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=`(uname -p 2>/dev/null || \ + "/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 ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-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) and ABI. + case "$UNAME_MACHINE_ARCH" in + earm*) + os=netbsdelf + ;; + 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 + # Determine ABI tags. + case "$UNAME_MACHINE_ARCH" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + 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/[-_].*//' | cut -d. -f1,2` + ;; + 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}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$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 ;; + *:Sortix:*:*) + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + 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 ;; + 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/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + 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:4.4BSD:*) + 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:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case "$UNAME_PROCESSOR" in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + i*:CYGWIN*:*) + echo "$UNAME_MACHINE"-pc-cygwin + exit ;; + *:MINGW64*:*) + echo "$UNAME_MACHINE"-pc-mingw64 + exit ;; + *:MINGW*:*) + echo "$UNAME_MACHINE"-pc-mingw32 + exit ;; + *:MSYS*:*) + echo "$UNAME_MACHINE"-pc-msys + 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 ;; + i*:UWIN*:*) + echo "$UNAME_MACHINE"-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-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-$LIBC`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 "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" + exit ;; + i*86:Minix:*:*) + echo "$UNAME_MACHINE"-pc-minix + exit ;; + aarch64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + 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=gnulibc1 ; fi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$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-"$LIBC" + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + else + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + cris:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + crisv32:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + e2k:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + frv:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + hexagon:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + ia64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + k1om:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m32r*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m68*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + 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-$LIBC"; exit; } + ;; + mips64el:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-"$LIBC" + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-"$LIBC" + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-"$LIBC" + 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-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-"$LIBC" + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-"$LIBC" + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-"$LIBC" + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-"$LIBC" + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" + exit ;; + sh64*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sh*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + tile*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + vax:Linux:*:*) + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" + exit ;; + x86_64:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + xtensa*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + 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.*:*) + 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 configure 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 ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-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 ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-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 + eval "$set_cc_for_build" + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then + 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 + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + 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 ;; + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-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 ;; + x86_64:VMkernel:*:*) + echo "$UNAME_MACHINE"-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&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 'before-save-hook '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..20f7cf2 --- /dev/null +++ b/config.sub @@ -0,0 +1,1833 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-05-05' + +# 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 3 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, 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. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# 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: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# 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 or ALIAS + +Canonicalize a configuration name. + +Options: + -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 1992-2018 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 + +# Spilt fields of configuration type +IFS="-" read -r field1 field2 field3 field4 <&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | csky-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | 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-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nfp-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | 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*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | wasm32-* \ + | 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-pc + 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 + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + 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*) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + 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 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + 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 + ;; + 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 + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=-linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-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 + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + 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 + ;; + nsv-tandem) + basic_machine=nsv-tandem + ;; + nsx-tandem) + basic_machine=nsx-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) + 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) + 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 | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + 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 + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + 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 + ;; + tile*) + basic_machine=$basic_machine-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 + ;; + x64) + basic_machine=x86_64-pc + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # es1800 is here to avoid being matched by es* (a different OS) + -es1800*) + os=-ose + ;; + # Now 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* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ + | -midnightbsd*) + # 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 | -xray | -os68k* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* \ + | -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 + ;; + -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 + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=-eabi + ;; + *) + os=-elf + ;; + esac + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + -*-eabi) + case $basic_machine in + arm*) + ;; + esac + ;; + *) + # 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 + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + 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 + ;; + 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 + ;; + pru-*) + os=-elf + ;; + *-be) + os=-beos + ;; + *-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 + ;; + *-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 'before-save-hook '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..1b392f0 --- /dev/null +++ b/configure @@ -0,0 +1,16700 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for alsa-lib 1.2.1.2. +# +# +# Copyright (C) 1992-1996, 1998-2012 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. +as_myself= +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 + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # 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. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +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 +test -x / || 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 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || 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 : + export CONFIG_SHELL + # 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. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +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_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_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; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # 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 -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +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 + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# 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'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +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='alsa-lib' +PACKAGE_TARNAME='alsa-lib' +PACKAGE_VERSION='1.2.1.2' +PACKAGE_STRING='alsa-lib 1.2.1.2' +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_MIXER_PYMODULES_FALSE +BUILD_MIXER_PYMODULES_TRUE +BUILD_MIXER_MODULES_FALSE +BUILD_MIXER_MODULES_TRUE +BUILD_ALISP_FALSE +BUILD_ALISP_TRUE +BUILD_TOPOLOGY_FALSE +BUILD_TOPOLOGY_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_PKGCONF_DIR +ALSA_PLUGIN_DIR +ALSA_CONFIG_DIR +LIBTOOL_VERSION_INFO +SND_LIB_EXTRAVER +SND_LIB_SUBMINOR +SND_LIB_MINOR +SND_LIB_MAJOR +SND_LIB_VERSION +LDFLAGS_NOUNDEFINED +LT_SYS_LIBRARY_PATH +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +LIBTOOL +LN_S +EGREP +GREP +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +INSTALL_M4_FALSE +INSTALL_M4_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +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 +am__quote' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_dependency_tracking +enable_static +enable_shared +with_pic +enable_fast_install +with_aix_soname +with_gnu_ld +with_sysroot +enable_libtool_lock +with_configdir +with_plugindir +with_pkgconfdir +with_versioned +enable_symbolic_functions +with_debug +enable_debug_assert +with_tmpdir +with_softfloat +with_libdl +with_pthread +with_librt +with_wordexp +enable_resmgr +enable_aload +with_alsa_devdir +with_aload_devdir +enable_mixer +enable_pcm +enable_rawmidi +enable_hwdep +enable_seq +enable_ucm +enable_topology +enable_alisp +enable_old_symbols +enable_mixer_modules +enable_mixer_pymods +enable_python +enable_python2 +with_pythonlibs +with_pythonincludes +with_pcm_plugins +with_ctl_plugins +with_max_cards +enable_thread_safety +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +LT_SYS_LIBRARY_PATH' + + +# 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_TARNAME}' +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 + 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 alsa-lib 1.2.1.2 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/alsa-lib] + --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 + case $ac_init_help in + short | recursive ) echo "Configuration of alsa-lib 1.2.1.2:";; + esac + 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-maintainer-mode + disable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --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-topology disable the DSP topology component + --enable-alisp enable the alisp component + --disable-old-symbols disable old obsoleted symbols + --enable-mixer-modules enable the additional mixer modules (experimental) + --enable-mixer-pymods enable the mixer python modules (experimental) + --disable-python disable the python components + --enable-python2 prefer python2 + --disable-thread-safety disable thread-safe API functions + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). + --with-configdir=dir path where ALSA config files are stored + --with-plugindir=dir path where ALSA plugin files are stored + --with-pkgconfdir=dir path where pkgconfig 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-wordexp Use wordexp when expanding configs (default = no) + --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) + --with-max-cards Specify the max number of cards (default = 32) + +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 + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. + +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 +alsa-lib configure 1.2.1.2 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 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; ${as_lineno_stack:+:} 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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# 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 \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; 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 \${$3+:} false; 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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# 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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# 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 \${$3+:} false; 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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# 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 || + 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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# 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 \${$3+:} false; 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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_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; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl +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 alsa-lib $as_me 1.2.1.2, which was +generated by GNU Autoconf 2.69. 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 ${ac_cv_build+:} false; 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 ${ac_cv_host+:} false; 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.16' + +# 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 ${ac_cv_path_install+:} false; 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 as_fn_executable_p "$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; } +# 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 ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + 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 + 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 + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + 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; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +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 --is-lightweight"; then + am_missing_run="$MISSING " +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+set}" != 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 ${ac_cv_prog_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_path_mkdir+:} false; 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 + as_fn_executable_p "$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; } + +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 ${ac_cv_prog_AWK+:} false; 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 as_fn_executable_p "$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 \${ac_cv_prog_make_${ac_make}_set+:} false; 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 + +# 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=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +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.2.1.2' + + +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"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +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 + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +# 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_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + + + + +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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_CC+:} false; 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 as_fn_executable_p "$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 ${ac_cv_objext+:} false; 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 ${ac_cv_c_compiler_gnu+:} false; 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 ${ac_cv_prog_cc_g+:} false; 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 ${ac_cv_prog_cc_c89+:} false; 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 +struct stat; +/* 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 + +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 $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +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" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : + ;; +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +$as_echo "${_am_result}" >&6; } + +# 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='\' + am__nodep='_no' +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 ${am_cv_CC_dependencies_compiler_type+:} false; 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". + rm -rf conftest.dir + 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 10 /bin/sh. + echo '/* dummy */' > 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 + ;; + msvc7 | msvc7msys | 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 ${ac_cv_prog_CPP+:} false; 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 for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; 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" + as_fn_executable_p "$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 ${ac_cv_path_EGREP+:} false; 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" + as_fn_executable_p "$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 ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; 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 + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = xyes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if ${ac_cv_safe_to_define___extensions__+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + + +{ $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.4.6' +macro_revision='2.4.6' + + + + + + + + + + + + + +ltmain=$ac_aux_dir/ltmain.sh + +# Backslashify 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' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case $ECHO in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $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 ${ac_cv_path_SED+:} false; 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" + as_fn_executable_p "$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 fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; 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" + as_fn_executable_p "$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 no = "$withval" || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; 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 yes = "$with_gnu_ld"; 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 ${lt_cv_path_LD+:} false; 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 ${lt_cv_prog_gnu_ld+:} false; 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 ${lt_cv_path_NM+:} false; 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 + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + 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 no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + 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 ${ac_cv_prog_DUMPBIN+:} false; 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 as_fn_executable_p "$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 "link -dump" +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 ${ac_cv_prog_ac_ct_DUMPBIN+:} false; 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 as_fn_executable_p "$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 + + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + 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 ${lt_cv_nm_interface+:} false; 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:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: 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 ${lt_cv_sys_max_cmd_len+:} false; 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; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + 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; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # 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 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + 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" && \ + test undefined != "$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`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 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"} + +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 how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $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 ${lt_cv_ld_reload_flag+:} false; 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 + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; 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 ${ac_cv_prog_OBJDUMP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_OBJDUMP+:} false; 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 as_fn_executable_p "$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 ${lt_cv_deplibs_check_method+:} false; 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 +# that 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 + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + 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 + ;; + +haiku*) + 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])(-bit)?( [LM]SB)? 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + 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* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 + ;; +os2*) + 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_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +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}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $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 +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $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_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="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 + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + 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 ${ac_cv_prog_AR+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$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 +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 + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +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 ${ac_cv_prog_ac_ct_AR+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$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_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 + + + test -n "$ac_ct_AR" && break +done + + 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 +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +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 ${ac_cv_prog_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_STRIP+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_RANLIB+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_RANLIB+:} false; 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 as_fn_executable_p "$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 + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 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 ${lt_cv_sys_global_symbol_pipe+:} false; 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 ia64 = "$host_cpu"; 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 + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# 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"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$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"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, + # D for any global variable and I for any imported 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};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,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 + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # 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 +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#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. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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_globsym_save_LIBS=$LIBS + lt_globsym_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_globsym_save_LIBS + CFLAGS=$lt_globsym_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 yes = "$pipe_works"; 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 + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +$as_echo "$with_sysroot" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +$as_echo_n "checking for a working dd... " >&6; } +if ${ac_cv_path_lt_DD+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_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 dd; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +$as_echo "$ac_cv_path_lt_DD" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +$as_echo_n "checking how to truncate binary pipes... " >&6; } +if ${lt_cv_truncate_bin+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +$as_echo "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode + # options accordingly. + 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 what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "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 yes = "$lt_cv_prog_gnu_ld"; 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* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "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 + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + 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*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + 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" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + 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 ${lt_cv_cc_needs_belf+:} false; 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 yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + 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*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + 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 + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $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 +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $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_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + 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 + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi + + + + + + + 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 ${ac_cv_prog_DSYMUTIL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_NMEDIT+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_NMEDIT+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_LIPO+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_LIPO+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_OTOOL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_OTOOL+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_OTOOL64+:} false; 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 as_fn_executable_p "$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 ${ac_cv_prog_ac_ct_OTOOL64+:} false; 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 as_fn_executable_p "$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 ${lt_cv_apple_cc_single_mod+:} false; 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 there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; 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 ${lt_cv_ld_exported_symbols_list+:} false; 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; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&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 yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; 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" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + +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" = xyes; 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; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + pic_mode=default +fi + + + + + + + + + # 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 + + + + + + + + + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +$as_echo_n "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test "${with_aix_soname+set}" = set; then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else + if ${lt_cv_with_aix_soname+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_with_aix_soname=aix +fi + + with_aix_soname=$lt_cv_with_aix_soname +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +$as_echo "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + + + + +# 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 ${lt_cv_objdir+:} false; 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 set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# 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 + +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + +# 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 ${lt_cv_path_MAGIC_CMD+:} false; 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 ${lt_cv_path_MAGIC_CMD+:} false; 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* + + +## 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_prog_compiler_no_builtin_flag= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $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 ${lt_cv_prog_compiler_rtti_exceptions+:} false; 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" ## exclude from sc_useless_quotes_in_assignment + # 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 yes = "$lt_cv_prog_compiler_rtti_exceptions"; 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= + + + if test yes = "$GCC"; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + 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' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + 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 + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + 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 ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + + 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' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + 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 | 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' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # 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* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # 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='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + 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* | sunf77* | sunf90* | sunf95*) + 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 that 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}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# 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 ${lt_cv_prog_compiler_pic_works+:} false; 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" ## exclude from sc_useless_quotes_in_assignment + # 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 yes = "$lt_cv_prog_compiler_pic_works"; 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 ${lt_cv_prog_compiler_static_works+:} false; 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 "$_lt_linker_boilerplate" | $SED '/^$/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 yes = "$lt_cv_prog_compiler_static_works"; 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 ${lt_cv_prog_compiler_c_o+:} false; 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 ${lt_cv_prog_compiler_c_o+:} false; 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; 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 no = "$hard_links"; 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_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 yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/(^)\+)\s\+//' 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 ia64 != "$host_cpu"; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, 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 install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_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' + export_dynamic_flag_spec='$wl--export-all-symbols' + 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/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + 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, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; 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 + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + 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; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # 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; func_echo_all \"$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' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + ;; + 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; func_echo_all \"$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 yes = "$supports_anon_versioning"; 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 + tcc*) + export_dynamic_flag_spec='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # 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='$wl-rpath $wl$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; 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 $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 cannot +*** 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 no = "$ld_shlibs"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX 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") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + 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,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac + + if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + 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 + } + }' + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; 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. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + 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 + } + }' + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +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' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + 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. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + 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 `func_echo_all "$deplibs" | $SED '\''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' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + 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 + ;; + + # 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 $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $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 no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$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 yes,no = "$GCC,$with_gnu_ld"; 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 $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag $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' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -b" + 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 "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $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 + + ;; + esac + fi + if test no = "$with_gnu_ld"; 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 yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $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. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + 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) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=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_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -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 + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd*) + 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* | bitrig*) + 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__`"; 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 + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + osf3*) + if test yes = "$GCC"; 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" && func_echo_all "$wl-set_version $wl$verstring"` $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" && func_echo_all "-set_version $verstring"` -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 yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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 yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $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 $pic_flag $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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; 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 no = "$ld_shlibs" && 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 yes,yes = "$GCC,$enable_shared"; 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; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $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 + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + 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 yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # 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 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # 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` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + 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" + elif test -n "$lt_multi_os_dir"; then + 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; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; 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 + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # 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' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # 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' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + 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=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $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 # correct to gnu/linux during the next big refactor + 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,$cc_basename in + yes,*) + # gcc + 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="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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 # correct to gnu/linux during the next big refactor + 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 + ;; + +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[23].*) 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$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + 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 + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # 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 + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + 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 : + lt_cv_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 + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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 + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) 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;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $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' + ;; + +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 # correct to gnu/linux during the next big refactor + 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* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + 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 + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + 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' + ;; + +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 # correct to gnu/linux during the next big refactor + 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 yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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=sco + 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 yes = "$with_gnu_ld"; 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $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 yes = "$hardcode_automatic"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct" && + # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; 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 relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test yes != "$enable_dlopen"; 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 ${ac_cv_lib_dl_dlopen+:} false; 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" = xyes; 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 + + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; 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 ${ac_cv_lib_dld_shl_load+:} false; 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" = xyes; 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" = xyes; 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 ${ac_cv_lib_dl_dlopen+:} false; 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" = xyes; 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 ${ac_cv_lib_svld_dlopen+:} false; 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" = xyes; 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 ${ac_cv_lib_dld_dld_link+:} false; 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" = xyes; then : + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && 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 ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; 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 $LINENO "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 + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* 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 yes = "$lt_cv_dlopen_self"; 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 ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; 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 $LINENO "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 + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* 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 what 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || 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: + + + + + + + case $host in + *-freebsd*) ;; + *) + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports $possible_flags flag" >&5 +$as_echo_n "checking if $CC supports $possible_flags flag... " >&6; } +if { as_var=`$as_echo "cc_cv_ldflags_$possible_flags" | $as_tr_sh`; eval \${$as_var+:} false; }; then : + $as_echo_n "(cached) " >&6 +else + ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $possible_flags" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main() { return 1; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "`$as_echo "cc_cv_ldflags_$possible_flags" | $as_tr_sh`='yes'" +else + eval "`$as_echo "cc_cv_ldflags_$possible_flags" | $as_tr_sh`=" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$ac_save_LDFLAGS" + +fi +eval ac_res=\$`$as_echo "cc_cv_ldflags_$possible_flags" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + + if eval test x$`$as_echo "cc_cv_ldflags_$possible_flags" | $as_tr_sh` = xyes; then : + LDFLAGS_NOUNDEFINED="$possible_flags" +fi + + break + done + ;; + 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 ${ac_cv_header_stdc+:} false; 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 ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#ifndef __cplusplus + /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; + const charset cs = { 0, 0 }; + /* 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 sort of thing. */ + char tx; + char *t = &tx; + 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 sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; 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 ${ac_cv_c_inline+:} false; 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 ${ac_cv_header_time+:} false; 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 ${ac_cv_prog_gcc_traditional+:} false; 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 + +for ac_func in uselocale +do : + ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale" +if test "x$ac_cv_func_uselocale" = xyes; 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 + +if test "$enable_static" = "$enable_shared" -a "$enable_static" = "yes"; then +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" + + + +# Check whether --with-pkgconfdir was given. +if test "${with_pkgconfdir+set}" = set; then : + withval=$with_pkgconfdir; pkgconfdir="$withval" +else + pkgconfdir="" +fi + +if test -z "$pkgconfdir"; then + eval dir="$libdir" + case "$dir" in + /*) ;; + *) dir="$dir" + esac + pkgconfdir="$dir/pkgconfig" +fi + +cat >>confdefs.h <<_ACEOF +#define ALSA_PKGCONF_DIR "$pkgconfdir" +_ACEOF + +ALSA_PKGCONF_DIR="$pkgconfdir" + + +{ $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 + +HAVE_LIBDL= +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 ${ac_cv_lib_dl_dlsym+:} false; 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" = xyes; 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 ${ac_cv_lib_pthread_pthread_join+:} false; 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" = xyes; 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 + +if test "$HAVE_LIBPTHREAD" = "yes"; then + ac_fn_c_check_decl "$LINENO" "PTHREAD_MUTEX_RECURSIVE" "ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" "#include +" +if test "x$ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" = xyes; then : + +$as_echo "#define HAVE_PTHREAD_MUTEX_RECURSIVE /**/" >>confdefs.h + +fi + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __thread" >&5 +$as_echo_n "checking for __thread... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2)) +#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html +#endif +int +main () +{ +static __thread int p = 0 + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +$as_echo "#define HAVE___THREAD 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 +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $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 ${ac_cv_lib_rt_clock_gettime+:} false; 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" = xyes; 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 use of wordexp" >&5 +$as_echo_n "checking for use of wordexp... " >&6; } + +# Check whether --with-wordexp was given. +if test "${with_wordexp+set}" = set; then : + withval=$with_wordexp; case "$withval" in + y|yes) wordexp=yes ;; + *) wordexp=no ;; + esac +fi + +if test "$wordexp" = "yes" ; then + +$as_echo "#define HAVE_WORDEXP \"1\"" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + 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" = xyes; then : + +else + as_fn_error $? "Couldn't find wordexp.h" "$LINENO" 5 +fi + + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +for ac_header in endian.h sys/endian.h sys/shm.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$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 + + +{ $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 ${ac_cv_lib_resmgr_rsm_open_device+:} false; 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" = xyes; 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-topology was given. +if test "${enable_topology+set}" = set; then : + enableval=$enable_topology; build_topology="$enableval" +else + build_topology="yes" +fi + +# Check whether --enable-alisp was given. +if test "${enable_alisp+set}" = set; then : + enableval=$enable_alisp; build_alisp="$enableval" +else + build_alisp="no" +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-mixer-modules was given. +if test "${enable_mixer_modules+set}" = set; then : + enableval=$enable_mixer_modules; build_mixer_modules="$enableval" +else + build_mixer_modules="no" +fi + + +# Check whether --enable-mixer-pymods was given. +if test "${enable_mixer_pymods+set}" = set; then : + enableval=$enable_mixer_pymods; build_mixer_pymodules="$enableval" +else + build_mixer_pymodules="no" +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 + + +# Check whether --enable-python2 was given. +if test "${enable_python2+set}" = set; then : + enableval=$enable_python2; build_python2="$enableval" +else + build_python2="no" +fi + +PYTHON_LIBS="" +PYTHON_INCLUDES="" +if test "$build_python" = "yes" -a "$build_mixer_pymodules" = "yes"; then + pythonlibs0= + pythoninc0= + if test "$build_python2" != "yes"; then + pythonlibs0=$(python3-config --libs) + pythoninc0=$(python3-config --includes) + fi + if test -z "$pythonlibs0"; then + pythonlibs0=$(python-config --libs) + pythoninc0=$(python-config --includes) + fi + +# Check whether --with-pythonlibs was given. +if test "${with_pythonlibs+set}" = set; then : + withval=$with_pythonlibs; pythonlibs="$withval" +else + pythonlibs=$pythonlibs0 +fi + + +# Check whether --with-pythonincludes was given. +if test "${with_pythonincludes+set}" = set; then : + withval=$with_pythonincludes; pythonincludes="$withval" +else + pythonincludes=$pythoninc0 +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 "$build_python" != "yes"; then + build_mixer_pymodules= +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_topology = xyes; then + BUILD_TOPOLOGY_TRUE= + BUILD_TOPOLOGY_FALSE='#' +else + BUILD_TOPOLOGY_TRUE='#' + BUILD_TOPOLOGY_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_mixer_modules = xyes; then + BUILD_MIXER_MODULES_TRUE= + BUILD_MIXER_MODULES_FALSE='#' +else + BUILD_MIXER_MODULES_TRUE='#' + BUILD_MIXER_MODULES_FALSE= +fi + + if test x$build_mixer_pymodules = xyes; then + BUILD_MIXER_PYMODULES_TRUE= + BUILD_MIXER_PYMODULES_FALSE='#' +else + BUILD_MIXER_PYMODULES_TRUE='#' + BUILD_MIXER_PYMODULES_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_topology" = "yes"; then + +$as_echo "#define BUILD_TOPOLOGY \"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 + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GCC supports builtin atomic intrinsics" >&5 +$as_echo_n "checking whether GCC supports builtin atomic intrinsics... " >&6; } +if test -z "$gcc_have_atomics"; then + gcc_have_atomics=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int i; + __atomic_load_n(&i, __ATOMIC_SEQ_CST); + __atomic_add_fetch(&i, 0, __ATOMIC_SEQ_CST); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_have_atomics=yes +else + gcc_have_atomics=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_have_atomics" >&5 +$as_echo "$gcc_have_atomics" >&6; } + +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 "$gcc_have_atomics" != "yes"; then + build_pcm_meter="no" +fi + +if test "$ac_cv_header_sys_shm_h" != "yes"; then + build_pcm_dmix="no" + build_pcm_dshare="no" + build_pcm_dsnoop="no" + build_pcm_shm="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 "$ac_cv_header_sys_shm_h" != "yes"; then + build_ctl_shm="no" +fi + + 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 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for max number of cards" >&5 +$as_echo_n "checking for max number of cards... " >&6; } + +# Check whether --with-max-cards was given. +if test "${with_max_cards+set}" = set; then : + withval=$with_max_cards; max_cards="$withval" +else + max_cards="32" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $max_cards" >&5 +$as_echo "$max_cards" >&6; } + +if test "$max_cards" -lt 1; then + as_fn_error $? "Invalid max cards $max_cards" "$LINENO" 5 +elif test "$max_cards" -gt 256; then + as_fn_error $? "Invalid max cards $max_cards" "$LINENO" 5 +fi + +cat >>confdefs.h <<_ACEOF +#define SND_MAX_CARDS $max_cards +_ACEOF + + +if test "$HAVE_LIBPTHREAD" = "yes"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread-safe API functions" >&5 +$as_echo_n "checking for thread-safe API functions... " >&6; } +# Check whether --enable-thread-safety was given. +if test "${enable_thread_safety+set}" = set; then : + enableval=$enable_thread_safety; threadsafe="$enableval" +else + threadsafe="yes" +fi + +if test "$threadsafe" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define THREAD_SAFE_API \"1\"" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +fi + +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/alisp/Makefile src/topology/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 utils/alsa-topology.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 + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + 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 + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + 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 "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" 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 "${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_TOPOLOGY_TRUE}" && test -z "${BUILD_TOPOLOGY_FALSE}"; then + as_fn_error $? "conditional \"BUILD_TOPOLOGY\" 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_MIXER_MODULES_TRUE}" && test -z "${BUILD_MIXER_MODULES_FALSE}"; then + as_fn_error $? "conditional \"BUILD_MIXER_MODULES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_MIXER_PYMODULES_TRUE}" && test -z "${BUILD_MIXER_PYMODULES_FALSE}"; then + as_fn_error $? "conditional \"BUILD_MIXER_PYMODULES\" 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. +as_myself= +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 -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +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 + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# 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 alsa-lib $as_me 1.2.1.2, which was +generated by GNU Autoconf 2.69. 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="\\ +alsa-lib config.status 1.2.1.2 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 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" MAKE="${MAKE-make}" + + +# 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 "$enable_static" | $SED "$delay_single_quote_subst"`' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ +nm_file_list_spec \ +lt_cv_truncate_bin \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +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_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + 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 \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' + +# See if we are running on zsh, and set the options that 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' + 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/alisp/Makefile") CONFIG_FILES="$CONFIG_FILES src/alisp/Makefile" ;; + "src/topology/Makefile") CONFIG_FILES="$CONFIG_FILES src/topology/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" ;; + "utils/alsa-topology.pc") CONFIG_FILES="$CONFIG_FILES utils/alsa-topology.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= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_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 -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# 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 {' >"$ac_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 >>"\$ac_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 >>"\$ac_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 < "$ac_tmp/subs1.awk" > "$ac_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 >"$ac_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_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; 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="$ac_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 >"$ac_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 "$ac_tmp/subs.awk" \ + >$ac_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' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_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 "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_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 "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_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 "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_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"" || { + # Older Autoconf 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. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$am_mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? + done + if test $am_rc -ne 0; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options that 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 +# Generated automatically by $as_me ($PACKAGE) $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. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 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 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 this program. If not, see . + + +# The names of the tagged configurations supported by this script. +available_tags='' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### 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 + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# 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 + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# 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 + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# 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 + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# 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 into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + +# 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 lister interface. +nm_interface=$lt_lt_cv_nm_interface + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot=$lt_sysroot + +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# 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 + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# 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 + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# 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 + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path + +# 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 + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# 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 + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# 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 + +# 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 + +# 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 + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_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 + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_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 set != "${COLLECT_NAMES+set}"; 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 '$q' "$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 "$ac_cv_header_endian_h" = "yes" && echo "#include " >> include/asoundlib.h +if test "$ac_cv_header_sys_endian_h" = "yes"; then +cat >> include/asoundlib.h < +#ifndef __BYTE_ORDER +#define __BYTE_ORDER BYTE_ORDER +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#endif +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif +EOF +fi +cat >> include/asoundlib.h < +#include +#include +#include +#include +#include +#include +EOF +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 + +case $host in + *-*-linux-gnu) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Fixing libtool for -rpath problems." >&5 +$as_echo "Fixing libtool for -rpath problems." >&6; } + sed < libtool > libtool-2 \ + 's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=" -D__LIBTOOL_IS_A_FOOL__ "/' + mv libtool-2 libtool + chmod 755 libtool + ;; +esac diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..119ef60 --- /dev/null +++ b/configure.ac @@ -0,0 +1,777 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.59) +AC_INIT(alsa-lib, 1.2.1.2) + +AC_CONFIG_SRCDIR([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 +eval LIBTOOL_VERSION_INFO="2:0:0" +dnl ************************************************* +AM_CONDITIONAL([INSTALL_M4], [test -n "${ACLOCAL}"]) + +AM_MAINTAINER_MODE([enable]) + +# 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. + +AC_PROG_CC +AC_PROG_CPP +AC_USE_SYSTEM_EXTENSIONS +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 +AC_CONFIG_HEADERS(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_FUNCS([uselocale]) + +SAVE_LIBRARY_VERSION +AC_SUBST(LIBTOOL_VERSION_INFO) + +test "x$prefix" = xNONE && prefix=$ac_default_prefix + +dnl Do not build static and shared libraries together +if test "$enable_static" = "$enable_shared" -a "$enable_static" = "yes"; then +cat <&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" ]) +HAVE_LIBDL= +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 pthread +if test "$HAVE_LIBPTHREAD" = "yes"; then + AC_CHECK_DECL(PTHREAD_MUTEX_RECURSIVE, + AC_DEFINE(HAVE_PTHREAD_MUTEX_RECURSIVE, [], + [Define if your pthreads implementation have PTHREAD_MUTEX_RECURSIVE]), + , + [#include ]) +fi + +dnl Check for __thread +AC_MSG_CHECKING([for __thread]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2)) +#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html +#endif], [static __thread int p = 0])], +[AC_DEFINE(HAVE___THREAD, 1, +Define to 1 if compiler supports __thread) +AC_MSG_RESULT([yes])], +[AC_MSG_RESULT([no])]) + +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 use of wordexp... +AC_MSG_CHECKING(for use of wordexp) +AC_ARG_WITH(wordexp, + AS_HELP_STRING([--with-wordexp], + [Use wordexp when expanding configs (default = no)]), + [case "$withval" in + y|yes) wordexp=yes ;; + *) wordexp=no ;; + esac],) +if test "$wordexp" = "yes" ; then + AC_DEFINE(HAVE_WORDEXP, "1", [Enable use of wordexp]) + AC_MSG_RESULT(yes) + AC_CHECK_HEADER([wordexp.h],[], [AC_MSG_ERROR([Couldn't find wordexp.h])]) +else + AC_MSG_RESULT(no) +fi + +dnl Check for headers +AC_CHECK_HEADERS([endian.h sys/endian.h sys/shm.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(topology, + AS_HELP_STRING([--disable-topology], [disable the DSP topology component]), + [build_topology="$enableval"], [build_topology="yes"]) +AC_ARG_ENABLE(alisp, + AS_HELP_STRING([--enable-alisp], [enable the alisp component]), + [build_alisp="$enableval"], [build_alisp="no"]) +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(mixer-modules, + AS_HELP_STRING([--enable-mixer-modules], [enable the additional mixer modules (experimental)]), + [build_mixer_modules="$enableval"], [build_mixer_modules="no"]) + +AC_ARG_ENABLE(mixer-pymods, + AS_HELP_STRING([--enable-mixer-pymods], [enable the mixer python modules (experimental)]), + [build_mixer_pymodules="$enableval"], [build_mixer_pymodules="no"]) + +AC_ARG_ENABLE(python, + AS_HELP_STRING([--disable-python], [disable the python components]), + [build_python="$enableval"], [build_python="yes"]) + +AC_ARG_ENABLE(python2, + AS_HELP_STRING([--enable-python2], [prefer python2]), + [build_python2="$enableval"], [build_python2="no"]) +PYTHON_LIBS="" +PYTHON_INCLUDES="" +if test "$build_python" = "yes" -a "$build_mixer_pymodules" = "yes"; then + pythonlibs0= + pythoninc0= + if test "$build_python2" != "yes"; then + pythonlibs0=$(python3-config --libs) + pythoninc0=$(python3-config --includes) + fi + if test -z "$pythonlibs0"; then + pythonlibs0=$(python-config --libs) + pythoninc0=$(python-config --includes) + fi + AC_ARG_WITH(pythonlibs, + AS_HELP_STRING([--with-pythonlibs=ldflags], + [specify python libraries (-lpthread -lm -ldl -lpython2.4)]), + pythonlibs="$withval", pythonlibs=$pythonlibs0) + AC_ARG_WITH(pythonincludes, + AS_HELP_STRING([--with-pythonincludes=Cflags], + [specify python C header files (-I/usr/include/python)]), + pythonincludes="$withval", pythonincludes=$pythoninc0) + 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 "$build_python" != "yes"; then + build_mixer_pymodules= +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_TOPOLOGY], [test x$build_topology = xyes]) +AM_CONDITIONAL([BUILD_ALISP], [test x$build_alisp = xyes]) +AM_CONDITIONAL([BUILD_MIXER_MODULES], [test x$build_mixer_modules = xyes]) +AM_CONDITIONAL([BUILD_MIXER_PYMODULES], [test x$build_mixer_pymodules = 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 +if test "$build_topology" = "yes"; then + AC_DEFINE([BUILD_TOPOLOGY], "1", [Build DSP Topology 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 + +dnl check atomics for pcm_meter + +AC_MSG_CHECKING([whether GCC supports builtin atomic intrinsics]) +if test -z "$gcc_have_atomics"; then + gcc_have_atomics=no + AC_TRY_LINK([], + [int i; + __atomic_load_n(&i, __ATOMIC_SEQ_CST); + __atomic_add_fetch(&i, 0, __ATOMIC_SEQ_CST); + ], + [gcc_have_atomics=yes], + [gcc_have_atomics=no]) +fi +AC_MSG_RESULT($gcc_have_atomics) + +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 + +if test "$gcc_have_atomics" != "yes"; then + build_pcm_meter="no" +fi + +if test "$ac_cv_header_sys_shm_h" != "yes"; then + build_pcm_dmix="no" + build_pcm_dshare="no" + build_pcm_dsnoop="no" + build_pcm_shm="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 + +if test "$ac_cv_header_sys_shm_h" != "yes"; then + build_ctl_shm="no" +fi + +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 Max number of cards +AC_MSG_CHECKING(for max number of cards) +AC_ARG_WITH(max-cards, + AS_HELP_STRING([--with-max-cards], [Specify the max number of cards (default = 32)]), + [ max_cards="$withval" ], [ max_cards="32" ]) +AC_MSG_RESULT([$max_cards]) + +if test "$max_cards" -lt 1; then + AC_ERROR([Invalid max cards $max_cards]) +elif test "$max_cards" -gt 256; then + AC_ERROR([Invalid max cards $max_cards]) +fi +AC_DEFINE_UNQUOTED(SND_MAX_CARDS, $max_cards, [Max number of cards]) + +dnl Check for thread-safe API functions +if test "$HAVE_LIBPTHREAD" = "yes"; then +AC_MSG_CHECKING(for thread-safe API functions) +AC_ARG_ENABLE(thread-safety, + AS_HELP_STRING([--disable-thread-safety], + [disable thread-safe API functions]), + threadsafe="$enableval", threadsafe="yes") +if test "$threadsafe" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE([THREAD_SAFE_API], "1", [Disable thread-safe API functions]) +else + AC_MSG_RESULT(no) +fi +fi + +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/alisp/Makefile src/topology/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 utils/alsa-topology.pc) + +dnl Create asoundlib.h dynamically according to configure options +echo "Creating asoundlib.h..." +cp "$srcdir"/include/asoundlib-head.h include/asoundlib.h +test "$ac_cv_header_endian_h" = "yes" && echo "#include " >> include/asoundlib.h +if test "$ac_cv_header_sys_endian_h" = "yes"; then +cat >> include/asoundlib.h < +#ifndef __BYTE_ORDER +#define __BYTE_ORDER BYTE_ORDER +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#endif +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif +EOF +fi +cat >> include/asoundlib.h < +#include +#include +#include +#include +#include +#include +EOF +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 + +dnl Taken from https://wiki.debian.org/RpathIssue +case $host in + *-*-linux-gnu) + AC_MSG_RESULT([Fixing libtool for -rpath problems.]) + sed < libtool > libtool-2 \ + 's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=" -D__LIBTOOL_IS_A_FOOL__ "/' + mv libtool-2 libtool + chmod 755 libtool + ;; +esac diff --git a/depcomp b/depcomp new file mode 100755 index 0000000..65cbf70 --- /dev/null +++ b/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2018 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 outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +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" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# 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 + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 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=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +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 -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## 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). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - 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 -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # 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. +## 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. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -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 -ne 0; then + 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 ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # 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 + ;; + +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. + set_dir_from "$object" + set_base_from "$object" + 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 -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + 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. + set_dir_from "$object" + set_base_from "$object" + 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 -ne 0; then + 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,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_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. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool 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$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # 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 + ;; + +#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|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | 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" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | 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::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..e087f42 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS=pictures + +EXTRA_DIST=README.1st asoundrc.txt doxygen.cfg index.doxygen + +AM_CPPFLAGS=-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 -rf $(top_srcdir)/doc/doxygen/html/* + +doc-clean: + rm -rf $(top_srcdir)/doc/doxygen/html/* diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..9f49181 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,655 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = doxygen.cfg +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/doxygen.cfg.in +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am 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-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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 -rf $(top_srcdir)/doc/doxygen/html/* + +doc-clean: + rm -rf $(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 b/doc/doxygen.cfg new file mode 100644 index 0000000..4fd106b --- /dev/null +++ b/doc/doxygen.cfg @@ -0,0 +1,128 @@ +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 = ../doc/index.doxygen \ + ../include/asoundlib.h \ + ../include/version.h \ + ../include/global.h \ + ../include/asoundef.h \ + ../include/input.h \ + ../include/output.h \ + ../include/error.h \ + ../include/conf.h \ + ../include/control.h \ + ../include/pcm.h \ + ../include/rawmidi.h \ + ../include/timer.h \ + ../include/hwdep.h \ + ../include/seq.h \ + ../include/seq_event.h \ + ../include/seqmid.h \ + ../include/seq_midi_event.h \ + ../include/pcm_external.h \ + ../include/pcm_extplug.h \ + ../include/pcm_ioplug.h \ + ../include/control_external.h \ + ../include/mixer.h \ + ../include/use-case.h \ + ../include/topology.h \ + ../src/error.c \ + ../src/dlmisc.c \ + ../src/async.c \ + ../src/input.c \ + ../src/output.c \ + ../src/conf.c \ + ../src/confmisc.c \ + ../src/names.c \ + ../src/shmarea.c \ + ../src/userfile.c \ + ../src/control \ + ../src/mixer \ + ../src/pcm/pcm.c \ + ../src/pcm/pcm_mmap.c \ + ../src/pcm/pcm_plugin.c \ + ../src/pcm/pcm_hw.c \ + ../src/pcm/pcm_mmap_emul.c \ + ../src/pcm/pcm_shm.c \ + ../src/pcm/pcm_null.c \ + ../src/pcm/pcm_copy.c \ + ../src/pcm/pcm_linear.c \ + ../src/pcm/pcm_lfloat.c \ + ../src/pcm/pcm_mulaw.c \ + ../src/pcm/pcm_alaw.c \ + ../src/pcm/pcm_adpcm.c \ + ../src/pcm/pcm_route.c \ + ../src/pcm/pcm_rate.c \ + ../src/pcm/pcm_plug.c \ + ../src/pcm/pcm_file.c \ + ../src/pcm/pcm_multi.c \ + ../src/pcm/pcm_share.c \ + ../src/pcm/pcm_hooks.c \ + ../src/pcm/pcm_dmix.c \ + ../src/pcm/pcm_dshare.c \ + ../src/pcm/pcm_dsnoop.c \ + ../src/pcm/pcm_meter.c \ + ../src/pcm/pcm_ladspa.c \ + ../src/pcm/pcm_asym.c \ + ../src/pcm/pcm_iec958.c \ + ../src/pcm/pcm_softvol.c \ + ../src/pcm/pcm_extplug.c \ + ../src/pcm/pcm_ioplug.c \ + ../src/pcm/pcm_empty.c \ + ../src/pcm/pcm_misc.c \ + ../src/pcm/pcm_simple.c \ + ../src/rawmidi \ + ../src/timer \ + ../src/hwdep \ + ../src/seq \ + ../src/ucm \ + ../src/topology +EXCLUDE = ../src/control/control_local.h \ + ../src/pcm/atomic.h \ + ../src/pcm/interval.h \ + ../src/pcm/interval_inline.h \ + ../src/pcm/mask.h \ + ../src/pcm/mask_inline.h \ + ../src/pcm/pcm_local.h \ + ../src/pcm/pcm_meter.h \ + ../src/pcm/pcm_plugin.h \ + ../src/pcm/plugin_ops.h \ + ../src/pcm/ladspa.h \ + ../src/hwdep/hwdep_local.h \ + ../src/mixer/mixer_local.h \ + ../src/rawmidi/rawmidi_local.h \ + ../src/seq/seq_local.h \ + ../src/ucm/ucm_local.h \ + ../src/topology/tplg_local.h +RECURSIVE = YES +FILE_PATTERNS = *.c *.h +EXAMPLE_PATH = ../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 + +HTML_TIMESTAMP = NO diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in new file mode 100644 index 0000000..11740d3 --- /dev/null +++ b/doc/doxygen.cfg.in @@ -0,0 +1,128 @@ +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@/include/topology.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 \ + @top_srcdir@/src/topology +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/ucm/ucm_local.h \ + @top_srcdir@/src/topology/tplg_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 + +HTML_TIMESTAMP = NO diff --git a/doc/index.doxygen b/doc/index.doxygen new file mode 100644 index 0000000..b40c75a --- /dev/null +++ b/doc/index.doxygen @@ -0,0 +1,56 @@ +/*! \mainpage 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. +
  • Page \ref ucm explains the use case API. +
  • Page \ref topology explains the DSP topology 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..ce69380 --- /dev/null +++ b/doc/pictures/Makefile.in @@ -0,0 +1,454 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 -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 \ + cscopelist-am ctags-am 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 \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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 0000000..e465df8 Binary files /dev/null and b/doc/pictures/wave1.gif differ diff --git a/doc/pictures/wave2.gif b/doc/pictures/wave2.gif new file mode 100644 index 0000000..ee91bf2 Binary files /dev/null and b/doc/pictures/wave2.gif differ diff --git a/gitcompile b/gitcompile new file mode 100755 index 0000000..41da25d --- /dev/null +++ b/gitcompile @@ -0,0 +1,94 @@ +#!/bin/bash + +set -e + +bit32= +modules= +alisp= +lto= +if [ $# -ne 0 ]; then + endloop= + while [ -z "$endloop" ]; do + case "$1" in + 32) + bits32=yes + echo "Forced 32-bit library build..." + shift ;; + modules) + modules=yes + echo "Forced mixer modules build..." + shift ;; + alisp) + alisp=yes + echo "Forced alisp code build..." + shift ;; + python2) + python2=yes + echo "Forced python2 interpreter build..." + shift ;; + lto) + lto="-flto -flto-partition=none" + echo "Forced lto build..." + shift ;; + *) + endloop=yes + ;; + esac + done +fi +if [ $# -ne 0 -a -z "$bit32" ]; then + args="$@" +elif [ -r /etc/asound/library_args ]; then + args="`cat /etc/asound/library_args`" + if [ -z "$bit32" ]; then + test -r /etc/asound/library64_args && \ + args="`cat /etc/asound/library64_args`" + fi +else + prefix="/usr" + libdir="/usr/lib" + libdir2="/usr/lib" + if [ -z "$bit32" ]; then + test -d /usr/lib64 && libdir="/usr/lib64" + test -f /lib64/libasound.so.2 && libdir="/lib64" + test -d /usr/lib64 && libdir2="/usr/lib64" + else + test -f /lib/libasound.so.2 && libdir="/lib" + fi + args="--disable-aload --prefix=$prefix --libdir=$libdir" + args="$args --with-plugindir=$libdir2/alsa-lib" + args="$args --with-pkgconfdir=$libdir2/pkgconfig" +fi + +if [ "$modules" = "yes" ]; then + args="$args --enable-mixer-modules" + args="$args --enable-mixer-pymods" +fi + +if [ "$alisp" = "yes" ]; then + args="$args --enable-alisp" +fi + +if [ "$python2" = "yes" ]; then + args="$args --enable-python2" +fi + +touch ltconfig +libtoolize --force --copy --automake +aclocal $ACLOCAL_FLAGS +autoheader +automake --foreign --copy --add-missing +touch depcomp # seems to be missing for old automake +autoconf +export CFLAGS="-O2 -Wall -W -Wunused-const-variable=0 -pipe -g $lto" +if [ -n "$lto" ]; then + export AR="gcc-ar" + export RANLIB="gcc-ranlib" +fi +echo "CFLAGS=$CFLAGS" +echo "./configure $args" +./configure $args || exit 1 +unset CFLAGS +if [ -z "$GITCOMPILE_NO_MAKE" ]; then + make +fi diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..665704a --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,99 @@ +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 + +if BUILD_CTL_PLUGIN_EXT +alsainclude_HEADERS += control_external.h +endif + +if BUILD_PCM +alsainclude_HEADERS += pcm.h pcm_old.h timer.h +if BUILD_PCM_PLUGIN +alsainclude_HEADERS += pcm_plugin.h +endif +if BUILD_PCM_PLUGIN_RATE +alsainclude_HEADERS += pcm_rate.h +endif +if BUILD_PCM_PLUGIN_EXTPLUG +alsainclude_HEADERS += pcm_external.h pcm_extplug.h +endif +if BUILD_PCM_PLUGIN_IOPLUG +if !BUILD_PCM_PLUGIN_EXTPLUG +alsainclude_HEADERS += pcm_external.h +endif +alsainclude_HEADERS += pcm_ioplug.h +endif +endif + +if BUILD_RAWMIDI +alsainclude_HEADERS += rawmidi.h +endif + +if BUILD_HWDEP +alsainclude_HEADERS += hwdep.h +endif + +if BUILD_MIXER +alsainclude_HEADERS += mixer.h mixer_abst.h +endif + +if BUILD_SEQ +alsainclude_HEADERS += seq_event.h seq.h seqmid.h seq_midi_event.h +endif + +if BUILD_UCM +alsainclude_HEADERS += use-case.h +endif + +if BUILD_TOPOLOGY +alsainclude_HEADERS += topology.h +endif + +if BUILD_ALISP +alsainclude_HEADERS += alisp.h +endif + +noinst_HEADERS = alsa sys.h search.h list.h aserver.h local.h alsa-symbols.h \ + asoundlib-head.h asoundlib-tail.h bswap.h type_compat.h + +DISTCLEANFILES = stamp-vh version.h alsa asoundlib.h + +alsa: + ln -s $(top_srcdir)/include alsa + +version.h: stamp-vh alsa + @: + +stamp-vh: $(top_builddir)/configure.ac + @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 + +AM_CPPFLAGS=-I$(top_srcdir)/include + +install-data-hook: + test -d $(DESTDIR)$(sysincludedir) || mkdir -p $(DESTDIR)$(sysincludedir) + $(INSTALL_DATA) $(srcdir)/sys.h $(DESTDIR)$(sysincludedir)/asoundlib.h + $(INSTALL_DATA) $(srcdir)/sys.h $(DESTDIR)$(includedir)/asoundlib.h diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 0000000..aaf0bee --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,778 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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_UCM_TRUE@am__append_12 = use-case.h +@BUILD_TOPOLOGY_TRUE@am__append_13 = topology.h +@BUILD_ALISP_TRUE@am__append_14 = alisp.h +subdir = include +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__alsainclude_HEADERS_DIST) \ + $(noinst_HEADERS) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__alsainclude_HEADERS_DIST = asoundlib.h asoundef.h version.h \ + global.h input.h output.h error.h conf.h control.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 use-case.h topology.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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +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_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 $(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) +noinst_HEADERS = alsa sys.h search.h list.h aserver.h local.h alsa-symbols.h \ + asoundlib-head.h asoundlib-tail.h bswap.h type_compat.h + +DISTCLEANFILES = stamp-vh version.h alsa asoundlib.h +AM_CPPFLAGS = -I$(top_srcdir)/include +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +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: @MAINTAINER_MODE_TRUE@ $(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) + @list='$(alsainclude_HEADERS)'; test -n "$(alsaincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(alsaincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(alsaincludedir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(alsaincludedir)'; $(am__uninstall_files_from_dir) + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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) + -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: $(am__recursive_targets) all install-am install-data-am \ + install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am 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-am uninstall \ + uninstall-alsaincludeHEADERS uninstall-am + +.PRECIOUS: Makefile + + +alsa: + ln -s $(top_srcdir)/include alsa + +version.h: stamp-vh alsa + @: + +stamp-vh: $(top_builddir)/configure.ac + @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 + $(INSTALL_DATA) $(srcdir)/sys.h $(DESTDIR)$(includedir)/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..11d7adf --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 b/include/alsa new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/include/alsa @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/include/alsa-symbols.h b/include/alsa-symbols.h new file mode 100644 index 0000000..bba9a9d --- /dev/null +++ b/include/alsa-symbols.h @@ -0,0 +1,57 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) + +#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) + +#define EXPORT_SYMBOL __attribute__((visibility("default"),externally_visible)) + +#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 */ +#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 /* __ALSA_SYMBOLS_H */ diff --git a/include/aserver.h b/include/aserver.h new file mode 100644 index 0000000..6fb9480 --- /dev/null +++ b/include/aserver.h @@ -0,0 +1,159 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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); + +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..f4dfa92 --- /dev/null +++ b/include/asoundef.h @@ -0,0 +1,344 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/CEA-861 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 */ + +#define CEA861_AUDIO_INFOFRAME_DB1CC (7<<0) /**< mask - channel count */ +#define CEA861_AUDIO_INFOFRAME_DB1CT (0xf<<4) /**< mask - coding type */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM (0<<4) /**< refer to stream */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_IEC60958 (1<<4) /**< IEC-60958 L-PCM */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_AC3 (2<<4) /**< AC-3 */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG1 (3<<4) /**< MPEG1 Layers 1 & 2 */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_MP3 (4<<4) /**< MPEG1 Layer 3 */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG2_MULTICH (5<<4) /**< MPEG2 Multichannel */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_AAC (6<<4) /**< AAC */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS (7<<4) /**< DTS */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_ATRAC (8<<4) /**< ATRAC */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_ONEBIT (9<<4) /**< One Bit Audio */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_DOLBY_DIG_PLUS (10<<4) /**< Dolby Digital + */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS_HD (11<<4) /**< DTS-HD */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_MAT (12<<4) /**< MAT (MLP) */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_DST (13<<4) /**< DST */ +#define CEA861_AUDIO_INFOFRAME_DB1CT_WMA_PRO (14<<4) /**< WMA Pro */ +#define CEA861_AUDIO_INFOFRAME_DB2SF (7<<2) /**< mask - sample frequency */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM (0<<2) /**< refer to stream */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_32000 (1<<2) /**< 32kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_44100 (2<<2) /**< 44.1kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_48000 (3<<2) /**< 48kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_88200 (4<<2) /**< 88.2kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_96000 (5<<2) /**< 96kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_176400 (6<<2) /**< 176.4kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SF_192000 (7<<2) /**< 192kHz */ +#define CEA861_AUDIO_INFOFRAME_DB2SS (3<<0) /**< mask - sample size */ +#define CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM (0<<0) /**< refer to stream */ +#define CEA861_AUDIO_INFOFRAME_DB2SS_16BIT (1<<0) /**< 16 bits */ +#define CEA861_AUDIO_INFOFRAME_DB2SS_20BIT (2<<0) /**< 20 bits */ +#define CEA861_AUDIO_INFOFRAME_DB2SS_24BIT (3<<0) /**< 24 bits */ +#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH (1<<7) /**< mask - inhibit downmixing */ +#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED (0<<7) /**< stereo downmix permitted */ +#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED (1<<7) /**< stereo downmis prohibited */ +#define CEA861_AUDIO_INFOFRAME_DB5_LSV (0xf<<3) /**< mask - level-shift values */ + +/** + * \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..7cfa440 --- /dev/null +++ b/include/asoundlib-head.h @@ -0,0 +1,40 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ASOUNDLIB_H +#define __ASOUNDLIB_H + +#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/asoundlib.h b/include/asoundlib.h new file mode 100644 index 0000000..94dfb7b --- /dev/null +++ b/include/asoundlib.h @@ -0,0 +1,65 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ASOUNDLIB_H +#define __ASOUNDLIB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __GNUC__ +#define __inline__ inline +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __ASOUNDLIB_H */ diff --git a/include/bswap.h b/include/bswap.h new file mode 100644 index 0000000..4e5b3e2 --- /dev/null +++ b/include/bswap.h @@ -0,0 +1,39 @@ +/* + * ALSA lib - compatibility header for providing byte swapping macros + * Copyright (c) 2016 by Thomas Klausner + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __BSWAP_H +#define __BSWAP_H + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#include +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 +#elif defined (__sun) +#include +#define bswap_16 BSWAP_16 +#define bswap_32 BSWAP_32 +#define bswap_64 BSWAP_64 +#else +#include +#endif + +#endif diff --git a/include/conf.h b/include/conf.h new file mode 100644 index 0000000..456b272 --- /dev/null +++ b/include/conf.h @@ -0,0 +1,217 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + +const char *snd_config_topdir(void); + +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_update_ref(snd_config_t **top); +void snd_config_ref(snd_config_t *top); +void snd_config_unref(snd_config_t *top); + +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 *child); +int snd_config_add_before(snd_config_t *before, snd_config_t *child); +int snd_config_add_after(snd_config_t *after, snd_config_t *child); +int snd_config_remove(snd_config_t *config); +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_safe_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..691d0e4 --- /dev/null +++ b/include/config.h.in @@ -0,0 +1,228 @@ +/* include/config.h.in. Generated from configure.ac 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 pkgconfig files */ +#undef ALSA_PKGCONF_DIR + +/* 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 DSP Topology component */ +#undef BUILD_TOPOLOGY + +/* 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_ENDIAN_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 + +/* Define if your pthreads implementation have PTHREAD_MUTEX_RECURSIVE */ +#undef HAVE_PTHREAD_MUTEX_RECURSIVE + +/* 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_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SHM_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 + +/* Enable use of wordexp */ +#undef HAVE_WORDEXP + +/* Define to 1 if compiler supports __thread */ +#undef HAVE___THREAD + +/* Define to the sub-directory where 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 + +/* Max number of cards */ +#undef SND_MAX_CARDS + +/* 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 + +/* Disable thread-safe API functions */ +#undef THREAD_SAFE_API + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* directory to put tmp socket files */ +#undef TMPDIR + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* sound library version string */ +#undef VERSION + +/* compiled with versioned symbols */ +#undef VERSIONED_SYMBOLS + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* 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..02db72d --- /dev/null +++ b/include/control.h @@ -0,0 +1,622 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 + +/** TLV type - fixed channel map positions */ +#define SND_CTL_TLVT_CHMAP_FIXED 0x00101 +/** TLV type - freely swappable channel map positions */ +#define SND_CTL_TLVT_CHMAP_VAR 0x00102 +/** TLV type - pair-wise swappable channel map positions */ +#define SND_CTL_TLVT_CHMAP_PAIRED 0x00103 + +/** 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_open_fallback(snd_ctl_t **ctl, snd_config_t *root, const char *name, const char *orig_name, int mode); +int snd_ctl_close(snd_ctl_t *ctl); +int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock); +static __inline__ int snd_ctl_abort(snd_ctl_t *ctl) { return snd_ctl_nonblock(ctl, 2); } +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 *data); +int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *data); +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); +int snd_ctl_elem_info_set_dimension(snd_ctl_elem_info_t *info, + const int dimension[4]); +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_add_integer_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count, + long min, long max, long step); +int snd_ctl_add_integer64_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count, + long long min, long long max, + long long step); +int snd_ctl_add_boolean_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count); +int snd_ctl_add_enumerated_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count, + unsigned int items, + const char *const labels[]); +int snd_ctl_add_bytes_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count); + +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_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, unsigned int items, const char *const names[]); +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); +static __inline__ int snd_hctl_abort(snd_hctl_t *hctl) { return snd_hctl_nonblock(hctl, 2); } +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..488fa6e --- /dev/null +++ b/include/control_external.h @@ -0,0 +1,286 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; +#ifdef DOC_HIDDEN +/* redefine typedef's for stupid doxygen */ +typedef snd_ctl_ext snd_ctl_ext_t; +typedef snd_ctl_ext_callback snd_ctl_ext_callback_t; +#endif +/** Callback to handle TLV commands. */ +typedef int (snd_ctl_ext_tlv_rw_t)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int op_flag, unsigned int numid, + unsigned int *tlv, unsigned int tlv_size); + +/* + * 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 1 /**< 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 */ + + /** + * optional TLV data for the control (since protocol 1.0.1) + */ + union { + snd_ctl_ext_tlv_rw_t *c; + const unsigned int *p; + } tlv; +}; + +/** 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_TLV_READ = (1<<4), + SND_CTL_EXT_ACCESS_TLV_WRITE = (1<<5), + SND_CTL_EXT_ACCESS_TLV_READWRITE = (3<<4), + SND_CTL_EXT_ACCESS_TLV_COMMAND = (1<<6), + SND_CTL_EXT_ACCESS_INACTIVE = (1<<8), + SND_CTL_EXT_ACCESS_TLV_CALLBACK = (1<<28), +} 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..7239db8 --- /dev/null +++ b/include/error.h @@ -0,0 +1,85 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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__, __func__, 0, __VA_ARGS__) /**< Shows a sound error message. */ +#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __func__, errno, __VA_ARGS__) /**< Shows a system error message (related to \c errno). */ +#else +#define SNDERR(args...) snd_lib_error(__FILE__, __LINE__, __func__, 0, ##args) /**< Shows a sound error message. */ +#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __func__, errno, ##args) /**< Shows a system error message (related to \c errno). */ +#endif + +/** \} */ + +#ifdef __cplusplus +} +#endif + +/** Local error handler function type */ +typedef void (*snd_local_error_handler_t)(const char *file, int line, + const char *func, int err, + const char *fmt, va_list arg); + +snd_local_error_handler_t snd_lib_error_set_local(snd_local_error_handler_t func); + +#endif /* __ALSA_ERROR_H */ + diff --git a/include/global.h b/include/global.h new file mode 100644 index 0000000..d73d333 --- /dev/null +++ b/include/global.h @@ -0,0 +1,161 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, char *errbuf, size_t errbuflen); +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); + +#ifdef __GLIBC__ +#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 +#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..46ed1f7 --- /dev/null +++ b/include/hwdep.h @@ -0,0 +1,172 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_HDA, /**< HD-audio */ + SND_HWDEP_IFACE_USB_STREAM, /**< direct access to usb stream */ + SND_HWDEP_IFACE_FW_DICE, /**< TC DICE FireWire device */ + SND_HWDEP_IFACE_FW_FIREWORKS, /**< Echo Audio Fireworks based device */ + SND_HWDEP_IFACE_FW_BEBOB, /**< BridgeCo BeBoB based device */ + SND_HWDEP_IFACE_FW_OXFW, /**< Oxford OXFW970/971 based device */ + SND_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ + SND_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ + SND_HWDEP_IFACE_LINE6, /* Line6 USB processors */ + SND_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */ + SND_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ + + SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_FW_FIREFACE, /**< 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_count(snd_hwdep_t *hwdep); +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/input.h b/include/input.h new file mode 100644 index 0000000..e7ce791 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..7f0cfc0 --- /dev/null +++ b/include/list.h @@ -0,0 +1,117 @@ +/* Doubly linked list macros compatible with Linux kernel's version + * Copyright (c) 2015 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. + */ + +#ifndef _LIST_H +#define _LIST_H + +#include + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +/* one-shot definition of a list head */ +#define LIST_HEAD(x) \ + struct list_head x = { &x, &x } + +/* initialize a list head explicitly */ +static inline void INIT_LIST_HEAD(struct list_head *p) +{ + p->next = p->prev = p; +} + +#define list_entry_offset(p, type, offset) \ + ((type *)((char *)(p) - (offset))) + +/* list_entry - retrieve the original struct from list_head + * @p: list_head pointer + * @type: struct type + * @member: struct field member containing the list_head + */ +#define list_entry(p, type, member) \ + list_entry_offset(p, type, offsetof(type, member)) + +/* list_for_each - iterate over the linked list + * @p: iterator, a list_head pointer variable + * @list: list_head pointer containing the list + */ +#define list_for_each(p, list) \ + for (p = (list)->next; p != (list); p = p->next) + +/* list_for_each_safe - iterate over the linked list, safe to delete + * @p: iterator, a list_head pointer variable + * @s: a temporary variable to keep the next, a list_head pointer, too + * @list: list_head pointer containing the list + */ +#define list_for_each_safe(p, s, list) \ + for (p = (list)->next; s = p->next, p != (list); p = s) + +/* list_add - prepend a list entry at the head + * @p: the new list entry to add + * @list: the list head + */ +static inline void list_add(struct list_head *p, struct list_head *list) +{ + struct list_head *first = list->next; + + p->next = first; + first->prev = p; + list->next = p; + p->prev = list; +} + +/* list_add_tail - append a list entry at the tail + * @p: the new list entry to add + * @list: the list head + */ +static inline void list_add_tail(struct list_head *p, struct list_head *list) +{ + struct list_head *last = list->prev; + + last->next = p; + p->prev = last; + p->next = list; + list->prev = p; +} + +/* list_insert - insert a new list entry between two known consecutive entries + * @p: the new entry to be inserted between prev and next + * @prev: the left-side entry + * @next: the right-side entry + */ +static inline void list_insert(struct list_head *p, + struct list_head *prev, + struct list_head *next) +{ + next->prev = p; + p->next = next; + p->prev = prev; + prev->next = p; +} + +/* list_del - delete the given list entry */ +static inline void list_del(struct list_head *p) +{ + p->prev->next = p->next; + p->next->prev = p->prev; +} + +/* list_empty - returns 1 if the given list is empty */ +static inline int list_empty(const struct list_head *p) +{ + return p->next == p; +} + +#endif /* _LIST_H */ diff --git a/include/local.h b/include/local.h new file mode 100644 index 0000000..ea0ec32 --- /dev/null +++ b/include/local.h @@ -0,0 +1,375 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __LOCAL_H +#define __LOCAL_H + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ENDIAN_H +#include +#elif defined(HAVE_SYS_ENDIAN_H) +#include +#ifndef __BYTE_ORDER +#define __BYTE_ORDER BYTE_ORDER +#endif +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#endif +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif +#else +#error Header defining endianness not defined +#endif +#include +#include +#include +#include +#if defined(__linux__) +#include +#include +#else +#include "type_compat.h" +#endif + +#ifdef SUPPORT_RESMGR +#include +#endif +#ifdef HAVE_LIBDL +#include +#else +#define RTLD_NOW 0 +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SND_LITTLE_ENDIAN +#define SNDRV_LITTLE_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +#define SND_BIG_ENDIAN +#define SNDRV_BIG_ENDIAN +#else +#error "Unsupported endian..." +#endif + +#define _snd_config_iterator list_head +#define _snd_interval snd_interval +#define _snd_pcm_info snd_pcm_info +#define _snd_pcm_hw_params snd_pcm_hw_params +#define _snd_pcm_sw_params snd_pcm_sw_params +#define _snd_pcm_status snd_pcm_status + +#define _snd_ctl_card_info snd_ctl_card_info +#define _snd_ctl_elem_id snd_ctl_elem_id +#define _snd_ctl_elem_list snd_ctl_elem_list +#define _snd_ctl_elem_info snd_ctl_elem_info +#define _snd_ctl_elem_value snd_ctl_elem_value +#define _snd_ctl_event snd_ctl_event + +#define _snd_rawmidi_info snd_rawmidi_info +#define _snd_rawmidi_params snd_rawmidi_params +#define _snd_rawmidi_status snd_rawmidi_status + +#define _snd_hwdep_info snd_hwdep_info +#define _snd_hwdep_dsp_status snd_hwdep_dsp_status +#define _snd_hwdep_dsp_image snd_hwdep_dsp_image + +#define _snd_seq_queue_tempo snd_seq_queue_tempo +#define _snd_seq_client_info snd_seq_client_info +#define _snd_seq_port_info snd_seq_port_info +#define _snd_seq_system_info snd_seq_system_info +#define _snd_seq_queue_info snd_seq_queue_info +#define _snd_seq_queue_status snd_seq_queue_status +#define _snd_seq_queue_timer snd_seq_queue_timer +#define _snd_seq_port_subscribe snd_seq_port_subscribe +#define _snd_seq_query_subscribe snd_seq_query_subs +#define _snd_seq_client_pool snd_seq_client_pool +#define _snd_seq_remove_events snd_seq_remove_events + +#define _snd_timer_id snd_timer_id +#define _snd_timer_ginfo snd_timer_ginfo +#define _snd_timer_gparams snd_timer_gparams +#define _snd_timer_gstatus snd_timer_gstatus +#define _snd_timer_select snd_timer_select +#define _snd_timer_info snd_timer_info +#define _snd_timer_params snd_timer_params +#define _snd_timer_status snd_timer_status + +#define ALSA_LIBRARY_BUILD + +/* rename some types for avoiding conflicts with alsalib's definitions */ +#define snd_aes_iec958 sndrv_aes_iec958 +#define snd_pcm_uframes_t sndrv_pcm_uframes_t +#define snd_pcm_sframes_t sndrv_pcm_sframes_t +#define snd_pcm_access_t sndrv_pcm_access_t +#define snd_pcm_format_t sndrv_pcm_format_t +#define snd_pcm_subformat_t sndrv_pcm_subformat_t +#define snd_pcm_state_t sndrv_pcm_state_t +#define snd_interval sndrv_interval +#define snd_mask sndrv_mask +#define snd_ctl_elem_type_t sndrv_ctl_elem_type_t +#define snd_ctl_elem_iface_t sndrv_ctl_elem_iface_t +#define snd_ctl_tlv sndrv_ctl_tlv + +/* kill and replace kernel-specific types */ +#ifndef __user +#define __user +#endif +#ifndef __force +#define __force +#endif + +#include + +/* take back superfluous renames; some can be kept as is */ +#undef snd_aes_iec958 +#undef snd_pcm_uframes_t +#undef snd_pcm_sframes_t +#undef snd_pcm_access_t +#undef snd_pcm_format_t +#undef snd_pcm_subformat_t +#undef snd_pcm_state_t +#undef snd_ctl_elem_type_t +#undef snd_ctl_elem_iface_t + +#include "asoundef.h" +#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" + +/* rename some types for avoiding conflicts with alsalib's definitions */ +#define snd_seq_addr sndrv_seq_addr +#define snd_seq_tick_time_t sndrv_seq_tick_time_t +#define snd_seq_real_time sndrv_seq_real_time +#define snd_seq_timestamp sndrv_seq_timestamp +#define snd_seq_event_type_t sndrv_seq_event_type_t +#define snd_seq_event sndrv_seq_event +#define snd_seq_connect sndrv_seq_connect +#define snd_seq_ev_note sndrv_seq_ev_note +#define snd_seq_ev_ctrl sndrv_seq_ev_ctrl +#define snd_seq_ev_raw8 sndrv_seq_ev_raw8 +#define snd_seq_ev_raw32 sndrv_seq_ev_raw32 +#define snd_seq_ev_ext sndrv_seq_ev_ext +#define snd_seq_result sndrv_seq_result +#define snd_seq_queue_skew sndrv_seq_queue_skew +#define snd_seq_ev_queue_control sndrv_seq_ev_queue_control +#define snd_seq_client_t sndrv_seq_client_t +#define snd_seq_client_type_t sndrv_seq_client_type_t + +#include + +/* take back some renames */ +#undef snd_seq_client_t +#undef snd_seq_client_type_t + +#include "seqmid.h" +#include "seq_midi_event.h" +#include "list.h" + +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); +size_t snd_strlcpy(char *dst, const char *src, size_t size); + +/* + * 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__, __func__, 0, ##args) +#define SYSMSG(args...) snd_err_msg(__FILE__, __LINE__, __func__, 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_get2 \ + snd1_dlobj_cache_get2 +#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); +void *snd_dlobj_cache_get2(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); + +int _snd_conf_generic_id(const char *id); + +int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in, + int override, const char * const *default_include_path); + +/* convenience macros */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#ifdef INTERNAL +void *INTERNAL(snd_dlopen)(const char *name, int mode, char *errbuf, size_t errbuflen); +#endif + +#endif diff --git a/include/mixer.h b/include/mixer.h new file mode 100644 index 0000000..51b6f04 --- /dev/null +++ b/include/mixer.h @@ -0,0 +1,318 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 *)); +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); +int snd_mixer_selem_id_parse(snd_mixer_selem_id_t *dst, const char *str); + +/** \} */ + +/** \} */ + +#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..ea8c096 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..74ff78a --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..5b07823 --- /dev/null +++ b/include/pcm.h @@ -0,0 +1,1356 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ALSA_PCM_H +#define __ALSA_PCM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * \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 + * + * snd_pcm_hw_params_t is an opaque structure which contains a set of possible + * PCM hardware configurations. For example, a given instance might include a + * range of buffer sizes, a range of period sizes, and a set of several sample + * formats. Some subset of all possible combinations these sets may be valid, + * but not necessarily any combination will be valid. + * + * When a parameter is set or restricted using a snd_pcm_hw_params_set* + * function, all of the other ranges will be updated to exclude as many + * impossible configurations as possible. Attempting to set a parameter + * outside of its acceptable range will result in the function failing + * and an error code being returned. + */ +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, + /** Signed 20bit Little Endian in 4bytes format, LSB justified */ + SND_PCM_FORMAT_S20_LE, + /** Signed 20bit Big Endian in 4bytes format, LSB justified */ + SND_PCM_FORMAT_S20_BE, + /** Unsigned 20bit Little Endian in 4bytes format, LSB justified */ + SND_PCM_FORMAT_U20_LE, + /** Unsigned 20bit Big Endian in 4bytes format, LSB justified */ + SND_PCM_FORMAT_U20_BE, + /** 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, + /* G.723 (ADPCM) 24 kbit/s, 8 samples in 3 bytes */ + SND_PCM_FORMAT_G723_24, + /* G.723 (ADPCM) 24 kbit/s, 1 sample in 1 byte */ + SND_PCM_FORMAT_G723_24_1B, + /* G.723 (ADPCM) 40 kbit/s, 8 samples in 3 bytes */ + SND_PCM_FORMAT_G723_40, + /* G.723 (ADPCM) 40 kbit/s, 1 sample in 1 byte */ + SND_PCM_FORMAT_G723_40_1B, + /* Direct Stream Digital (DSD) in 1-byte samples (x8) */ + SND_PCM_FORMAT_DSD_U8, + /* Direct Stream Digital (DSD) in 2-byte samples (x16) */ + SND_PCM_FORMAT_DSD_U16_LE, + /* Direct Stream Digital (DSD) in 4-byte samples (x32) */ + SND_PCM_FORMAT_DSD_U32_LE, + /* Direct Stream Digital (DSD) in 2-byte samples (x16) */ + SND_PCM_FORMAT_DSD_U16_BE, + /* Direct Stream Digital (DSD) in 4-byte samples (x32) */ + SND_PCM_FORMAT_DSD_U32_BE, + SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_DSD_U32_BE, + +#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, + /** Signed 20bit in 4bytes format, LSB justified, CPU Endian */ + SND_PCM_FORMAT_S20 = SND_PCM_FORMAT_S20_LE, + /** Unsigned 20bit in 4bytes format, LSB justified, CPU Endian */ + SND_PCM_FORMAT_U20 = SND_PCM_FORMAT_U20_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, + /** Signed 20bit in 4bytes format, LSB justified, CPU Endian */ + SND_PCM_FORMAT_S20 = SND_PCM_FORMAT_S20_BE, + /** Unsigned 20bit in 4bytes format, LSB justified, CPU Endian */ + SND_PCM_FORMAT_U20 = SND_PCM_FORMAT_U20_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, + /** Private - used internally in the library - do not use*/ + SND_PCM_STATE_PRIVATE1 = 1024 +} 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; + +typedef enum _snd_pcm_tstamp_type { + SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /**< gettimeofday equivalent */ + SND_PCM_TSTAMP_TYPE_MONOTONIC, /**< posix_clock_monotonic equivalent */ + SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /**< monotonic_raw (no NTP) */ + SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, +} snd_pcm_tstamp_type_t; + +typedef struct _snd_pcm_audio_tstamp_config { + /* 5 of max 16 bits used */ + unsigned int type_requested:4; + unsigned int report_delay:1; /* add total delay to A/D or D/A */ +} snd_pcm_audio_tstamp_config_t; + +typedef struct _snd_pcm_audio_tstamp_report { + /* 6 of max 16 bits used for bit-fields */ + + /* for backwards compatibility */ + unsigned int valid:1; + + /* actual type if hardware could not support requested timestamp */ + unsigned int actual_type:4; + + /* accuracy represented in ns units */ + unsigned int accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */ + unsigned int accuracy; /* up to 4.29s, will be packed in separate field */ +} snd_pcm_audio_tstamp_report_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 +/** In an abort state (internal, not allowed for open) */ +#define SND_PCM_ABORT 0x00008000 +/** 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_open_fallback(snd_pcm_t **pcm, snd_config_t *root, + const char *name, const char *orig_name, + snd_pcm_stream_t stream, int mode); + +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); +static __inline__ int snd_pcm_abort(snd_pcm_t *pcm) { return snd_pcm_nonblock(pcm, 2); } +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); + +/** channel mapping API version number */ +#define SND_CHMAP_API_VERSION ((1 << 16) | (0 << 8) | 1) + +/** channel map list type */ +enum snd_pcm_chmap_type { + SND_CHMAP_TYPE_NONE = 0,/**< unspecified channel position */ + SND_CHMAP_TYPE_FIXED, /**< fixed channel position */ + SND_CHMAP_TYPE_VAR, /**< freely swappable channel position */ + SND_CHMAP_TYPE_PAIRED, /**< pair-wise swappable channel position */ + SND_CHMAP_TYPE_LAST = SND_CHMAP_TYPE_PAIRED, /**< last entry */ +}; + +/** channel positions */ +enum snd_pcm_chmap_position { + SND_CHMAP_UNKNOWN = 0, /**< unspecified */ + SND_CHMAP_NA, /**< N/A, silent */ + SND_CHMAP_MONO, /**< mono stream */ + SND_CHMAP_FL, /**< front left */ + SND_CHMAP_FR, /**< front right */ + SND_CHMAP_RL, /**< rear left */ + SND_CHMAP_RR, /**< rear right */ + SND_CHMAP_FC, /**< front center */ + SND_CHMAP_LFE, /**< LFE */ + SND_CHMAP_SL, /**< side left */ + SND_CHMAP_SR, /**< side right */ + SND_CHMAP_RC, /**< rear center */ + SND_CHMAP_FLC, /**< front left center */ + SND_CHMAP_FRC, /**< front right center */ + SND_CHMAP_RLC, /**< rear left center */ + SND_CHMAP_RRC, /**< rear right center */ + SND_CHMAP_FLW, /**< front left wide */ + SND_CHMAP_FRW, /**< front right wide */ + SND_CHMAP_FLH, /**< front left high */ + SND_CHMAP_FCH, /**< front center high */ + SND_CHMAP_FRH, /**< front right high */ + SND_CHMAP_TC, /**< top center */ + SND_CHMAP_TFL, /**< top front left */ + SND_CHMAP_TFR, /**< top front right */ + SND_CHMAP_TFC, /**< top front center */ + SND_CHMAP_TRL, /**< top rear left */ + SND_CHMAP_TRR, /**< top rear right */ + SND_CHMAP_TRC, /**< top rear center */ + SND_CHMAP_TFLC, /**< top front left center */ + SND_CHMAP_TFRC, /**< top front right center */ + SND_CHMAP_TSL, /**< top side left */ + SND_CHMAP_TSR, /**< top side right */ + SND_CHMAP_LLFE, /**< left LFE */ + SND_CHMAP_RLFE, /**< right LFE */ + SND_CHMAP_BC, /**< bottom center */ + SND_CHMAP_BLC, /**< bottom left center */ + SND_CHMAP_BRC, /**< bottom right center */ + SND_CHMAP_LAST = SND_CHMAP_BRC, +}; + +/** bitmask for channel position */ +#define SND_CHMAP_POSITION_MASK 0xffff + +/** bit flag indicating the channel is phase inverted */ +#define SND_CHMAP_PHASE_INVERSE (0x01 << 16) +/** bit flag indicating the non-standard channel value */ +#define SND_CHMAP_DRIVER_SPEC (0x02 << 16) + +/** the channel map header */ +typedef struct snd_pcm_chmap { + unsigned int channels; /**< number of channels */ + unsigned int pos[0]; /**< channel position array */ +} snd_pcm_chmap_t; + +/** the header of array items returned from snd_pcm_query_chmaps() */ +typedef struct snd_pcm_chmap_query { + enum snd_pcm_chmap_type type; /**< channel map type */ + snd_pcm_chmap_t map; /**< available channel map */ +} snd_pcm_chmap_query_t; + + +snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm); +snd_pcm_chmap_query_t **snd_pcm_query_chmaps_from_hw(int card, int dev, + int subdev, + snd_pcm_stream_t stream); +void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps); +snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm); +int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); + +const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val); +const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val); +const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val); +int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf); +unsigned int snd_pcm_chmap_from_string(const char *str); +snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str); + +//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_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params); /* deprecated, use audio_ts_type */ +int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type); +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_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val); +int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_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); +void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); +void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); +void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj, + snd_pcm_audio_tstamp_report_t *audio_tstamp_report); +void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj, + snd_pcm_audio_tstamp_config_t *audio_tstamp_config); + +static inline void snd_pcm_pack_audio_tstamp_config(unsigned int *data, + snd_pcm_audio_tstamp_config_t *config) +{ + *data = config->report_delay; + *data <<= 4; + *data |= config->type_requested; +} + +static inline void snd_pcm_unpack_audio_tstamp_report(unsigned int data, unsigned int accuracy, + snd_pcm_audio_tstamp_report_t *report) +{ + data >>= 16; + report->valid = data & 1; + report->actual_type = (data >> 1) & 0xF; + report->accuracy_report = (data >> 5) & 1; + report->accuracy = accuracy; +} + +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); +uint8_t snd_pcm_format_silence(snd_pcm_format_t format); +uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format); +uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format); +uint64_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); +int snd_pcm_areas_copy_wrap(const snd_pcm_channel_area_t *dst_channels, + snd_pcm_uframes_t dst_offset, + const snd_pcm_uframes_t dst_size, + const snd_pcm_channel_area_t *src_channels, + snd_pcm_uframes_t src_offset, + const snd_pcm_uframes_t src_size, + const unsigned int channels, + snd_pcm_uframes_t frames, + const 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..204a450 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..e5c02d4 --- /dev/null +++ b/include/pcm_extplug.h @@ -0,0 +1,208 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; +#ifdef DOC_HIDDEN +/* redefine typedefs for stupid doxygen */ +typedef snd_pcm_extplug snd_pcm_extplug_t; +typedef snd_pcm_extplug_callback snd_pcm_extplug_callback_t; +#endif + +/* + * 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 2 /**< 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); + /** + * query the channel maps; optional; since v1.0.2 + */ + snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_extplug_t *ext); + /** + * get the channel map; optional; since v1.0.2 + */ + snd_pcm_chmap_t *(*get_chmap)(snd_pcm_extplug_t *ext); + /** + * set the channel map; optional; since v1.0.2 + */ + int (*set_chmap)(snd_pcm_extplug_t *ext, const snd_pcm_chmap_t *map); +}; + + +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); +int snd_pcm_extplug_set_param_link(snd_pcm_extplug_t *extplug, int type, + int keep_link); + +/** + * 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..81ac861 --- /dev/null +++ b/include/pcm_ioplug.h @@ -0,0 +1,247 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; +#ifdef DOC_HIDDEN +/* redefine typedefs for stupid doxygen */ +typedef snd_pcm_ioplug snd_pcm_ioplug_t; +typedef snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; +#endif + +/* + * 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 */ +/** hw pointer wrap around at boundary instead of buffer_size */ +#define SND_PCM_IOPLUG_FLAG_BOUNDARY_WA (1<<2) + +/* + * 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 2 /**< 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_ioplug_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, called inside mutex lock + */ + int (*start)(snd_pcm_ioplug_t *io); + /** + * stop the PCM; required, called inside mutex lock + */ + int (*stop)(snd_pcm_ioplug_t *io); + /** + * get the current DMA position; required, called inside mutex lock + * \return buffer position up to buffer_size or + * when #SND_PCM_IOPLUG_FLAG_BOUNDARY_WA flag is set up to boundary or + * a negative error code for Xrun + */ + snd_pcm_sframes_t (*pointer)(snd_pcm_ioplug_t *io); + /** + * transfer the data; optional, called inside mutex lock + */ + 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, called inside mutex lock + */ + 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; since v1.0.1 + */ + int (*delay)(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp); + /** + * query the channel maps; optional; since v1.0.2 + */ + snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_ioplug_t *io); + /** + * get the channel map; optional; since v1.0.2 + */ + snd_pcm_chmap_t *(*get_chmap)(snd_pcm_ioplug_t *io); + /** + * set the channel map; optional; since v1.0.2 + */ + int (*set_chmap)(snd_pcm_ioplug_t *io, const snd_pcm_chmap_t *map); +}; + + +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); + +/* calucalte the available frames */ +snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr); +snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr); + +/** \} */ + +#endif /* __ALSA_PCM_IOPLUG_H */ diff --git a/include/pcm_old.h b/include/pcm_old.h new file mode 100644 index 0000000..e6e050f --- /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_get_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..2d01439 --- /dev/null +++ b/include/pcm_plugin.h @@ -0,0 +1,203 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __ALSA_PCM_PLUGIN_H +#define __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 768000 /**< 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..4171fb9 --- /dev/null +++ b/include/pcm_rate.h @@ -0,0 +1,156 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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); + +typedef int (*snd_pcm_rate_open_conf_func_t)(unsigned int version, void **objp, + snd_pcm_rate_ops_t *opsp, const snd_config_t *conf); + +/** + * Define the object entry for external PCM rate-converter plugins + */ +#define SND_PCM_RATE_PLUGIN_ENTRY(name) _snd_pcm_rate_##name##_open +#define SND_PCM_RATE_PLUGIN_CONF_ENTRY(name) _snd_pcm_rate_##name##_open_conf + +#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..d88c932 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..123a105 --- /dev/null +++ b/include/seq.h @@ -0,0 +1,739 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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); +int snd_seq_client_info_get_card(const snd_seq_client_info_t *info); +int snd_seq_client_info_get_pid(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..60727f5 --- /dev/null +++ b/include/seq_event.h @@ -0,0 +1,325 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 */ +struct snd_seq_ev_ext { + unsigned int len; /**< length of data */ + void *ptr; /**< pointer to data (note: can be 64-bit) */ +} __attribute__((packed)); +/** external stored data */ +typedef struct snd_seq_ev_ext snd_seq_ev_ext_t; +#ifdef DOC_HIDDEN +/* redefine typedef for stupid doxygen */ +typedef snd_seq_ev_ext snd_seq_ev_ext_t; +#endif + +/** 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..4cfb15c --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..3986628 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..99c4221 --- /dev/null +++ b/include/sound/Makefile.am @@ -0,0 +1,7 @@ +alsasoundincludedir = ${includedir}/alsa/sound + +alsasoundinclude_HEADERS = asound_fm.h hdsp.h hdspm.h sb16_csp.h \ + sscape_ioctl.h emu10k1.h type_compat.h \ + asoc.h tlv.h + +noinst_HEADERS = asound.h asequencer.h diff --git a/include/sound/Makefile.in b/include/sound/Makefile.in new file mode 100644 index 0000000..886bc88 --- /dev/null +++ b/include/sound/Makefile.in @@ -0,0 +1,580 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(alsasoundinclude_HEADERS) \ + $(noinst_HEADERS) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(alsasoundincludedir)" +HEADERS = $(alsasoundinclude_HEADERS) $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 \ + asoc.h tlv.h + +noinst_HEADERS = asound.h asequencer.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) + @list='$(alsasoundinclude_HEADERS)'; test -n "$(alsasoundincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(alsasoundincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(alsasoundincludedir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(alsasoundincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 -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 TAGS all all-am check check-am clean clean-generic \ + clean-libtool cscopelist-am ctags ctags-am 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 tags-am uninstall \ + uninstall-alsasoundincludeHEADERS uninstall-am + +.PRECIOUS: Makefile + + +# 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..a75e14e --- /dev/null +++ b/include/sound/asequencer.h @@ -0,0 +1,612 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * 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 _UAPI__SOUND_ASEQUENCER_H +#define _UAPI__SOUND_ASEQUENCER_H + +#include + +/** version of the sequencer */ +#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 2) + +/** + * definition of sequencer event types + */ + +/** system messages + * event data type = #snd_seq_result + */ +#define SNDRV_SEQ_EVENT_SYSTEM 0 +#define SNDRV_SEQ_EVENT_RESULT 1 + +/** note messages (channel specific) + * event data type = #snd_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 = #snd_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 = #snd_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 = snd_seq_ev_queue_control + */ +#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 = snd_seq_addr + */ +#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 = snd_seq_connect + */ +#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 = snd_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 snd_seq_event_type_t; + +/** event address */ +struct snd_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 snd_seq_connect { + struct snd_seq_addr sender; + struct snd_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 snd_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 snd_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 snd_seq_ev_raw8 { + unsigned char d[12]; /* 8 bit value */ +}; + + /* generic set of integers (3x32 bit) */ +struct snd_seq_ev_raw32 { + unsigned int d[3]; /* 32 bit value */ +}; + + /* external stored data */ +struct snd_seq_ev_ext { + unsigned int len; /* length of data */ + void *ptr; /* pointer to data (note: maybe 64-bit) */ +} __attribute__((packed)); + +struct snd_seq_result { + int event; /* processed event type */ + int result; +}; + + +struct snd_seq_real_time { + unsigned int tv_sec; /* seconds */ + unsigned int tv_nsec; /* nanoseconds */ +}; + +typedef unsigned int snd_seq_tick_time_t; /* midi ticks */ + +union snd_seq_timestamp { + snd_seq_tick_time_t tick; + struct snd_seq_real_time time; +}; + +struct snd_seq_queue_skew { + unsigned int value; + unsigned int base; +}; + + /* queue timer control */ +struct snd_seq_ev_queue_control { + unsigned char queue; /* affected queue */ + unsigned char pad[3]; /* reserved */ + union { + signed int value; /* affected value (e.g. tempo) */ + union snd_seq_timestamp time; /* time */ + unsigned int position; /* sync position */ + struct snd_seq_queue_skew skew; + unsigned int d32[2]; + unsigned char d8[8]; + } param; +}; + + /* quoted event - inside the kernel only */ +struct snd_seq_ev_quote { + struct snd_seq_addr origin; /* original sender */ + unsigned short value; /* optional data */ + struct snd_seq_event *event; /* quoted event */ +} __attribute__((packed)); + + + /* sequencer event */ +struct snd_seq_event { + snd_seq_event_type_t type; /* event type */ + unsigned char flags; /* event flags */ + char tag; + + unsigned char queue; /* schedule queue */ + union snd_seq_timestamp time; /* schedule time */ + + + struct snd_seq_addr source; /* source address */ + struct snd_seq_addr dest; /* destination address */ + + union { /* event data... */ + struct snd_seq_ev_note note; + struct snd_seq_ev_ctrl control; + struct snd_seq_ev_raw8 raw8; + struct snd_seq_ev_raw32 raw32; + struct snd_seq_ev_ext ext; + struct snd_seq_ev_queue_control queue; + union snd_seq_timestamp time; + struct snd_seq_addr addr; + struct snd_seq_connect connect; + struct snd_seq_result result; + struct snd_seq_ev_quote quote; + } data; +}; + + +/* + * bounce event - stored as variable size data + */ +struct snd_seq_event_bounce { + int err; + struct snd_seq_event event; + /* external data follows here. */ +}; + + + /* system information */ +struct snd_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 snd_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 */ +typedef int __bitwise snd_seq_client_type_t; +#define NO_CLIENT ((__force snd_seq_client_type_t) 0) +#define USER_CLIENT ((__force snd_seq_client_type_t) 1) +#define KERNEL_CLIENT ((__force snd_seq_client_type_t) 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 snd_seq_client_info { + int client; /* client number to inquire */ + snd_seq_client_type_t 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 */ + int card; /* RO: card number[kernel] */ + int pid; /* RO: pid[user] */ + char reserved[56]; /* for future use */ +}; + + +/* client pool size */ +struct snd_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 snd_seq_remove_events { + unsigned int remove_mode; /* Flags that determine what gets removed */ + + union snd_seq_timestamp time; + + unsigned char queue; /* Queue for REMOVE_DEST */ + struct snd_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 snd_seq_port_info { + struct snd_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 snd_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 */ + unsigned 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 snd_seq_queue_status { + int queue; /* queue id */ + int events; /* read-only - queue size */ + snd_seq_tick_time_t tick; /* current tick */ + struct snd_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 snd_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 snd_seq_queue_timer { + int queue; /* sequencer queue */ + int type; /* source timer type */ + union { + struct { + struct snd_timer_id id; /* ALSA's timer ID */ + unsigned int resolution; /* resolution in Hz */ + } alsa; + } u; + char reserved[64]; /* for the future use */ +}; + + +struct snd_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 snd_seq_port_subscribe { + struct snd_seq_addr sender; /* sender address */ + struct snd_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 snd_seq_query_subs { + struct snd_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 snd_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 snd_seq_system_info) +#define SNDRV_SEQ_IOCTL_RUNNING_MODE _IOWR('S', 0x03, struct snd_seq_running_info) + +#define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct snd_seq_client_info) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct snd_seq_client_info) + +#define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct snd_seq_port_info) +#define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct snd_seq_port_info) +#define SNDRV_SEQ_IOCTL_GET_PORT_INFO _IOWR('S', 0x22, struct snd_seq_port_info) +#define SNDRV_SEQ_IOCTL_SET_PORT_INFO _IOW ('S', 0x23, struct snd_seq_port_info) + +#define SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT _IOW ('S', 0x30, struct snd_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT _IOW ('S', 0x31, struct snd_seq_port_subscribe) + +#define SNDRV_SEQ_IOCTL_CREATE_QUEUE _IOWR('S', 0x32, struct snd_seq_queue_info) +#define SNDRV_SEQ_IOCTL_DELETE_QUEUE _IOW ('S', 0x33, struct snd_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_INFO _IOWR('S', 0x34, struct snd_seq_queue_info) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_INFO _IOWR('S', 0x35, struct snd_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE _IOWR('S', 0x36, struct snd_seq_queue_info) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS _IOWR('S', 0x40, struct snd_seq_queue_status) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO _IOWR('S', 0x41, struct snd_seq_queue_tempo) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO _IOW ('S', 0x42, struct snd_seq_queue_tempo) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER _IOWR('S', 0x45, struct snd_seq_queue_timer) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER _IOW ('S', 0x46, struct snd_seq_queue_timer) +#define SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT _IOWR('S', 0x49, struct snd_seq_queue_client) +#define SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT _IOW ('S', 0x4a, struct snd_seq_queue_client) +#define SNDRV_SEQ_IOCTL_GET_CLIENT_POOL _IOWR('S', 0x4b, struct snd_seq_client_pool) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_POOL _IOW ('S', 0x4c, struct snd_seq_client_pool) +#define SNDRV_SEQ_IOCTL_REMOVE_EVENTS _IOW ('S', 0x4e, struct snd_seq_remove_events) +#define SNDRV_SEQ_IOCTL_QUERY_SUBS _IOWR('S', 0x4f, struct snd_seq_query_subs) +#define SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION _IOWR('S', 0x50, struct snd_seq_port_subscribe) +#define SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT _IOWR('S', 0x51, struct snd_seq_client_info) +#define SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT _IOWR('S', 0x52, struct snd_seq_port_info) + +#endif /* _UAPI__SOUND_ASEQUENCER_H */ diff --git a/include/sound/asoc.h b/include/sound/asoc.h new file mode 100644 index 0000000..a74ca23 --- /dev/null +++ b/include/sound/asoc.h @@ -0,0 +1,633 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM + * + * Copyright (C) 2012 Texas Instruments Inc. + * Copyright (C) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Simple file API to load FW that includes mixers, coefficients, DAPM graphs, + * algorithms, equalisers, DAIs, widgets etc. +*/ + +#ifndef __LINUX_UAPI_SND_ASOC_H +#define __LINUX_UAPI_SND_ASOC_H + +#include +#include + +/* + * Maximum number of channels topology kcontrol can represent. + */ +#define SND_SOC_TPLG_MAX_CHAN 8 + +/* + * Maximum number of PCM formats capability + */ +#define SND_SOC_TPLG_MAX_FORMATS 16 + +/* + * Maximum number of PCM stream configs + */ +#define SND_SOC_TPLG_STREAM_CONFIG_MAX 8 + +/* + * Maximum number of physical link's hardware configs + */ +#define SND_SOC_TPLG_HW_CONFIG_MAX 8 + +/* individual kcontrol info types - can be mixed with other types */ +#define SND_SOC_TPLG_CTL_VOLSW 1 +#define SND_SOC_TPLG_CTL_VOLSW_SX 2 +#define SND_SOC_TPLG_CTL_VOLSW_XR_SX 3 +#define SND_SOC_TPLG_CTL_ENUM 4 +#define SND_SOC_TPLG_CTL_BYTES 5 +#define SND_SOC_TPLG_CTL_ENUM_VALUE 6 +#define SND_SOC_TPLG_CTL_RANGE 7 +#define SND_SOC_TPLG_CTL_STROBE 8 + + +/* individual widget kcontrol info types - can be mixed with other types */ +#define SND_SOC_TPLG_DAPM_CTL_VOLSW 64 +#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE 65 +#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT 66 +#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE 67 +#define SND_SOC_TPLG_DAPM_CTL_PIN 68 + +/* DAPM widget types - add new items to the end */ +#define SND_SOC_TPLG_DAPM_INPUT 0 +#define SND_SOC_TPLG_DAPM_OUTPUT 1 +#define SND_SOC_TPLG_DAPM_MUX 2 +#define SND_SOC_TPLG_DAPM_MIXER 3 +#define SND_SOC_TPLG_DAPM_PGA 4 +#define SND_SOC_TPLG_DAPM_OUT_DRV 5 +#define SND_SOC_TPLG_DAPM_ADC 6 +#define SND_SOC_TPLG_DAPM_DAC 7 +#define SND_SOC_TPLG_DAPM_SWITCH 8 +#define SND_SOC_TPLG_DAPM_PRE 9 +#define SND_SOC_TPLG_DAPM_POST 10 +#define SND_SOC_TPLG_DAPM_AIF_IN 11 +#define SND_SOC_TPLG_DAPM_AIF_OUT 12 +#define SND_SOC_TPLG_DAPM_DAI_IN 13 +#define SND_SOC_TPLG_DAPM_DAI_OUT 14 +#define SND_SOC_TPLG_DAPM_DAI_LINK 15 +#define SND_SOC_TPLG_DAPM_BUFFER 16 +#define SND_SOC_TPLG_DAPM_SCHEDULER 17 +#define SND_SOC_TPLG_DAPM_EFFECT 18 +#define SND_SOC_TPLG_DAPM_SIGGEN 19 +#define SND_SOC_TPLG_DAPM_SRC 20 +#define SND_SOC_TPLG_DAPM_ASRC 21 +#define SND_SOC_TPLG_DAPM_ENCODER 22 +#define SND_SOC_TPLG_DAPM_DECODER 23 +#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DECODER + +/* Header magic number and string sizes */ +#define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */ + +/* string sizes */ +#define SND_SOC_TPLG_NUM_TEXTS 16 + +/* ABI version */ +#define SND_SOC_TPLG_ABI_VERSION 0x5 /* current version */ +#define SND_SOC_TPLG_ABI_VERSION_MIN 0x4 /* oldest version supported */ + +/* Max size of TLV data */ +#define SND_SOC_TPLG_TLV_SIZE 32 + +/* + * File and Block header data types. + * Add new generic and vendor types to end of list. + * Generic types are handled by the core whilst vendors types are passed + * to the component drivers for handling. + */ +#define SND_SOC_TPLG_TYPE_MIXER 1 +#define SND_SOC_TPLG_TYPE_BYTES 2 +#define SND_SOC_TPLG_TYPE_ENUM 3 +#define SND_SOC_TPLG_TYPE_DAPM_GRAPH 4 +#define SND_SOC_TPLG_TYPE_DAPM_WIDGET 5 +#define SND_SOC_TPLG_TYPE_DAI_LINK 6 +#define SND_SOC_TPLG_TYPE_PCM 7 +#define SND_SOC_TPLG_TYPE_MANIFEST 8 +#define SND_SOC_TPLG_TYPE_CODEC_LINK 9 +#define SND_SOC_TPLG_TYPE_BACKEND_LINK 10 +#define SND_SOC_TPLG_TYPE_PDATA 11 +#define SND_SOC_TPLG_TYPE_DAI 12 +#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_DAI + +/* vendor block IDs - please add new vendor types to end */ +#define SND_SOC_TPLG_TYPE_VENDOR_FW 1000 +#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG 1001 +#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002 +#define SND_SOC_TPLG_TYPEVENDOR_CODEC 1003 + +#define SND_SOC_TPLG_STREAM_PLAYBACK 0 +#define SND_SOC_TPLG_STREAM_CAPTURE 1 + +/* vendor tuple types */ +#define SND_SOC_TPLG_TUPLE_TYPE_UUID 0 +#define SND_SOC_TPLG_TUPLE_TYPE_STRING 1 +#define SND_SOC_TPLG_TUPLE_TYPE_BOOL 2 +#define SND_SOC_TPLG_TUPLE_TYPE_BYTE 3 +#define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 +#define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5 + +/* DAI flags */ +#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES (1 << 0) +#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) +#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) + +/* DAI clock gating */ +#define SND_SOC_TPLG_DAI_CLK_GATE_UNDEFINED 0 +#define SND_SOC_TPLG_DAI_CLK_GATE_GATED 1 +#define SND_SOC_TPLG_DAI_CLK_GATE_CONT 2 + +/* DAI mclk_direction */ +#define SND_SOC_TPLG_MCLK_CO 0 /* for codec, mclk is output */ +#define SND_SOC_TPLG_MCLK_CI 1 /* for codec, mclk is input */ + +/* DAI physical PCM data formats. + * Add new formats to the end of the list. + */ +#define SND_SOC_DAI_FORMAT_I2S 1 /* I2S mode */ +#define SND_SOC_DAI_FORMAT_RIGHT_J 2 /* Right Justified mode */ +#define SND_SOC_DAI_FORMAT_LEFT_J 3 /* Left Justified mode */ +#define SND_SOC_DAI_FORMAT_DSP_A 4 /* L data MSB after FRM LRC */ +#define SND_SOC_DAI_FORMAT_DSP_B 5 /* L data MSB during FRM LRC */ +#define SND_SOC_DAI_FORMAT_AC97 6 /* AC97 */ +#define SND_SOC_DAI_FORMAT_PDM 7 /* Pulse density modulation */ + +/* left and right justified also known as MSB and LSB respectively */ +#define SND_SOC_DAI_FORMAT_MSB SND_SOC_DAI_FORMAT_LEFT_J +#define SND_SOC_DAI_FORMAT_LSB SND_SOC_DAI_FORMAT_RIGHT_J + +/* DAI link flags */ +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES (1 << 0) +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) +#define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) + +/* DAI topology BCLK parameter + * For the backwards capability, by default codec is bclk master + */ +#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */ +#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */ + +/* DAI topology FSYNC parameter + * For the backwards capability, by default codec is fsync master + */ +#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */ +#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */ + +/* + * Block Header. + * This header precedes all object and object arrays below. + */ +struct snd_soc_tplg_hdr { + __le32 magic; /* magic number */ + __le32 abi; /* ABI version */ + __le32 version; /* optional vendor specific version details */ + __le32 type; /* SND_SOC_TPLG_TYPE_ */ + __le32 size; /* size of this structure */ + __le32 vendor_type; /* optional vendor specific type info */ + __le32 payload_size; /* data bytes, excluding this header */ + __le32 index; /* identifier for block */ + __le32 count; /* number of elements in block */ +} __attribute__((packed)); + +/* vendor tuple for uuid */ +struct snd_soc_tplg_vendor_uuid_elem { + __le32 token; + char uuid[16]; +} __attribute__((packed)); + +/* vendor tuple for a bool/byte/short/word value */ +struct snd_soc_tplg_vendor_value_elem { + __le32 token; + __le32 value; +} __attribute__((packed)); + +/* vendor tuple for string */ +struct snd_soc_tplg_vendor_string_elem { + __le32 token; + char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +} __attribute__((packed)); + +struct snd_soc_tplg_vendor_array { + __le32 size; /* size in bytes of the array, including all elements */ + __le32 type; /* SND_SOC_TPLG_TUPLE_TYPE_ */ + __le32 num_elems; /* number of elements in array */ + union { + struct snd_soc_tplg_vendor_uuid_elem uuid[0]; + struct snd_soc_tplg_vendor_value_elem value[0]; + struct snd_soc_tplg_vendor_string_elem string[0]; + }; +} __attribute__((packed)); + +/* + * Private data. + * All topology objects may have private data that can be used by the driver or + * firmware. Core will ignore this data. + */ +struct snd_soc_tplg_private { + __le32 size; /* in bytes of private data */ + union { + char data[0]; + struct snd_soc_tplg_vendor_array array[0]; + }; +} __attribute__((packed)); + +/* + * Kcontrol TLV data. + */ +struct snd_soc_tplg_tlv_dbscale { + __le32 min; + __le32 step; + __le32 mute; +} __attribute__((packed)); + +struct snd_soc_tplg_ctl_tlv { + __le32 size; /* in bytes of this structure */ + __le32 type; /* SNDRV_CTL_TLVT_*, type of TLV */ + union { + __le32 data[SND_SOC_TPLG_TLV_SIZE]; + struct snd_soc_tplg_tlv_dbscale scale; + }; +} __attribute__((packed)); + +/* + * Kcontrol channel data + */ +struct snd_soc_tplg_channel { + __le32 size; /* in bytes of this structure */ + __le32 reg; + __le32 shift; + __le32 id; /* ID maps to Left, Right, LFE etc */ +} __attribute__((packed)); + +/* + * Genericl Operations IDs, for binding Kcontrol or Bytes ext ops + * Kcontrol ops need get/put/info. + * Bytes ext ops need get/put. + */ +struct snd_soc_tplg_io_ops { + __le32 get; + __le32 put; + __le32 info; +} __attribute__((packed)); + +/* + * kcontrol header + */ +struct snd_soc_tplg_ctl_hdr { + __le32 size; /* in bytes of this structure */ + __le32 type; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le32 access; + struct snd_soc_tplg_io_ops ops; + struct snd_soc_tplg_ctl_tlv tlv; +} __attribute__((packed)); + +/* + * Stream Capabilities + */ +struct snd_soc_tplg_stream_caps { + __le32 size; /* in bytes of this structure */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */ + __le32 rates; /* supported rates SNDRV_PCM_RATE_* */ + __le32 rate_min; /* min rate */ + __le32 rate_max; /* max rate */ + __le32 channels_min; /* min channels */ + __le32 channels_max; /* max channels */ + __le32 periods_min; /* min number of periods */ + __le32 periods_max; /* max number of periods */ + __le32 period_size_min; /* min period size bytes */ + __le32 period_size_max; /* max period size bytes */ + __le32 buffer_size_min; /* min buffer size bytes */ + __le32 buffer_size_max; /* max buffer size bytes */ + __le32 sig_bits; /* number of bits of content */ +} __attribute__((packed)); + +/* + * FE or BE Stream configuration supported by SW/FW + */ +struct snd_soc_tplg_stream { + __le32 size; /* in bytes of this structure */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* Name of the stream */ + __le64 format; /* SNDRV_PCM_FMTBIT_* */ + __le32 rate; /* SNDRV_PCM_RATE_* */ + __le32 period_bytes; /* size of period in bytes */ + __le32 buffer_bytes; /* size of buffer in bytes */ + __le32 channels; /* channels */ +} __attribute__((packed)); + + +/* + * Describes a physical link's runtime supported hardware config, + * i.e. hardware audio formats. + */ +struct snd_soc_tplg_hw_config { + __le32 size; /* in bytes of this structure */ + __le32 id; /* unique ID - - used to match */ + __le32 fmt; /* SND_SOC_DAI_FORMAT_ format value */ + __u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ + __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ + __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ + __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ + __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + __u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ + __le16 reserved; /* for 32bit alignment */ + __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ + __le32 bclk_rate; /* BCLK freqency in Hz */ + __le32 fsync_rate; /* frame clock in Hz */ + __le32 tdm_slots; /* number of TDM slots in use */ + __le32 tdm_slot_width; /* width in bits for each slot */ + __le32 tx_slots; /* bit mask for active Tx slots */ + __le32 rx_slots; /* bit mask for active Rx slots */ + __le32 tx_channels; /* number of Tx channels */ + __le32 tx_chanmap[SND_SOC_TPLG_MAX_CHAN]; /* array of slot number */ + __le32 rx_channels; /* number of Rx channels */ + __le32 rx_chanmap[SND_SOC_TPLG_MAX_CHAN]; /* array of slot number */ +} __attribute__((packed)); + +/* + * Manifest. List totals for each payload type. Not used in parsing, but will + * be passed to the component driver before any other objects in order for any + * global component resource allocations. + * + * File block representation for manifest :- + * +-----------------------------------+----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+----+ + * | struct snd_soc_tplg_manifest | 1 | + * +-----------------------------------+----+ + */ +struct snd_soc_tplg_manifest { + __le32 size; /* in bytes of this structure */ + __le32 control_elems; /* number of control elements */ + __le32 widget_elems; /* number of widget elements */ + __le32 graph_elems; /* number of graph elements */ + __le32 pcm_elems; /* number of PCM elements */ + __le32 dai_link_elems; /* number of DAI link elements */ + __le32 dai_elems; /* number of physical DAI elements */ + __le32 reserved[20]; /* reserved for new ABI element types */ + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + +/* + * Mixer kcontrol. + * + * File block representation for mixer kcontrol :- + * +-----------------------------------+----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+----+ + * | struct snd_soc_tplg_mixer_control | N | + * +-----------------------------------+----+ + */ +struct snd_soc_tplg_mixer_control { + struct snd_soc_tplg_ctl_hdr hdr; + __le32 size; /* in bytes of this structure */ + __le32 min; + __le32 max; + __le32 platform_max; + __le32 invert; + __le32 num_channels; + struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN]; + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + +/* + * Enumerated kcontrol + * + * File block representation for enum kcontrol :- + * +-----------------------------------+----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+----+ + * | struct snd_soc_tplg_enum_control | N | + * +-----------------------------------+----+ + */ +struct snd_soc_tplg_enum_control { + struct snd_soc_tplg_ctl_hdr hdr; + __le32 size; /* in bytes of this structure */ + __le32 num_channels; + struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN]; + __le32 items; + __le32 mask; + __le32 count; + char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4]; + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + +/* + * Bytes kcontrol + * + * File block representation for bytes kcontrol :- + * +-----------------------------------+----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+----+ + * | struct snd_soc_tplg_bytes_control | N | + * +-----------------------------------+----+ + */ +struct snd_soc_tplg_bytes_control { + struct snd_soc_tplg_ctl_hdr hdr; + __le32 size; /* in bytes of this structure */ + __le32 max; + __le32 mask; + __le32 base; + __le32 num_regs; + struct snd_soc_tplg_io_ops ext_ops; + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + +/* + * DAPM Graph Element + * + * File block representation for DAPM graph elements :- + * +-------------------------------------+----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-------------------------------------+----+ + * | struct snd_soc_tplg_dapm_graph_elem | N | + * +-------------------------------------+----+ + */ +struct snd_soc_tplg_dapm_graph_elem { + char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +} __attribute__((packed)); + +/* + * DAPM Widget. + * + * File block representation for DAPM widget :- + * +-------------------------------------+-----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-------------------------------------+-----+ + * | struct snd_soc_tplg_dapm_widget | N | + * +-------------------------------------+-----+ + * | struct snd_soc_tplg_enum_control | 0|1 | + * | struct snd_soc_tplg_mixer_control | 0|N | + * +-------------------------------------+-----+ + * + * Optional enum or mixer control can be appended to the end of each widget + * in the block. + */ +struct snd_soc_tplg_dapm_widget { + __le32 size; /* in bytes of this structure */ + __le32 id; /* SND_SOC_DAPM_CTL */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + __le32 reg; /* negative reg = no direct dapm */ + __le32 shift; /* bits to shift */ + __le32 mask; /* non-shifted mask */ + __le32 subseq; /* sort within widget type */ + __le32 invert; /* invert the power bit */ + __le32 ignore_suspend; /* kept enabled over suspend */ + __le16 event_flags; + __le16 event_type; + __le32 num_kcontrols; + struct snd_soc_tplg_private priv; + /* + * kcontrols that relate to this widget + * follow here after widget private data + */ +} __attribute__((packed)); + + +/* + * Describes SW/FW specific features of PCM (FE DAI & DAI link). + * + * File block representation for PCM :- + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_pcm | N | + * +-----------------------------------+-----+ + */ +struct snd_soc_tplg_pcm { + __le32 size; /* in bytes of this structure */ + char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le32 pcm_id; /* unique ID - used to match with DAI link */ + __le32 dai_id; /* unique ID - used to match */ + __le32 playback; /* supports playback mode */ + __le32 capture; /* supports capture mode */ + __le32 compress; /* 1 = compressed; 0 = PCM */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ + __le32 num_streams; /* number of streams */ + struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + + +/* + * Describes the physical link runtime supported configs or params + * + * File block representation for physical link config :- + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_link_config | N | + * +-----------------------------------+-----+ + */ +struct snd_soc_tplg_link_config { + __le32 size; /* in bytes of this structure */ + __le32 id; /* unique ID - used to match */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ + char stream_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* stream name - used to match */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ + __le32 num_streams; /* number of streams */ + struct snd_soc_tplg_hw_config hw_config[SND_SOC_TPLG_HW_CONFIG_MAX]; /* hw configs */ + __le32 num_hw_configs; /* number of hw configs */ + __le32 default_hw_config_id; /* default hw config ID for init */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + +/* + * Describes SW/FW specific features of physical DAI. + * It can be used to configure backend DAIs for DPCM. + * + * File block representation for physical DAI :- + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_hdr | 1 | + * +-----------------------------------+-----+ + * | struct snd_soc_tplg_dai | N | + * +-----------------------------------+-----+ + */ +struct snd_soc_tplg_dai { + __le32 size; /* in bytes of this structure */ + char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ + __le32 dai_id; /* unique ID - used to match */ + __le32 playback; /* supports playback mode */ + __le32 capture; /* supports capture mode */ + struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_DAI_FLGBIT_* */ + struct snd_soc_tplg_private priv; +} __attribute__((packed)); + +/* + * Old version of ABI structs, supported for backward compatibility. + */ + +/* Manifest v4 */ +struct snd_soc_tplg_manifest_v4 { + __le32 size; /* in bytes of this structure */ + __le32 control_elems; /* number of control elements */ + __le32 widget_elems; /* number of widget elements */ + __le32 graph_elems; /* number of graph elements */ + __le32 pcm_elems; /* number of PCM elements */ + __le32 dai_link_elems; /* number of DAI link elements */ + struct snd_soc_tplg_private priv; +} __packed; + +/* Stream Capabilities v4 */ +struct snd_soc_tplg_stream_caps_v4 { + __le32 size; /* in bytes of this structure */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */ + __le32 rates; /* supported rates SNDRV_PCM_RATE_* */ + __le32 rate_min; /* min rate */ + __le32 rate_max; /* max rate */ + __le32 channels_min; /* min channels */ + __le32 channels_max; /* max channels */ + __le32 periods_min; /* min number of periods */ + __le32 periods_max; /* max number of periods */ + __le32 period_size_min; /* min period size bytes */ + __le32 period_size_max; /* max period size bytes */ + __le32 buffer_size_min; /* min buffer size bytes */ + __le32 buffer_size_max; /* max buffer size bytes */ +} __packed; + +/* PCM v4 */ +struct snd_soc_tplg_pcm_v4 { + __le32 size; /* in bytes of this structure */ + char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le32 pcm_id; /* unique ID - used to match with DAI link */ + __le32 dai_id; /* unique ID - used to match */ + __le32 playback; /* supports playback mode */ + __le32 capture; /* supports capture mode */ + __le32 compress; /* 1 = compressed; 0 = PCM */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ + __le32 num_streams; /* number of streams */ + struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */ +} __packed; + +/* Physical link config v4 */ +struct snd_soc_tplg_link_config_v4 { + __le32 size; /* in bytes of this structure */ + __le32 id; /* unique ID - used to match */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ + __le32 num_streams; /* number of streams */ +} __packed; + +#endif diff --git a/include/sound/asound.h b/include/sound/asound.h new file mode 100644 index 0000000..df1153c --- /dev/null +++ b/include/sound/asound.h @@ -0,0 +1,1038 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * 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 _UAPI__SOUND_ASOUND_H +#define _UAPI__SOUND_ASOUND_H + +#if defined(__KERNEL__) || defined(__linux__) +#include +#else +#include +#endif + +#ifndef __KERNEL__ +#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 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 */ +}; + +/**************************************************************************** + * * + * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort * + * * + ****************************************************************************/ + +struct snd_cea_861_aud_if { + unsigned char db1_ct_cc; /* coding type and channel count */ + unsigned char db2_sf_ss; /* sample frequency and size */ + unsigned char db3; /* not used, all zeros */ + unsigned char db4_ca; /* channel allocation code */ + unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */ +}; + +/**************************************************************************** + * * + * Section for driver hardware dependent interface - /dev/snd/hw? * + * * + ****************************************************************************/ + +#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +enum { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, /* 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 */ + SNDRV_HWDEP_IFACE_HDA, /* HD-audio */ + SNDRV_HWDEP_IFACE_USB_STREAM, /* direct access to usb stream */ + SNDRV_HWDEP_IFACE_FW_DICE, /* TC DICE FireWire device */ + SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */ + SNDRV_HWDEP_IFACE_FW_BEBOB, /* BridgeCo BeBoB based device */ + SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */ + SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ + SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ + SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */ + SNDRV_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */ + SNDRV_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ + + /* Don't forget to change the following: */ + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE +}; + +struct snd_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 snd_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 snd_hwdep_dsp_image { + unsigned int index; /* W: DSP index */ + unsigned char name[64]; /* W: ID (e.g. file name) */ + unsigned char __user *image; /* W: binary image */ + size_t length; /* W: size of image in bytes */ + unsigned long driver_data; /* W: driver-specific data */ +}; + +#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) +#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info) +#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status) +#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image) + +/***************************************************************************** + * * + * Digital Audio (PCM) interface - /dev/snd/pcm?? * + * * + *****************************************************************************/ + +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) + +typedef unsigned long snd_pcm_uframes_t; +typedef signed long snd_pcm_sframes_t; + +enum { + SNDRV_PCM_CLASS_GENERIC = 0, /* 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_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_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +typedef int __bitwise snd_pcm_access_t; +#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) /* interleaved mmap */ +#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) /* noninterleaved mmap */ +#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) /* complex mmap */ +#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) /* readi/writei */ +#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) /* readn/writen */ +#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED + +typedef int __bitwise snd_pcm_format_t; +#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) +#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) +#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) +#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) +#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) +#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) +#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) /* low three bytes */ +#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */ +#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */ +#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */ +#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) +#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) +#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) +#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) +#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */ +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */ +#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) +#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) +#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) +#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) +#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) +#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */ +/* gap in the numbering for a future standard linear format */ +#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) +#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) /* in three bytes */ +#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */ +#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */ +#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */ +#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ +#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ +#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ +#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ +#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ +#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ +#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */ +#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */ +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE +#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8 + +#ifdef SNDRV_LITTLE_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_LE +#endif +#ifdef SNDRV_BIG_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE +#endif + +typedef int __bitwise snd_pcm_subformat_t; +#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD + +#define SNDRV_PCM_INFO_MMAP 0x00000001 /* 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_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ +#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 */ +#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ +#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ + +#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ +#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ + + + +typedef int __bitwise snd_pcm_state_t; +#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ +#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ +#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */ +#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) /* stream is running */ +#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) /* stream reached an xrun */ +#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */ +#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) /* stream is paused */ +#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */ +#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */ +#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, +}; + +union snd_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct snd_pcm_info { + unsigned int device; /* RO/WR (control): device number */ + unsigned int subdevice; /* RO/WR (control): subdevice number */ + int stream; /* RO/WR (control): stream direction */ + 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 snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char reserved[64]; /* reserved for future... */ +}; + +typedef int snd_pcm_hw_param_t; +#define SNDRV_PCM_HW_PARAM_ACCESS 0 /* Access type */ +#define SNDRV_PCM_HW_PARAM_FORMAT 1 /* Format */ +#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2 /* Subformat */ +#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS +#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT + +#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8 /* Bits per sample */ +#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9 /* Bits per frame */ +#define SNDRV_PCM_HW_PARAM_CHANNELS 10 /* Channels */ +#define SNDRV_PCM_HW_PARAM_RATE 11 /* Approx rate */ +#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12 /* Approx distance between + * interrupts in us + */ +#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13 /* Approx frames between + * interrupts + */ +#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14 /* Approx bytes between + * interrupts + */ +#define SNDRV_PCM_HW_PARAM_PERIODS 15 /* Approx interrupts per + * buffer + */ +#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16 /* Approx duration of buffer + * in us + */ +#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17 /* Size of buffer in frames */ +#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18 /* Size of buffer in bytes */ +#define SNDRV_PCM_HW_PARAM_TICK_TIME 19 /* Approx tick duration in us */ +#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS +#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME + +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* 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 snd_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +#define SNDRV_MASK_MAX 256 + +struct snd_mask { + __u32 bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct snd_pcm_hw_params { + unsigned int flags; + struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct snd_mask mres[5]; /* reserved masks */ + struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct snd_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 */ + snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ + unsigned char reserved[64]; /* reserved for future */ +}; + +enum { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_ENABLE, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, +}; + +struct snd_pcm_sw_params { + int tstamp_mode; /* timestamp mode */ + unsigned int period_step; + unsigned int sleep_min; /* min ticks to sleep */ + snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */ + snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ + snd_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */ + snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */ + snd_pcm_uframes_t silence_size; /* silence block size */ + snd_pcm_uframes_t boundary; /* pointers wrap point */ + unsigned int proto; /* protocol version */ + unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */ + unsigned char reserved[56]; /* reserved for future */ +}; + +struct snd_pcm_channel_info { + unsigned int channel; + __kernel_off_t offset; /* mmap offset */ + unsigned int first; /* offset to first sample in bits */ + unsigned int step; /* samples distance in bits */ +}; + +enum { + /* + * first definition for backwards compatibility only, + * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else + */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + + /* timestamp definitions */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +}; + +struct snd_pcm_status { + snd_pcm_state_t state; /* stream state */ + struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ + struct timespec tstamp; /* reference timestamp */ + snd_pcm_uframes_t appl_ptr; /* appl ptr */ + snd_pcm_uframes_t hw_ptr; /* hw ptr */ + snd_pcm_sframes_t delay; /* current delay in frames */ + snd_pcm_uframes_t avail; /* number of frames available */ + snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ + snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ + snd_pcm_state_t suspended_state; /* suspended stream state */ + __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ + struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ + struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ + __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ + unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ +}; + +struct snd_pcm_mmap_status { + snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ + int pad1; /* Needed for 64 bit alignment */ + snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ + struct timespec tstamp; /* Timestamp */ + snd_pcm_state_t suspended_state; /* RO: suspended stream state */ + struct timespec audio_tstamp; /* from sample counter or wall clock */ +}; + +struct snd_pcm_mmap_control { + snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ + snd_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 snd_pcm_sync_ptr { + unsigned int flags; + union { + struct snd_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct snd_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +struct snd_xferi { + snd_pcm_sframes_t result; + void __user *buf; + snd_pcm_uframes_t frames; +}; + +struct snd_xfern { + snd_pcm_sframes_t result; + void __user * __user *bufs; + snd_pcm_uframes_t frames; +}; + +enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, /* posix_clock_monotonic equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /* monotonic_raw (no NTP) */ + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, +}; + +/* channel positions */ +enum { + SNDRV_CHMAP_UNKNOWN = 0, + SNDRV_CHMAP_NA, /* N/A, silent */ + SNDRV_CHMAP_MONO, /* mono stream */ + /* this follows the alsa-lib mixer channel value + 3 */ + SNDRV_CHMAP_FL, /* front left */ + SNDRV_CHMAP_FR, /* front right */ + SNDRV_CHMAP_RL, /* rear left */ + SNDRV_CHMAP_RR, /* rear right */ + SNDRV_CHMAP_FC, /* front center */ + SNDRV_CHMAP_LFE, /* LFE */ + SNDRV_CHMAP_SL, /* side left */ + SNDRV_CHMAP_SR, /* side right */ + SNDRV_CHMAP_RC, /* rear center */ + /* new definitions */ + SNDRV_CHMAP_FLC, /* front left center */ + SNDRV_CHMAP_FRC, /* front right center */ + SNDRV_CHMAP_RLC, /* rear left center */ + SNDRV_CHMAP_RRC, /* rear right center */ + SNDRV_CHMAP_FLW, /* front left wide */ + SNDRV_CHMAP_FRW, /* front right wide */ + SNDRV_CHMAP_FLH, /* front left high */ + SNDRV_CHMAP_FCH, /* front center high */ + SNDRV_CHMAP_FRH, /* front right high */ + SNDRV_CHMAP_TC, /* top center */ + SNDRV_CHMAP_TFL, /* top front left */ + SNDRV_CHMAP_TFR, /* top front right */ + SNDRV_CHMAP_TFC, /* top front center */ + SNDRV_CHMAP_TRL, /* top rear left */ + SNDRV_CHMAP_TRR, /* top rear right */ + SNDRV_CHMAP_TRC, /* top rear center */ + /* new definitions for UAC2 */ + SNDRV_CHMAP_TFLC, /* top front left center */ + SNDRV_CHMAP_TFRC, /* top front right center */ + SNDRV_CHMAP_TSL, /* top side left */ + SNDRV_CHMAP_TSR, /* top side right */ + SNDRV_CHMAP_LLFE, /* left LFE */ + SNDRV_CHMAP_RLFE, /* right LFE */ + SNDRV_CHMAP_BC, /* bottom center */ + SNDRV_CHMAP_BLC, /* bottom left center */ + SNDRV_CHMAP_BRC, /* bottom right center */ + SNDRV_CHMAP_LAST = SNDRV_CHMAP_BRC, +}; + +#define SNDRV_CHMAP_POSITION_MASK 0xffff +#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) +#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) + +#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) +#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) +#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) +#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) +#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params) +#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) +#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) +#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) +#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) +#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) +#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) +#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) +#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) +#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) +#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) +#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi) +#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi) +#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern) +#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern) +#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) +#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) + +/***************************************************************************** + * * + * MIDI v1.0 interface * + * * + *****************************************************************************/ + +/* + * Raw MIDI section - /dev/snd/midi?? + */ + +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) + +enum { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 +#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 +#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 + +struct snd_rawmidi_info { + unsigned int device; /* 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 snd_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 snd_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 */ +}; + +#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) +#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) +#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) +#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) +#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) +#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) + +/* + * Timer section - /dev/snd/timer + */ + +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +enum { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +/* slave timer classes */ +enum { + 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 /* unused */ +#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 snd_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct snd_timer_ginfo { + struct snd_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 snd_timer_gparams { + struct snd_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 snd_timer_gstatus { + struct snd_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 snd_timer_select { + struct snd_timer_id id; /* bind to timer ID */ + unsigned char reserved[32]; /* reserved */ +}; + +struct snd_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 snd_timer_params { + unsigned int flags; /* flags - SNDRV_TIMER_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 snd_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 */ +}; + +#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) +#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) +#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) +#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) +#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) +#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select) +#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info) +#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params) +#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status) +/* The following four ioctls are changed since 1.0.9 due to confliction */ +#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) +#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) +#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) +#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) + +struct snd_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum { + SNDRV_TIMER_EVENT_RESOLUTION = 0, /* 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 snd_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, 7) + +struct snd_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..) */ +}; + +typedef int __bitwise snd_ctl_elem_type_t; +#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) /* invalid */ +#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) /* boolean type */ +#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) /* integer type */ +#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) /* enumerated type */ +#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) /* byte array */ +#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */ +#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */ +#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 + +typedef int __bitwise snd_ctl_elem_iface_t; +#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */ +#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */ +#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */ +#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */ +#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */ +#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */ +#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */ +#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER + +#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) +#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) +#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* 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 possible */ +#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */ +#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) /* kernel use a TLV callback */ +#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 */ + +#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 + +struct snd_ctl_elem_id { + unsigned int numid; /* numeric identifier, zero = invalid */ + snd_ctl_elem_iface_t iface; /* interface identifier */ + unsigned int device; /* device/client number */ + unsigned int subdevice; /* subdevice (substream) number */ + unsigned char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* ASCII name of item */ + unsigned int index; /* index of item */ +}; + +struct snd_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 snd_ctl_elem_id __user *pids; /* R: IDs */ + unsigned char reserved[50]; +}; + +struct snd_ctl_elem_info { + struct snd_ctl_elem_id id; /* W: element ID */ + snd_ctl_elem_type_t 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 */ + __kernel_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 */ + __u64 names_ptr; /* W: names list (ELEM_ADD only) */ + unsigned int names_length; + } enumerated; + unsigned char reserved[128]; + } value; + union { + unsigned short d[4]; /* dimensions */ + unsigned short *d_ptr; /* indirect - obsoleted */ + } dimen; + unsigned char reserved[64-4*sizeof(unsigned short)]; +}; + +struct snd_ctl_elem_value { + struct snd_ctl_elem_id id; /* W: element ID */ + unsigned int indirect: 1; /* W: indirect access - obsoleted */ + union { + union { + long value[128]; + long *value_ptr; /* obsoleted */ + } integer; + union { + long long value[64]; + long long *value_ptr; /* obsoleted */ + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; /* obsoleted */ + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; /* obsoleted */ + } bytes; + struct snd_aes_iec958 iec958; + } value; /* RO */ + struct timespec tstamp; + unsigned char reserved[128-sizeof(struct timespec)]; +}; + +struct snd_ctl_tlv { + unsigned int numid; /* control element numeric identification */ + unsigned int length; /* in bytes aligned to 4 */ + unsigned int tlv[0]; /* first TLV */ +}; + +#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) +#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) +#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) +#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) +#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) +#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info) +#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) +#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info) +#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) +#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) +#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) + +/* + * 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_TLV (1<<3) /* element TLV tree was changed */ +#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */ + +struct snd_ctl_event { + int type; /* event type - SNDRV_CTL_EVENT_* */ + union { + struct { + unsigned int mask; + struct snd_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 + +#endif /* _UAPI__SOUND_ASOUND_H */ diff --git a/include/sound/asound_fm.h b/include/sound/asound_fm.h new file mode 100644 index 0000000..8471f40 --- /dev/null +++ b/include/sound/asound_fm.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#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/emu10k1.h b/include/sound/emu10k1.h new file mode 100644 index 0000000..042c5a6 --- /dev/null +++ b/include/sound/emu10k1.h @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * 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 + * + */ +#ifndef _UAPI__SOUND_EMU10K1_H +#define _UAPI__SOUND_EMU10K1_H + +#include +#include + +/* + * ---- FX8010 ---- + */ + +#define EMU10K1_CARD_CREATIVE 0x00000000 +#define EMU10K1_CARD_EMUAPS 0x00000001 + +#define EMU10K1_FX8010_PCM_COUNT 8 + +/* + * Following definition is copied from linux/types.h to support compiling + * this header file in userspace since they are not generally available for + * uapi headers. + */ +#define __EMU10K1_DECLARE_BITMAP(name,bits) \ + unsigned long name[(bits) / (sizeof(unsigned long) * 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 physical outs -> FXWC low 16 bits */ +#define FXBUS2(x) (0x30 + (x)) /* x = 0x00 - 0x0f copies of fx buses for capture -> FXWC high 16 bits */ + /* NB: 0x31 and 0x32 are shared with Center/LFE on SB live 5.1 */ + +#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_ITRAM_DATA(x) (TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ +#define A_ETRAM_DATA(x) (TANKMEMDATAREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */ +#define A_ITRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ +#define A_ETRAM_ADDR(x) (TANKMEMADDRREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */ +#define A_ITRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ +#define A_ETRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */ + +#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f FX buses */ +#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x0f physical ins */ +#define A_P16VIN(x) (0x50 + (x)) /* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */ +#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown */ +#define A_FXBUS2(x) (0x80 + (x)) /* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */ +#define A_EMU32OUTH(x) (0xa0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */ +#define A_EMU32OUTL(x) (0xb0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */ +#define A3_EMU32IN(x) (0x160 + (x)) /* x = 0x00 - 0x3f "EMU32_IN_00 - _3F" - Only when .device = 0x0008 */ +#define A3_EMU32OUT(x) (0x1E0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_00 - _3F" - Only when .device = 0x0008 */ +#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 + +struct snd_emu10k1_fx8010_info { + 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 */ +}; + +#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 + +struct snd_emu10k1_fx8010_control_gpr { + struct snd_ctl_elem_id 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*) */ + const unsigned int *tlv; +}; + +/* old ABI without TLV support */ +struct snd_emu10k1_fx8010_control_old_gpr { + struct snd_ctl_elem_id id; + unsigned int vcount; + unsigned int count; + unsigned short gpr[32]; + unsigned int value[32]; + unsigned int min; + unsigned int max; + unsigned int translation; +}; + +struct snd_emu10k1_fx8010_code { + char name[128]; + + __EMU10K1_DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */ + __u32 __user *gpr_map; /* initializers */ + + unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */ + struct snd_emu10k1_fx8010_control_gpr __user *gpr_add_controls; /* GPR controls to add/replace */ + + unsigned int gpr_del_control_count; /* count of GPR controls to remove */ + struct snd_ctl_elem_id __user *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 */ + struct snd_emu10k1_fx8010_control_gpr __user *gpr_list_controls; /* listed GPR controls */ + + __EMU10K1_DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */ + __u32 __user *tram_data_map; /* data initializers */ + __u32 __user *tram_addr_map; /* map initializers */ + + __EMU10K1_DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */ + __u32 __user *code; /* one instruction - 64 bits */ +}; + +struct snd_emu10k1_fx8010_tram { + 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 */ +}; + +struct snd_emu10k1_fx8010_pcm_rec { + 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 */ +}; + +#define SNDRV_EMU10K1_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, struct snd_emu10k1_fx8010_info) +#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, struct snd_emu10k1_fx8010_code) +#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, struct snd_emu10k1_fx8010_code) +#define SNDRV_EMU10K1_IOCTL_TRAM_SETUP _IOW ('H', 0x20, int) +#define SNDRV_EMU10K1_IOCTL_TRAM_POKE _IOW ('H', 0x21, struct snd_emu10k1_fx8010_tram) +#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram) +#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec) +#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec) +#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) + +/* typedefs for compatibility to user-space */ +typedef struct snd_emu10k1_fx8010_info emu10k1_fx8010_info_t; +typedef struct snd_emu10k1_fx8010_control_gpr emu10k1_fx8010_control_gpr_t; +typedef struct snd_emu10k1_fx8010_code emu10k1_fx8010_code_t; +typedef struct snd_emu10k1_fx8010_tram emu10k1_fx8010_tram_t; +typedef struct snd_emu10k1_fx8010_pcm_rec emu10k1_fx8010_pcm_t; + +#endif /* _UAPI__SOUND_EMU10K1_H */ diff --git a/include/sound/hdsp.h b/include/sound/hdsp.h new file mode 100644 index 0000000..5dc0c3d --- /dev/null +++ b/include/sound/hdsp.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#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 + +enum HDSP_IO_Type { + Digiface, + Multiface, + H9652, + H9632, + RPM, + Undefined, +}; + +struct hdsp_peak_rms { + __u32 input_peaks[26]; + __u32 playback_peaks[26]; + __u32 output_peaks[28]; + __u64 input_rms[26]; + __u64 playback_rms[26]; + /* These are only used for H96xx cards */ + __u64 output_rms[26]; +}; + +#define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct hdsp_peak_rms) + +struct 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, struct hdsp_config_info) + +struct hdsp_firmware { + void __user *firmware_data; /* 24413 x 4 bytes */ +}; + +#define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, struct hdsp_firmware) + +struct hdsp_version { + enum HDSP_IO_Type io_type; + unsigned short firmware_rev; +}; + +#define SNDRV_HDSP_IOCTL_GET_VERSION _IOR('H', 0x43, struct hdsp_version) + +struct hdsp_mixer { + unsigned short matrix[HDSP_MATRIX_MIXER_SIZE]; +}; + +#define SNDRV_HDSP_IOCTL_GET_MIXER _IOR('H', 0x44, struct hdsp_mixer) + +struct hdsp_9632_aeb { + int aebi; + int aebo; +}; + +#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, struct hdsp_9632_aeb) + +/* typedefs for compatibility to user-space */ +typedef enum HDSP_IO_Type HDSP_IO_Type; +typedef struct hdsp_peak_rms hdsp_peak_rms_t; +typedef struct hdsp_config_info hdsp_config_info_t; +typedef struct hdsp_firmware hdsp_firmware_t; +typedef struct hdsp_version hdsp_version_t; +typedef struct hdsp_mixer hdsp_mixer_t; +typedef struct hdsp_9632_aeb 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..a38f3f7 --- /dev/null +++ b/include/sound/hdspm.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#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. + */ + +#include + +/* 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 { + __u32 input_peaks[64]; + __u32 playback_peaks[64]; + __u32 output_peaks[64]; + + __u64 input_rms[64]; + __u64 playback_rms[64]; + __u64 output_rms[64]; + + __u8 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_ltc) + +/* + * 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 { + __u8 card_type; /* enum hdspm_io_type */ + enum hdspm_syncsource autosync_source; + + __u64 card_clock; + __u32 master_period; + + union { + struct { + __u8 sync_wc; /* enum hdspm_sync */ + __u8 sync_madi; /* enum hdspm_sync */ + __u8 sync_tco; /* enum hdspm_sync */ + __u8 sync_in; /* enum hdspm_sync */ + __u8 madi_input; /* enum hdspm_madi_input */ + __u8 channel_format; /* enum hdspm_madi_channel_format */ + __u8 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 { + __u8 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 continuous 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..e648514 --- /dev/null +++ b/include/sound/sb16_csp.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * 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 + * + */ +#ifndef _UAPI__SOUND_SB16_CSP_H +#define _UAPI__SOUND_SB16_CSP_H + + +/* 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 */ +struct snd_sb_csp_mc_header { + char codec_name[16]; /* id name of codec */ + unsigned short func_req; /* requested function */ +}; + +/* microcode to be loaded */ +struct snd_sb_csp_microcode { + struct snd_sb_csp_mc_header info; + unsigned char data[SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE]; +}; + +/* start CSP with sample_width in mono/stereo */ +struct snd_sb_csp_start { + int sample_width; /* sample width, look above */ + int channels; /* channels, look above */ +}; + +/* CSP information */ +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 */ +}; + +/* HWDEP controls */ +/* get CSP information */ +#define SNDRV_SB_CSP_IOCTL_INFO _IOR('H', 0x10, struct snd_sb_csp_info) +/* load microcode to CSP */ +/* NOTE: struct snd_sb_csp_microcode overflows the max size (13 bits) + * defined for some architectures like MIPS, and it leads to build errors. + * (x86 and co have 14-bit size, thus it's valid, though.) + * As a workaround for skipping the size-limit check, here we don't use the + * normal _IOW() macro but _IOC() with the manual argument. + */ +#define SNDRV_SB_CSP_IOCTL_LOAD_CODE \ + _IOC(_IOC_WRITE, 'H', 0x11, sizeof(struct snd_sb_csp_microcode)) +/* 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, struct snd_sb_csp_start) +/* 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 /* _UAPI__SOUND_SB16_CSP_H */ 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/tlv.h b/include/sound/tlv.h new file mode 100644 index 0000000..7d6d65f --- /dev/null +++ b/include/sound/tlv.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * 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. + */ + +#ifndef __UAPI_SOUND_TLV_H +#define __UAPI_SOUND_TLV_H + +#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */ +#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */ +#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */ +#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */ +#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */ +#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */ + +/* + * channel-mapping TLV items + * TLV length must match with num_channels + */ +#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */ +#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */ +#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */ + +/* + * TLV structure is right behind the struct snd_ctl_tlv: + * unsigned int type - see SNDRV_CTL_TLVT_* + * unsigned int length + * .... data aligned to sizeof(unsigned int), use + * block_length = (length + (sizeof(unsigned int) - 1)) & + * ~(sizeof(unsigned int) - 1)) .... + */ +#define SNDRV_CTL_TLVD_ITEM(type, ...) \ + (type), SNDRV_CTL_TLVD_LENGTH(__VA_ARGS__), __VA_ARGS__ +#define SNDRV_CTL_TLVD_LENGTH(...) \ + ((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ })) + +/* Accessor offsets for TLV data items */ +#define SNDRV_CTL_TLVO_TYPE 0 +#define SNDRV_CTL_TLVO_LEN 1 + +#define SNDRV_CTL_TLVD_CONTAINER_ITEM(...) \ + SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__) +#define SNDRV_CTL_TLVD_DECLARE_CONTAINER(name, ...) \ + unsigned int name[] = { \ + SNDRV_CTL_TLVD_CONTAINER_ITEM(__VA_ARGS__) \ + } + +#define SNDRV_CTL_TLVD_DB_SCALE_MASK 0xffff +#define SNDRV_CTL_TLVD_DB_SCALE_MUTE 0x10000 +#define SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ + SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_SCALE, \ + (min), \ + ((step) & SNDRV_CTL_TLVD_DB_SCALE_MASK) | \ + ((mute) ? SNDRV_CTL_TLVD_DB_SCALE_MUTE : 0)) +#define SNDRV_CTL_TLVD_DECLARE_DB_SCALE(name, min, step, mute) \ + unsigned int name[] = { \ + SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ + } + +/* Accessor offsets for min, mute and step items in dB scale type TLV */ +#define SNDRV_CTL_TLVO_DB_SCALE_MIN 2 +#define SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP 3 + +/* dB scale specified with min/max values instead of step */ +#define SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ + SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB)) +#define SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ + SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX_MUTE, (min_dB), (max_dB)) +#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(name, min_dB, max_dB) \ + unsigned int name[] = { \ + SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ + } +#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX_MUTE(name, min_dB, max_dB) \ + unsigned int name[] = { \ + SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ + } + +/* Accessor offsets for min, max items in db-minmax types of TLV. */ +#define SNDRV_CTL_TLVO_DB_MINMAX_MIN 2 +#define SNDRV_CTL_TLVO_DB_MINMAX_MAX 3 + +/* linear volume between min_dB and max_dB (.01dB unit) */ +#define SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ + SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB)) +#define SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(name, min_dB, max_dB) \ + unsigned int name[] = { \ + SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ + } + +/* Accessor offsets for min, max items in db-linear type of TLV. */ +#define SNDRV_CTL_TLVO_DB_LINEAR_MIN 2 +#define SNDRV_CTL_TLVO_DB_LINEAR_MAX 3 + +/* dB range container: + * Items in dB range container must be ordered by their values and by their + * dB values. This implies that larger values must correspond with larger + * dB values (which is also required for all other mixer controls). + */ +/* Each item is: */ +#define SNDRV_CTL_TLVD_DB_RANGE_ITEM(...) \ + SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_RANGE, __VA_ARGS__) +#define SNDRV_CTL_TLVD_DECLARE_DB_RANGE(name, ...) \ + unsigned int name[] = { \ + SNDRV_CTL_TLVD_DB_RANGE_ITEM(__VA_ARGS__) \ + } + +#define SNDRV_CTL_TLVD_DB_GAIN_MUTE -9999999 + +#endif diff --git a/include/sound/type_compat.h b/include/sound/type_compat.h new file mode 100644 index 0000000..e973ff3 --- /dev/null +++ b/include/sound/type_compat.h @@ -0,0 +1,42 @@ +#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 __le8 __u8 +#define __be64 __u64 +#define __be32 __u32 +#define __be16 __u16 +#define __be8 __u8 +#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..dc5ca69 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 /* Obsoleted, due to enough legacy. */ +/** 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/topology.h b/include/topology.h new file mode 100644 index 0000000..27da730 --- /dev/null +++ b/include/topology.h @@ -0,0 +1,1115 @@ +/* + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Copyright (C) 2015 Intel Corporation + * + */ + +#ifndef __ALSA_TOPOLOGY_H +#define __ALSA_TOPOLOGY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup topology Topology Interface + * \{ + */ + +/*! \page topology ALSA Topology Interface + * + * The topology interface allows developers to define DSP topologies in a text + * file format and to convert the text topology to a binary topology + * representation that can be understood by the kernel. The topology core + * currently recognises the following object types :- + * + * * Controls (mixer, enumerated and byte) including TLV data. + * * PCMs (Front End DAI & DAI link) + * * DAPM widgets + * * DAPM graph elements. + * * Physical DAI & DAI links + * * Private data for each object type. + * * Manifest (containing count of each object type) + * + *

Topology File Format

+ * + * The topology text format uses the standard ALSA configuration file format to + * describe each topology object type. This allows topology objects to include + * other topology objects as part of their definition. i.e. a TLV data object + * can be shared amongst many control objects that use the same TLV data. + * + * + *

Controls

+ * Topology audio controls can belong to three different types :- + * * Mixer control + * * Enumerated control + * * Byte control + * + * Each control type can contain TLV data, private data, operations and also + * belong to widget objects.
+ * + *
Control Operations
+ * Driver Kcontrol callback info(), get() and put() operations are mapped with + * the CTL ops section in topology configuration files. The ctl ops section can + * assign operations using the standard names (listed below) for the standard + * kcontrol types or use ID numbers (>256) to map to bespoke driver controls.
+ * + *
+ *
+ *	ops."ctl" {
+ *		info "volsw"
+ *		get "257"
+ *		put "257"
+ *	}
+ *
+ * 
+ * + * This mapping shows info() using the standard "volsw" info callback whilst + * the get() and put() are mapped to bespoke driver callbacks.
+ * + * The Standard operations names for control get(), put() and info calls + * are :- + * * volsw + * * volsw_sx + * * volsw_xr_sx + * * enum + * * bytes + * * enum_value + * * range + * * strobe + * +*
Control Access
+ * Controls access can be specified using the "access" section. If no "access" + * section is defined then default RW access flags are set for normal and TLV + * controls. + * + *
+ *	access [
+ *		read
+ *		write
+ *		tlv_command
+ *	]
+ * 
+ * + * The standard access flags are as follows :- + * * read + * * write + * * read_write + * * volatile + * * timestamp + * * tlv_read + * * tlv_write + * * tlv_read_write + * * tlv_command + * * inactive + * * lock + * * owner + * * tlv_callback + * * user + * + *
Control TLV Data
+ * Controls can also use TLV data to represent dB information. This can be done + * by defining a TLV section and using the TLV section within the control. + * The TLV data for DBScale types are defined as follows :- + * + *
+ *	scale {
+ *		min "-9000"
+ *		step "300"
+ *		mute "1"
+ *	}
+ * 
+ * + * Where the meanings and values for min, step and mute are exactly the same + * as defined in driver code. + * + *
Control Channel Mapping
+ * Controls can also specify which channels they are mapped with. This is useful + * for userspace as it allows applications to determine the correct control + * channel for Left and Right etc. Channel maps are defined as follows :- + * + *
+ *	channel."name" {
+ *		reg "0"
+ *		shift "0"
+ *	}
+ * 
+ * + * The channel map reg is the register offset for the control, shift is the + * bit shift within the register for the channel and the section name is the + * channel name and can be one of the following :- + * + *
+ *  * mono		# mono stream
+ *  * fl 		# front left
+ *  * fr		# front right
+ *  * rl		# rear left
+ *  * rr		# rear right
+ *  * fc		# front center
+ *  * lfe		# LFE
+ *  * sl		# side left
+ *  * sr		# side right
+ *  * rc		# rear center
+ *  * flc		# front left center
+ *  * frc		# front right center
+ *  * rlc		# rear left center
+ *  * rrc		# rear right center
+ *  * flw		# front left wide
+ *  * frw		# front right wide
+ *  * flh		# front left high
+ *  * fch		# front center high
+ *  * frh		# front right high
+ *  * tc		# top center
+ *  * tfl		# top front left
+ *  * tfr		# top front right
+ *  * tfc		# top front center
+ *  * trl		# top rear left
+ *  * trr		# top rear right
+ *  * trc		# top rear center
+ *  * tflc		# top front left center
+ *  * tfrc		# top front right center
+ *  * tsl		# top side left
+ *  * tsr		# top side right
+ *  * llfe		# left LFE
+ *  * rlfe		# right LFE
+ *  * bc		# bottom center
+ *  * blc		# bottom left center
+ *  * brc		# bottom right center
+ * 
+ * + *
Control Private Data
+ * Controls can also have private data. This can be done by defining a private + * data section and including the section within the control. The private data + * section is defined as follows :- + * + *
+ * SectionData."pdata for EQU1" {
+ *	file "/path/to/file"
+ *	bytes "0x12,0x34,0x56,0x78"
+ *	shorts "0x1122,0x3344,0x5566,0x7788"
+ *	words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
+ *	tuples "section id of the vendor tuples"
+ * };
+ * 
+ * The file, bytes, shorts, words and tuples keywords are all mutually + * exclusive as the private data should only be taken from one source. + * The private data can either be read from a separate file or defined in + * the topology file using the bytes, shorts, words or tuples keywords. + * The keyword tuples is to define vendor specific tuples. Please refer to + * section Vendor Tokens and Vendor tuples. + * + * It's easy to use a vendor tuples object to define a C structure instance. + * And a data section can include multiple vendor tuples objects: + * + *
+ * SectionData."data element name" {
+ *	index "1"	#Index number
+ *	tuples [
+ *		"id of the 1st vendor tuples section"
+ *		"id of the 2nd vendor tuples section"
+ *		...
+ *	]
+ * };
+ * 
+ * + *
How to define an element with private data
+ * An element can refer to a single data section or multiple data + * sections. + * + *
To refer to a single data section:
+ *
+ * Sectionxxx."element name" {
+ *    ...
+ *	data "name of data section"		# optional private data
+ * }
+ * 
+ * + *
To refer to multiple data sections:
+ *
+ * Sectionxxx."element name" {
+ *	...
+ *	data [						# optional private data
+ *		"name of 1st data section"
+ *		"name of 2nd data section"
+ *		...
+ *	]
+ * }
+ * 
+ * And data of these sections will be merged in the same order as they are + * in the list, as the element's private data for kernel. + * + * + * + *
Vendor Tokens
+ * A vendor token list is defined as a new section. Each token element is + * a pair of string ID and integer value. And both the ID and value are + * vendor-specific. + * + *
+ * SectionVendorTokens."id of the vendor tokens" {
+ *	comment "optional comments"
+ *	VENDOR_TOKEN_ID1 "1"
+ *	VENDOR_TOKEN_ID2 "2"
+ *	VENDOR_TOKEN_ID3 "3"
+ *	...
+ * }
+ * 
+ * + *
Vendor Tuples
+ * Vendor tuples are defined as a new section. It contains a reference to + * a vendor token list and several tuple arrays. + * All arrays share a vendor token list, defined by the tokens keyword. + * Each tuple array is for a specific type, defined by the string following + * the tuples keyword. Supported types are: string, uuid, bool, byte, + * short and word. + * + *
+ * SectionVendorTuples."id of the vendor tuples" {
+ *	tokens "id of the vendor tokens"
+ *
+ *	tuples."string" {
+ *		VENDOR_TOKEN_ID1 "character string"
+ *		...
+ *	}
+ *
+ *	tuples."uuid" {			# 16 characters separated by commas
+ *		VENDOR_TOKEN_ID2 "0x01,0x02,...,0x0f"
+ *		...
+ *	}
+ *
+ *	tuples."bool" {
+ *		VENDOR_TOKEN_ID3 "true/false"
+ *		...
+ *	}
+ *
+ *	tuples."byte" {
+ *		VENDOR_TOKEN_ID4 "0x11"
+ *		VENDOR_TOKEN_ID5 "0x22"
+ *		...
+ *	}
+ *
+ *	tuples."short" {
+ *		VENDOR_TOKEN_ID6 "0x1122"
+ *		VENDOR_TOKEN_ID7 "0x3344"
+ *		...
+ *	}
+ *
+ *	tuples."word" {
+ *		VENDOR_TOKEN_ID8 "0x11223344"
+ *		VENDOR_TOKEN_ID9 "0x55667788"
+ *		...
+ *	}
+ * }
+ * 
+ * To define multiple vendor tuples of same type, please append some + * characters after the type string ("string", "uuid", "bool", "byte", "short" + * or "word"), to avoid ID duplication in the SectionVendorTuples.
+ * The parser will check the first few characters in ID to get the tuple type. + * Here is an example: + *
+ * SectionVendorTuples."id of the vendor tuples" {
+ *    ...
+ *	tuples."word.module0" {
+ *		VENDOR_TOKEN_PARAM_ID1 "0x00112233"
+ *		VENDOR_TOKEN_PARAM_ID2 "0x44556677"
+ *		...
+ *	}
+ *
+ *	tuples."word.module2" {
+ *		VENDOR_TOKEN_PARAM_ID1 "0x11223344"
+ *		VENDOR_TOKEN_PARAM_ID2 "0x55667788"
+ *		...
+ *	}
+ *	...
+ * }
+ *
+ * 
+ * + *
Mixer Controls
+ * A mixer control is defined as a new section that can include channel mapping, + * TLV data, callback operations and private data. The mixer section also + * includes a few other config options that are shown here :- + * + *
+ * SectionControlMixer."mixer name" {
+ *	comment "optional comments"
+ *
+ *	index "1"			# Index number
+ *
+ *	channel."name" {		# Channel maps
+ *	   ....
+ *	}
+ *
+ *	ops."ctl" {			# Ops callback functions
+ *	   ....
+ *	}
+ *
+ *	max "32"			# Max control value
+ *	invert "0"			# Whether control values are inverted
+ *
+ *	tlv "tld_data"			# optional TLV data
+ *
+ *	data "pdata for mixer1"		# optional private data
+ * }
+ * 
+ * + * The section name is used to define the mixer name. The index number can be + * used to identify topology objects groups(index "0" is common, fit for all + * user cases).This allows driver operations on objects with index number N and + * can be used to add/remove pipelines of objects whilst other objects are + * unaffected. + * + *
Byte Controls
+ * A byte control is defined as a new section that can include channel mapping, + * TLV data, callback operations and private data. The bytes section also + * includes a few other config options that are shown here :- + * + *
+ * SectionControlBytes."name" {
+ *	comment "optional comments"
+ *
+ *	index "1"			# Index number
+ *
+ *	channel."name" {		# Channel maps
+ *	   ....
+ *	}
+ *
+ *	ops."ctl" {			# Ops callback functions
+ *	   ....
+ *	}
+ *
+ *	base "0"			# Register base
+ *	num_regs "16"			# Number of registers
+ *	mask "0xff"			# Mask
+ *	max "255"			# Maximum value
+ *
+ *	tlv "tld_data"			# optional TLV data
+ *
+ *	data "pdata for mixer1"		# optional private data
+ * }
+ * 
+ * + *
Enumerated Controls
+ * A enumerated control is defined as a new section (like mixer and byte) that + * can include channel mapping, callback operations, private data and + * text strings to represent the enumerated control options.
+ * + * The text strings for the enumerated controls are defined in a separate + * section as follows :- + * + *
+ * SectionText."name" {
+ *
+ *		Values [
+ *			"value1"
+ *			"value2"
+			"value3"
+ *		]
+ * }
+ * 
+ * + * All the enumerated text values are listed in the values list.
+ * The enumerated control is similar to the other controls and defined as + * follows :- + * + *
+ * SectionControlMixer."name" {
+ *	comment "optional comments"
+ *
+ *	index "1"			# Index number
+ *
+ *	texts "EQU1"			# Enumerated text items
+ *
+ *	channel."name" {		# Channel maps
+ *	   ....
+ *	}
+ *
+ *	ops."ctl" {			# Ops callback functions
+ *	   ....
+ *	}
+ *
+ *	data "pdata for mixer1"		# optional private data
+ * }
+ * 
+ * + *

DAPM Graph

+ * DAPM graphs can easily be defined using the topology file. The format is + * very similar to the DAPM graph kernel format. :- + * + *
+ * SectionGraph."dsp" {
+ *	index "1"			# Index number
+ *
+ *	lines [
+ *		"sink1, control, source1"
+ *		"sink2, , source2"
+ *	]
+ * }
+ * 
+ * + * The lines in the graph are defined as a variable size list of sinks, + * controls and sources. The control name is optional as some graph lines have + * no associated controls. The section name can be used to differentiate the + * graph with other graphs, it's not used by the kernel atm. + * + *

DAPM Widgets

+ * DAPM widgets are similar to controls in that they can include many other + * objects. Widgets can contain private data, mixer controls and enum controls. + * + * The following widget types are supported and match the driver types :- + * + * * input + * * output + * * mux + * * mixer + * * pga + * * out_drv + * * adc + * * dac + * * switch + * * pre + * * post + * * aif_in + * * aif_out + * * dai_in + * * dai_out + * * dai_link + * + * Widgets are defined as follows :- + * + *
+ * SectionWidget."name" {
+ *
+ *	index "1"			# Index number
+ *
+ *	type "aif_in"			# Widget type - detailed above
+ *	stream_name "name"		# Stream name
+ *
+ *	no_pm "true"			# No PM control bit.
+ *	reg "20"			# PM bit register offset
+ *	shift "0"			# PM bit register shift
+ *	invert "1			# PM bit is inverted
+ *	subseq "8"			# subsequence number
+ *
+ *	event_type "1"			# DAPM widget event type
+ *	event_flags "1"			# DAPM widget event flags
+ *
+ *	mixer "name"			# Optional Mixer Control
+ *	enum "name"			# Optional Enum Control
+ *
+ *	data "name"			# optional private data
+ * }
+ * 
+ * + * The section name is the widget name. The mixer and enum fields are mutually + * exclusive and used to include controls into the widget. The index and data + * fields are the same for widgets as they are for controls whilst the other + * fields map on very closely to the driver widget fields. + * + *
Widget Private Data
+ * Widget can have private data. For the format of the private data, please + * refer to section Control Private Data. + * + *

PCM Capabilities

+ * Topology can also define the PCM capabilities of front end or physical DAIs. + * Capabilities can be defined with the following section :- + * + *
+ * SectionPCMCapabilities."name" {
+ *
+ *	formats "S24_LE,S16_LE"		# Supported formats
+ *	rates "48000"			# Supported rates
+ *	rate_min "48000"		# Max supported sample rate
+ *	rate_max "48000"		# Min supported sample rate
+ *	channels_min "2"		# Min number of channels
+ *	channels_max "2"		# max number of channels
+ * }
+ * 
+ * The supported formats use the same naming convention as the driver macros. + * The PCM capabilities name can be referred to and included by PCM and + * physical DAI sections. + * + *

PCM Configurations

+ * PCM runtime configurations can be defined for playback and capture stream + * directions with the following section :- + * + *
+ * SectionPCMConfig."name" {
+ *
+ *	config."playback" {		# playback config
+ *		format "S16_LE"		# playback format
+ *		rate "48000"		# playback sample rate
+ *		channels "2"		# playback channels
+ *		tdm_slot "0xf"		# playback TDM slot
+ *	}
+ *
+ *	config."capture" {		# capture config
+ *		format "S16_LE"		# capture format
+ *		rate "48000"		# capture sample rate
+ *		channels "2"		# capture channels
+ *		tdm_slot "0xf"		# capture TDM slot
+ *	}
+ * }
+ * 
+ * + * The supported formats use the same naming convention as the driver macros. + * The PCM configuration name can be referred to and included by PCM and + * physical link sections. + * + *

PCM (Front-end DAI & DAI link)

+ * PCM sections define the supported capabilities and configurations for + * supported playback and capture streams, names and flags for front end + * DAI & DAI links. Topology kernel driver will use a PCM object to create + * a pair of FE DAI & DAI links. + * + *
+ * SectionPCM."name" {
+ *
+ *	index "1"			# Index number
+ *
+ *	id "0"				# used for binding to the PCM
+ *
+ *	dai."name of front-end DAI" {
+ *		id "0"		# used for binding to the front-end DAI
+ *	}
+ *
+ *	pcm."playback" {
+ *		capabilities "capabilities1"	# capabilities for playback
+ *
+ *		configs [		# supported configs for playback
+ *			"config1"
+ *			"config2"
+ *		]
+ *	}
+ *
+ *	pcm."capture" {
+ *		capabilities "capabilities2"	# capabilities for capture
+ *
+ *		configs [		# supported configs for capture
+ *			"config1"
+ *			"config2"
+ *			"config3"
+ *		]
+ *	}
+ *
+ *	# Optional boolean flags
+ *	symmetric_rates			"true"
+ *	symmetric_channels		"true"
+ *	symmetric_sample_bits		"false"
+ *
+ *	data "name"			# optional private data
+ * }
+ * 
+ * + *

Physical DAI Link Configurations

+ * The runtime configurations of a physical DAI link can be defined by + * SectionLink.
Backend DAI links belong to physical links, and can + * be configured by either SectionLink or SectionBE, with same syntax. + * But SectionBE is deprecated atm since the internal processing is + * actually same. + * + *
+ * SectionLink."name" {
+ *
+ *	index "1"			# Index number
+ *
+ *	id "0"				# used for binding to the link
+ *
+ *	stream_name "name"		# used for binding to the link
+ *
+ *	hw_configs [	# runtime supported HW configurations, optional
+ *		"config1"
+ *		"config2"
+ *		...
+ *	]
+ *
+ *	default_hw_conf_id "1"		#default HW config ID for init
+ *
+ *	# Optional boolean flags
+ *	symmetric_rates			"true"
+ *	symmetric_channels		"false"
+ *	symmetric_sample_bits		"true"
+ *
+ *	data "name"			# optional private data
+ * }
+ * 
+ * + * A physical link can refer to multiple runtime supported hardware + * configurations, which is defined by SectionHWConfig. + * + *
+ * SectionHWConfig."name" {
+ *
+ *	id "1"				# used for binding to the config
+ *	format "I2S"			# physical audio format.
+ *	bclk   "master"			# Platform is master of bit clock
+ *	fsync  "slave"			# Platform is slave of fsync
+ * }
+ * 
+ * + *

Physical DAI

+ * A physical DAI (e.g. backend DAI for DPCM) is defined as a new section + * that can include a unique ID, playback and capture stream capabilities, + * optional flags, and private data.
+ * Its PCM stream capablities are same as those for PCM objects, + * please refer to section 'PCM Capabilities'. + * + *
+ * SectionDAI."name" {
+ *
+ *	index "1"			# Index number
+ *
+ *	id "0"				# used for binding to the Backend DAI
+ *
+ *	pcm."playback" {
+ *		capabilities "capabilities1"	# capabilities for playback
+ *	}
+ *
+ *	pcm."capture" {
+ *		capabilities "capabilities2"	# capabilities for capture
+ *	}
+ *
+ *	symmetric_rates "true"			# optional flags
+ *	symmetric_channels "true"
+ *	symmetric_sample_bits "false"
+ *
+ *	data "name"			# optional private data
+ * }
+ * 
+ * + *

Manifest Private Data

+ * Manfiest may have private data. Users need to define a manifest section + * and add the references to 1 or multiple data sections. Please refer to + * section 'How to define an element with private data'.
+ * And the text conf file can have at most 1 manifest section.

+ * + * Manifest section is defined as follows :- + * + *
+ * SectionManifest"name" {
+ *
+ *	data "name"			# optional private data
+ * }
+ * 
+ * + *

Include other files

+ * Users may include other files in a text conf file via alsaconf syntax + * . This allows users to define common info + * in separate files (e.g. vendor tokens, tuples) and share them for + * different platforms, thus save the total size of config files.
+ * Users can also specifiy additional configuraiton directories relative + * to "/usr/share/alsa/" to search the included files, via alsaconf syntax + * .

+ * + * For example, file A and file B are two text conf files for platform X, + * they will be installed to /usr/share/alsa/topology/platformx. If we + * need file A to include file B, in file A we can add:
+ * + *
+ *

+ * + * ALSA conf will search and open an included file in the following order + * of priority: + * 1. directly open the file by its name; + * 2. search for the file name in "/usr/share/alsa"; + * 3. search for the file name in user specified subdirectories under + * "/usr/share/alsa". + * + * The order of the included files need not to be same as their + * dependencies, since the topology library will load them all before + * parsing their dependencies.
+ * + * The configuration directories defined by a file will only be used to search + * the files included by this file. + */ + +/** Maximum number of channels supported in one control */ +#define SND_TPLG_MAX_CHAN 8 + +/** Topology context */ +typedef struct snd_tplg snd_tplg_t; + +/** Topology object types */ +enum snd_tplg_type { + SND_TPLG_TYPE_TLV = 0, /*!< TLV Data */ + SND_TPLG_TYPE_MIXER, /*!< Mixer control*/ + SND_TPLG_TYPE_ENUM, /*!< Enumerated control */ + SND_TPLG_TYPE_TEXT, /*!< Text data */ + SND_TPLG_TYPE_DATA, /*!< Private data */ + SND_TPLG_TYPE_BYTES, /*!< Byte control */ + SND_TPLG_TYPE_STREAM_CONFIG, /*!< PCM Stream configuration */ + SND_TPLG_TYPE_STREAM_CAPS, /*!< PCM Stream capabilities */ + SND_TPLG_TYPE_PCM, /*!< PCM stream device */ + SND_TPLG_TYPE_DAPM_WIDGET, /*!< DAPM widget */ + SND_TPLG_TYPE_DAPM_GRAPH, /*!< DAPM graph elements */ + SND_TPLG_TYPE_BE, /*!< BE DAI link */ + SND_TPLG_TYPE_CC, /*!< Hostless codec <-> codec link */ + SND_TPLG_TYPE_MANIFEST, /*!< Topology manifest */ + SND_TPLG_TYPE_TOKEN, /*!< Vendor tokens */ + SND_TPLG_TYPE_TUPLE, /*!< Vendor tuples */ + SND_TPLG_TYPE_LINK, /*!< Physical DAI link */ + SND_TPLG_TYPE_HW_CONFIG, /*!< Link HW config */ + SND_TPLG_TYPE_DAI, /*!< Physical DAI */ +}; + +/** Fit for all user cases */ +#define SND_TPLG_INDEX_ALL 0 + +/** + * \brief Create a new topology parser instance. + * \return New topology parser instance + */ +snd_tplg_t *snd_tplg_new(void); + +/** + * \brief Free a topology parser instance. + * \param tplg Topology parser instance + */ +void snd_tplg_free(snd_tplg_t *tplg); + +/** + * \brief Parse and build topology text file into binary file. + * \param tplg Topology instance. + * \param infile Topology text input file to be parsed + * \param outfile Binary topology output file. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile, + const char *outfile); + +/** + * \brief Enable verbose reporting of binary file output + * \param tplg Topology Instance + * \param verbose Enable verbose output level if non zero + */ +void snd_tplg_verbose(snd_tplg_t *tplg, int verbose); + +/** \struct snd_tplg_tlv_template + * \brief Template type for all TLV objects. + */ +struct snd_tplg_tlv_template { + int type; /*!< TLV type SNDRV_CTL_TLVT_ */ +}; + +/** \struct snd_tplg_tlv_dbscale_template + * \brief Template type for TLV Scale objects. + */ +struct snd_tplg_tlv_dbscale_template { + struct snd_tplg_tlv_template hdr; /*!< TLV type header */ + int min; /*!< dB minimum value in 0.1dB */ + int step; /*!< dB step size in 0.1dB */ + int mute; /*!< is min dB value mute ? */ +}; + +/** \struct snd_tplg_channel_template + * \brief Template type for single channel mapping. + */ +struct snd_tplg_channel_elem { + int size; /*!< size in bytes of this structure */ + int reg; /*!< channel control register */ + int shift; /*!< channel shift for control bits */ + int id; /*!< ID maps to Left, Right, LFE etc */ +}; + +/** \struct snd_tplg_channel_map_template + * \brief Template type for channel mapping. + */ +struct snd_tplg_channel_map_template { + int num_channels; /*!< number of channel mappings */ + struct snd_tplg_channel_elem channel[SND_TPLG_MAX_CHAN]; /*!< mapping */ +}; + +/** \struct snd_tplg_pdata_template + * \brief Template type for private data objects. + */ +struct snd_tplg_pdata_template { + unsigned int length; /*!< data length */ + const void *data; /*!< data */ +}; + +/** \struct snd_tplg_io_ops_template + * \brief Template type for object operations mapping. + */ +struct snd_tplg_io_ops_template { + int get; /*!< get callback ID */ + int put; /*!< put callback ID */ + int info; /*!< info callback ID */ +}; + +/** \struct snd_tplg_ctl_template + * \brief Template type for control objects. + */ +struct snd_tplg_ctl_template { + int type; /*!< Control type */ + const char *name; /*!< Control name */ + int access; /*!< Control access */ + struct snd_tplg_io_ops_template ops; /*!< operations */ + struct snd_tplg_tlv_template *tlv; /*!< non NULL means we have TLV data */ +}; + +/** \struct snd_tplg_mixer_template + * \brief Template type for mixer control objects. + */ +struct snd_tplg_mixer_template { + struct snd_tplg_ctl_template hdr; /*!< control type header */ + struct snd_tplg_channel_map_template *map; /*!< channel map */ + int min; /*!< min value for mixer */ + int max; /*!< max value for mixer */ + int platform_max; /*!< max value for platform control */ + int invert; /*!< whether controls bits are inverted */ + struct snd_soc_tplg_private *priv; /*!< control private data */ +}; + +/** \struct snd_tplg_enum_template + * \brief Template type for enumerated control objects. + */ +struct snd_tplg_enum_template { + struct snd_tplg_ctl_template hdr; /*!< control type header */ + struct snd_tplg_channel_map_template *map; /*!< channel map */ + int items; /*!< number of enumerated items in control */ + int mask; /*!< register mask size */ + const char **texts; /*!< control text items */ + const int **values; /*!< control value items */ + struct snd_soc_tplg_private *priv; /*!< control private data */ +}; + +/** \struct snd_tplg_bytes_template + * \brief Template type for TLV Scale objects. + */ +struct snd_tplg_bytes_template { + struct snd_tplg_ctl_template hdr; /*!< control type header */ + int max; /*!< max byte control value */ + int mask; /*!< byte control mask */ + int base; /*!< base register */ + int num_regs; /*!< number of registers */ + struct snd_tplg_io_ops_template ext_ops; /*!< ops mapping */ + struct snd_soc_tplg_private *priv; /*!< control private data */ +}; + +/** \struct snd_tplg_graph_elem + * \brief Template type for single DAPM graph element. + */ +struct snd_tplg_graph_elem { + const char *src; /*!< source widget name */ + const char *ctl; /*!< control name or NULL if no control */ + const char *sink; /*!< sink widget name */ +}; + +/** \struct snd_tplg_graph_template + * \brief Template type for array of DAPM graph elements. + */ +struct snd_tplg_graph_template { + int count; /*!< Number of graph elements */ + struct snd_tplg_graph_elem elem[0]; /*!< graph elements */ +}; + +/** \struct snd_tplg_widget_template + * \brief Template type for DAPM widget objects. + */ +struct snd_tplg_widget_template { + int id; /*!< SND_SOC_DAPM_CTL */ + const char *name; /*!< widget name */ + const char *sname; /*!< stream name (certain widgets only) */ + int reg; /*!< negative reg = no direct dapm */ + int shift; /*!< bits to shift */ + int mask; /*!< non-shifted mask */ + int subseq; /*!< sort within widget type */ + unsigned int invert; /*!< invert the power bit */ + unsigned int ignore_suspend; /*!< kept enabled over suspend */ + unsigned short event_flags; /*!< PM event sequence flags */ + unsigned short event_type; /*!< PM event sequence type */ + struct snd_soc_tplg_private *priv; /*!< widget private data */ + int num_ctls; /*!< Number of controls used by widget */ + struct snd_tplg_ctl_template *ctl[0]; /*!< array of widget controls */ +}; + +/** \struct snd_tplg_stream_template + * \brief Stream configurations. + */ +struct snd_tplg_stream_template { + const char *name; /*!< name of the stream config */ + int format; /*!< SNDRV_PCM_FMTBIT_* */ + int rate; /*!< SNDRV_PCM_RATE_* */ + int period_bytes; /*!< size of period in bytes */ + int buffer_bytes; /*!< size of buffer in bytes. */ + int channels; /*!< number of channels */ +}; + +/** \struct snd_tplg_stream_caps_template + * \brief Stream Capabilities. + */ +struct snd_tplg_stream_caps_template { + const char *name; /*!< name of the stream caps */ + uint64_t formats; /*!< supported formats SNDRV_PCM_FMTBIT_* */ + unsigned int rates; /*!< supported rates SNDRV_PCM_RATE_* */ + unsigned int rate_min; /*!< min rate */ + unsigned int rate_max; /*!< max rate */ + unsigned int channels_min; /*!< min channels */ + unsigned int channels_max; /*!< max channels */ + unsigned int periods_min; /*!< min number of periods */ + unsigned int periods_max; /*!< max number of periods */ + unsigned int period_size_min; /*!< min period size bytes */ + unsigned int period_size_max; /*!< max period size bytes */ + unsigned int buffer_size_min; /*!< min buffer size bytes */ + unsigned int buffer_size_max; /*!< max buffer size bytes */ + unsigned int sig_bits; /*!< number of bits of content */ +}; + +/** \struct snd_tplg_pcm_template + * \brief Template type for PCM (FE DAI & DAI links). + */ +struct snd_tplg_pcm_template { + const char *pcm_name; /*!< PCM stream name */ + const char *dai_name; /*!< DAI name */ + unsigned int pcm_id; /*!< unique ID - used to match */ + unsigned int dai_id; /*!< unique ID - used to match */ + unsigned int playback; /*!< supports playback mode */ + unsigned int capture; /*!< supports capture mode */ + unsigned int compress; /*!< 1 = compressed; 0 = PCM */ + struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ + unsigned int flag_mask; /*!< bitmask of flags to configure */ + unsigned int flags; /*!< flag value SND_SOC_TPLG_LNK_FLGBIT_* */ + struct snd_soc_tplg_private *priv; /*!< private data */ + int num_streams; /*!< number of supported configs */ + struct snd_tplg_stream_template stream[0]; /*!< supported configs */ +}; + + /** \struct snd_tplg_hw_config_template + * \brief Template type to describe a physical link runtime supported + * hardware config, i.e. hardware audio formats. + */ +struct snd_tplg_hw_config_template { + int id; /* unique ID - - used to match */ + unsigned int fmt; /* SND_SOC_DAI_FORMAT_ format value */ + unsigned char clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ + unsigned char invert_bclk; /* 1 for inverted BCLK, 0 for normal */ + unsigned char invert_fsync; /* 1 for inverted frame clock, 0 for normal */ + unsigned char bclk_master; /* SND_SOC_TPLG_BCLK_ value */ + unsigned char fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + unsigned char mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ + unsigned short reserved; /* for 32bit alignment */ + unsigned int mclk_rate; /* MCLK or SYSCLK freqency in Hz */ + unsigned int bclk_rate; /* BCLK freqency in Hz */ + unsigned int fsync_rate; /* frame clock in Hz */ + unsigned int tdm_slots; /* number of TDM slots in use */ + unsigned int tdm_slot_width; /* width in bits for each slot */ + unsigned int tx_slots; /* bit mask for active Tx slots */ + unsigned int rx_slots; /* bit mask for active Rx slots */ + unsigned int tx_channels; /* number of Tx channels */ + unsigned int *tx_chanmap; /* array of slot number */ + unsigned int rx_channels; /* number of Rx channels */ + unsigned int *rx_chanmap; /* array of slot number */ +}; + +/** \struct snd_tplg_dai_template + * \brief Template type for physical DAI. + * It can be used to configure backend DAIs for DPCM. + */ +struct snd_tplg_dai_template { + const char *dai_name; /*!< DAI name */ + unsigned int dai_id; /*!< unique ID - used to match */ + unsigned int playback; /*!< supports playback mode */ + unsigned int capture; /*!< supports capture mode */ + struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ + unsigned int flag_mask; /*!< bitmask of flags to configure */ + unsigned int flags; /*!< SND_SOC_TPLG_DAI_FLGBIT_* */ + struct snd_soc_tplg_private *priv; /*!< private data */ + +}; + +/** \struct snd_tplg_link_template + * \brief Template type for physical DAI Links. + */ +struct snd_tplg_link_template { + const char *name; /*!< link name, used to match */ + int id; /*!< unique ID - used to match with existing physical links */ + const char *stream_name; /*!< link stream name, used to match */ + + int num_streams; /*!< number of configs */ + struct snd_tplg_stream_template *stream; /*!< supported configs */ + + struct snd_tplg_hw_config_template *hw_config; /*!< supported HW configs */ + int num_hw_configs; /* number of hw configs */ + int default_hw_config_id; /* default hw config ID for init */ + + unsigned int flag_mask; /* bitmask of flags to configure */ + unsigned int flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private *priv; /*!< private data */ +}; + +/** \struct snd_tplg_obj_template + * \brief Generic Template Object + */ +typedef struct snd_tplg_obj_template { + enum snd_tplg_type type; /*!< template object type */ + int index; /*!< group index for object */ + int version; /*!< optional vendor specific version details */ + int vendor_type; /*!< optional vendor specific type info */ + union { + struct snd_tplg_widget_template *widget; /*!< DAPM widget */ + struct snd_tplg_mixer_template *mixer; /*!< Mixer control */ + struct snd_tplg_bytes_template *bytes_ctl; /*!< Bytes control */ + struct snd_tplg_enum_template *enum_ctl; /*!< Enum control */ + struct snd_tplg_graph_template *graph; /*!< Graph elements */ + struct snd_tplg_pcm_template *pcm; /*!< PCM elements */ + struct snd_tplg_link_template *link; /*!< physical DAI Links */ + struct snd_tplg_dai_template *dai; /*!< Physical DAI */ + }; +} snd_tplg_obj_template_t; + +/** + * \brief Register topology template object. + * \param tplg Topology instance. + * \param t Template object. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); + +/** + * \brief Build all registered topology data into binary file. + * \param tplg Topology instance. + * \param outfile Binary topology output file. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_build(snd_tplg_t *tplg, const char *outfile); + +/** + * \brief Attach private data to topology manifest. + * \param tplg Topology instance. + * \param data Private data. + * \param len Length of data in bytes. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_set_manifest_data(snd_tplg_t *tplg, const void *data, int len); + +/** + * \brief Set an optional vendor specific version number. + * \param tplg Topology instance. + * \param version Vendor specific version number. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_set_version(snd_tplg_t *tplg, unsigned int version); + +/* \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_TOPOLOGY_H */ diff --git a/include/type_compat.h b/include/type_compat.h new file mode 100644 index 0000000..000057f --- /dev/null +++ b/include/type_compat.h @@ -0,0 +1,61 @@ +/* + * ALSA lib - compatibility header to be included by local.h + * Copyright (c) 2016 by Thomas Klausner + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __TYPE_COMPAT_H +#define __TYPE_COMPAT_H + +#ifndef EBADFD +#define EBADFD EBADF +#endif +#ifndef ESTRPIPE +#define ESTRPIPE EPIPE +#endif + +#ifndef __u16 +#define __u16 uint16_t +#endif +#ifndef __u32 +#define __u32 uint32_t +#endif +#ifndef __u64 +#define __u64 uint64_t +#endif +#ifndef __le16 +#define __le16 uint16_t +#endif +#ifndef __le32 +#define __le32 uint32_t +#endif +#ifndef __le64 +#define __le64 uint64_t +#endif +#ifndef __kernel_pid_t +#define __kernel_pid_t pid_t +#endif +#ifndef __kernel_off_t +#define __kernel_off_t off_t +#endif + +#ifndef __bitwise +#define __bitwise +#endif + +#endif diff --git a/include/use-case.h b/include/use-case.h new file mode 100644 index 0000000..8e7e838 --- /dev/null +++ b/include/use-case.h @@ -0,0 +1,500 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 + +#include + +/** + * \defgroup ucm Use Case Interface + * The ALSA Use Case manager interface. + * See \ref Usecase page for more details. + * \{ + */ + +/*! \page Usecase 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. + * + * + Incoming phone call when the device is playing music + * + Recording sections of a phone call + * + 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 :- + * + * + Query the supported use case verbs, devices and modifiers for the machine. + * + Set and Get use case verbs, devices and modifiers for the machine. + * + Get the ALSA PCM playback and capture device PCMs for use case verb, + * use case device and modifier. + * + Get the TQ parameter for each use case verb, use case device and + * modifier. + * + Get the ALSA master playback and capture volume/switch kcontrols + * or mixer elements 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" /**< Inactive Verb */ +#define SND_USE_CASE_VERB_HIFI "HiFi" /**< HiFi Verb */ +#define SND_USE_CASE_VERB_HIFI_LOW_POWER "HiFi Low Power" /**< HiFi Low Power Verb */ +#define SND_USE_CASE_VERB_VOICE "Voice" /**< Voice Verb */ +#define SND_USE_CASE_VERB_VOICE_LOW_POWER "Voice Low Power" /**< Voice Low Power Verb */ +#define SND_USE_CASE_VERB_VOICECALL "Voice Call" /**< Voice Call Verb */ +#define SND_USE_CASE_VERB_IP_VOICECALL "Voice Call IP" /**< Voice Call IP Verb */ +#define SND_USE_CASE_VERB_ANALOG_RADIO "FM Analog Radio" /**< FM Analog Radio Verb */ +#define SND_USE_CASE_VERB_DIGITAL_RADIO "FM Digital Radio" /**< FM Digital Radio Verb */ +/* 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" /**< None Device */ +#define SND_USE_CASE_DEV_SPEAKER "Speaker" /**< Speaker Device */ +#define SND_USE_CASE_DEV_LINE "Line" /**< Line Device */ +#define SND_USE_CASE_DEV_HEADPHONES "Headphones" /**< Headphones Device */ +#define SND_USE_CASE_DEV_HEADSET "Headset" /**< Headset Device */ +#define SND_USE_CASE_DEV_HANDSET "Handset" /**< Handset Device */ +#define SND_USE_CASE_DEV_BLUETOOTH "Bluetooth" /**< Bluetooth Device */ +#define SND_USE_CASE_DEV_EARPIECE "Earpiece" /**< Earpiece Device */ +#define SND_USE_CASE_DEV_SPDIF "SPDIF" /**< SPDIF Device */ +#define SND_USE_CASE_DEV_HDMI "HDMI" /**< HDMI Device */ +/* 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" /**< Capture Voice Modifier */ +#define SND_USE_CASE_MOD_CAPTURE_MUSIC "Capture Music" /**< Capture Music Modifier */ +#define SND_USE_CASE_MOD_PLAY_MUSIC "Play Music" /**< Play Music Modifier */ +#define SND_USE_CASE_MOD_PLAY_VOICE "Play Voice" /**< Play Voice Modifier */ +#define SND_USE_CASE_MOD_PLAY_TONE "Play Tone" /**< Play Tone Modifier */ +#define SND_USE_CASE_MOD_ECHO_REF "Echo Reference" /**< Echo Reference Modifier */ +/* 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" /**< Music Tone Quality */ +#define SND_USE_CASE_TQ_VOICE "Voice" /**< Voice Tone Quality */ +#define SND_USE_CASE_TQ_TONES "Tones" /**< Tones Tone Quality */ + +/** 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[/{verb}] - get list of supported devices + * (in pair device+comment) + * - _modifiers[/{verb}] - get list of supported modifiers + * (in pair modifier+comment) + * - TQ[/{verb}] - get list of TQ identifiers + * - _enadevs - get list of enabled devices + * - _enamods - get list of enabled modifiers + * + * - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices + * - _conflictingdevs/{modifier}|{device}[/{verb}] - 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: The returned string is dynamically allocated, use free() to + * deallocate this string. (Yes, the value parameter shouldn't be marked as + * "const", but it's too late to fix it, sorry about that.) + * + * Known identifiers: + * - NULL - return current card + * - _verb - return current verb + * - _file - return configuration file loaded for current card + * + * - [=]{NAME}[/[{modifier}|{/device}][/{verb}]] + * - value identifier {NAME} + * - 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 + * - PlaybackPCMIsDummy + * - Valid values: "yes" and "no". If set to "yes", the PCM named by the + * PlaybackPCM value is a dummy device, meaning that opening it enables + * an audio path in the hardware, but writing to the PCM device has no + * effect. + * - CapturePCM + * - full PCM capture device name + * - CapturePCMIsDummy + * - Valid values: "yes" and "no". If set to "yes", the PCM named by the + * CapturePCM value is a dummy device, meaning that opening it enables + * an audio path in the hardware, but reading from the PCM device has no + * effect. + * - PlaybackRate + * - playback device sample rate + * - PlaybackChannels + * - playback device channel count + * - PlaybackCTL + * - playback control device name + * - PlaybackVolume + * - playback control volume identifier string + * - can be parsed using snd_use_case_parse_ctl_elem_id() + * - PlaybackSwitch + * - playback control switch identifier string + * - can be parsed using snd_use_case_parse_ctl_elem_id() + * - PlaybackPriority + * - priority value (1-10000), default value is 100, higher value means lower priority + * - CaptureRate + * - capture device sample rate + * - CaptureChannels + * - capture device channel count + * - CaptureCTL + * - capture control device name + * - CaptureVolume + * - capture control volume identifier string + * - can be parsed using snd_use_case_parse_ctl_elem_id() + * - CaptureSwitch + * - capture control switch identifier string + * - can be parsed using snd_use_case_parse_ctl_elem_id() + * - CapturePriority + * - priority value (1-10000), default value is 100, higher value means lower priority + * - PlaybackMixer + * - name of playback mixer + * - PlaybackMixerElem + * - mixer element playback identifier + * - can be parsed using snd_use_case_parse_selem_id() + * - PlaybackMasterElem + * - mixer element playback identifier for the master control + * - PlaybackMasterType + * - type of the master volume control + * - Valid values: "soft" (software attenuation) + * - CaptureMixer + * - name of capture mixer + * - CaptureMixerElem + * - mixer element capture identifier + * - can be parsed using snd_use_case_parse_selem_id() + * - CaptureMasterElem + * - mixer element playback identifier for the master control + * - CaptureMasterType + * - type of the master volume control + * - Valid values: "soft" (software attenuation) + * - EDIDFile + * - Path to EDID file for HDMI devices + * - JackControl, JackDev, JackHWMute + * - Jack information for a device. The jack status can be reported via + * a kcontrol and/or via an input device. **JackControl** is the + * kcontrol name of the jack, and **JackDev** is the input device id of + * the jack (if the full input device path is /dev/input/by-id/foo, the + * JackDev value should be "foo"). UCM configuration files should + * contain both JackControl and JackDev when possible, because + * applications are likely to support only one or the other. + * + * If **JackHWMute** is set, it indicates that when the jack is plugged + * in, the hardware automatically mutes some other device(s). The + * JackHWMute value is a space-separated list of device names (this + * isn't compatible with device names with spaces in them, so don't use + * such device names!). Note that JackHWMute should be used only when + * the hardware enforces the automatic muting. If the hardware doesn't + * enforce any muting, it may still be tempting to set JackHWMute to + * trick upper software layers to e.g. automatically mute speakers when + * headphones are plugged in, but that's application policy + * configuration that doesn't belong to UCM configuration files. + * - MinBufferLevel + * - This is used on platform where reported buffer level is not accurate. + * E.g. "512", which holds 512 samples in device buffer. Note: this will + * increase latency. + */ +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/{device} - return status for given device + * - _modstatus/{modifier} - 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/{old_device} - 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/{old_modifier} - 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 + * + * By default only first card is used when the driver card + * name or long name is passed in the card_name argument. + * + * The "strict:" prefix in the card_name defines that + * there is no driver name / long name matching. The straight + * configuration is used. + * + * The "hw:" prefix in the card_name will load the configuration + * for the ALSA card specified by the card index (value) or + * the card string identificator. + * + * The sound card might be also composed from several physical + * sound cards (for the default and strict card_name). + * The application cannot expect that the device names will refer + * only one ALSA sound card in this case. + */ +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); +} + +/** + * \brief Parse control element identifier + * \param elem_id Element identifier + * \param ucm_id Use case identifier + * \param value String value to be parsed + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst, + const char *ucm_id, + const char *value); + +/** + * \brief Parse mixer element identifier + * \param dst Simple mixer element identifier + * \param ucm_id Use case identifier + * \param value String value to be parsed + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, + const char *ucm_id, + const char *value); + +/** + * \} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_USE_CASE_H */ diff --git a/include/version.h b/include/version.h new file mode 100644 index 0000000..56c7589 --- /dev/null +++ b/include/version.h @@ -0,0 +1,15 @@ +/* + * version.h + */ + +#define SND_LIB_MAJOR 1 /**< major number of library version */ +#define SND_LIB_MINOR 2 /**< minor number of library version */ +#define SND_LIB_SUBMINOR 1 /**< subminor number of library version */ +#define SND_LIB_EXTRAVER 1000000 /**< extra version number, used mainly for betas */ +/** library version */ +#define SND_LIB_VERSION ((SND_LIB_MAJOR<<16)|\ + (SND_LIB_MINOR<<8)|\ + SND_LIB_SUBMINOR) +/** library version (string) */ +#define SND_LIB_VERSION_STR "1.2.1.2" + diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..8175c64 --- /dev/null +++ b/install-sh @@ -0,0 +1,518 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2018-03-11.20; # 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. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# 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_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 +is_target_a_directory=possibly + +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 + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +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 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + 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 + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 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 problematic for 'test' and other utilities. + 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 + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + 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. + ;; + *) + # Note that $RANDOM variable is not portable (e.g. dash); Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p' feature. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/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-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 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 + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && 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=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_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` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + 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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/libtool b/libtool new file mode 100755 index 0000000..a5f660d --- /dev/null +++ b/libtool @@ -0,0 +1,11647 @@ +#! /bin/sh +# Generated automatically by config.status (alsa-lib) 1.2.1.2 +# Libtool was configured on host e010f88cea4a: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 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 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 this program. If not, see . + + +# The names of the tagged configurations supported by this script. +available_tags='' + +# Configured defaults for sys_lib_dlsearch_path munging. +: ${LT_SYS_LIBRARY_PATH=""} + +# ### BEGIN LIBTOOL CONFIG + +# Whether or not to build static libraries. +build_old_libs=no + +# Which release of libtool.m4 was used? +macro_version=2.4.6 +macro_revision=2.4.6 + +# Whether or not to build shared libraries. +build_libtool_libs=yes + +# What type of objects to build. +pic_mode=default + +# Whether or not to optimize for fast installation. +fast_install=yes + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec= + +# Shell to use when invoking shell scripts. +SHELL="/bin/sh" + +# An echo program that protects backslashes. +ECHO="printf %s\\n" + +# The PATH separator for the build system. +PATH_SEPARATOR=":" + +# The host system. +host_alias= +host=x86_64-pc-linux-gnu +host_os=linux-gnu + +# The build system. +build_alias= +build=x86_64-pc-linux-gnu +build_os=linux-gnu + +# A sed program that does not truncate output. +SED="/usr/bin/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="/usr/bin/grep" + +# An ERE matcher. +EGREP="/usr/bin/grep -E" + +# A literal string matcher. +FGREP="/usr/bin/grep -F" + +# A BSD- or MS-compatible name lister. +NM="/usr/bin/nm -B" + +# Whether we need soft or hard links. +LN_S="ln -s" + +# What is the maximum length of a command? +max_cmd_len=1572864 + +# Object file suffix (normally "o"). +objext=o + +# Executable file suffix (normally ""). +exeext= + +# whether the shell understands "unset". +lt_unset=unset + +# turn spaces into newlines. +SP2NL="tr \\040 \\012" + +# turn newlines into spaces. +NL2SP="tr \\015\\012 \\040\\040" + +# convert $build file names to $host format. +to_host_file_cmd=func_convert_file_noop + +# convert $build files to toolchain format. +to_tool_file_cmd=func_convert_file_noop + +# An object symbol dumper. +OBJDUMP="objdump" + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method="pass_all" + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd="\$MAGIC_CMD" + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob="" + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob="no" + +# DLL creation program. +DLLTOOL="false" + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd="printf %s\\n" + +# The archiver. +AR="ar" + +# Flags to create an archive. +AR_FLAGS="cru" + +# How to feed a file listing to the archiver. +archiver_list_spec="@" + +# A symbol stripping program. +STRIP="strip" + +# Commands used to install an old-style archive. +RANLIB="ranlib" +old_postinstall_cmds="chmod 644 \$oldlib~\$RANLIB \$tool_oldlib" +old_postuninstall_cmds="" + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=no + +# A C compiler. +LTCC="gcc" + +# LTCC compiler flags. +LTCFLAGS="-O2 -fomit-frame-pointer -Wall -pipe" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\([_A-Za-z][_A-Za-z0-9]*\\)\$/\\1 \\2 \\2/p' | sed '/ __gnu_lto/d'" + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl="sed -n -e 's/^T .* \\(.*\\)\$/extern int \\1();/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(.*\\)\$/extern char \\1;/p'" + +# Transform the output of nm into a list of symbols to manually relocate. +global_symbol_to_import="" + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address="sed -n -e 's/^: \\(.*\\) .*\$/ {\"\\1\", (void *) 0},/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(.*\\)\$/ {\"\\1\", (void *) \\&\\1},/p'" + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \\(.*\\) .*\$/ {\"\\1\", (void *) 0},/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(lib.*\\)\$/ {\"\\1\", (void *) \\&\\1},/p' -e 's/^[ABCDGIRSTW][ABCDGIRSTW]* .* \\(.*\\)\$/ {\"lib\\1\", (void *) \\&\\1},/p'" + +# The name lister interface. +nm_interface="BSD nm" + +# Specify filename containing input files for $NM. +nm_file_list_spec="@" + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot= + +# Command to truncate a binary pipe. +lt_truncate_bin="/usr/bin/dd bs=4096 count=1" + +# The name of the directory that contains temporary libtool files. +objdir=.libs + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=file + +# Must we lock files when doing compilation? +need_locks="no" + +# Manifest tool. +MANIFEST_TOOL=":" + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL="" + +# Tool to change global to local symbols on Mac OS X. +NMEDIT="" + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO="" + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL="" + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64="" + +# Old archive suffix (normally "a"). +libext=a + +# Shared library suffix (normally ".so"). +shrext_cmds=".so" + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds="" + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" + +# Do we need the "lib" prefix for modules? +need_lib_prefix=no + +# Do we need a version for libraries? +need_version=no + +# Library versioning type. +version_type=linux + +# Shared library runtime path variable. +runpath_var=LD_RUN_PATH + +# Shared library path variable. +shlibpath_var=LD_LIBRARY_PATH + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=no + +# Format of library name prefix. +libname_spec="lib\$name" + +# 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="\$libname\$release\$shared_ext\$versuffix \$libname\$release\$shared_ext\$major \$libname\$shared_ext" + +# The coded name of the library, if different from the real name. +soname_spec="\$libname\$release\$shared_ext\$major" + +# Permission mode override for installation of shared libraries. +install_override_mode="" + +# Command to use after installation of a shared archive. +postinstall_cmds="" + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds="" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="PATH=\\\"\\\$PATH:/sbin\\\" ldconfig -n \$libdir" + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval="" + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=yes + +# Compile-time system search path for libraries. +sys_lib_search_path_spec="/usr/lib/gcc/x86_64-redhat-linux/8 /usr/lib64 /lib64 /usr/lib /lib " + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib /usr/lib64/qt-3.3/lib " + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path="" + +# Whether dlopen is supported. +dlopen_support=yes + +# Whether dlopen of programs is supported. +dlopen_self=yes + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=yes + +# Commands to strip libraries. +old_striplib="strip --strip-debug" +striplib="strip --strip-unneeded" + + +# The linker used to build libraries. +LD="/usr/bin/ld -m elf_x86_64" + +# How to create reloadable object files. +reload_flag=" -r" +reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs" + +# Commands used to build an old-style archive. +old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs~\$RANLIB \$tool_oldlib" + +# A language specific compiler. +CC="gcc" + +# Is the compiler the GNU compiler? +with_gcc=yes + +# Compiler flag to turn off builtin functions. +no_builtin_flag=" -fno-builtin" + +# Additional compiler flags for building library objects. +pic_flag=" -fPIC -DPIC" + +# How to pass a linker flag through the compiler. +wl="-Wl," + +# Compiler flag to prevent dynamic linking. +link_static_flag="" + +# Does compiler simultaneously support -c and -o options? +compiler_c_o="yes" + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=no + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=no + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="\$wl--export-dynamic" + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec="\$wl--whole-archive\$convenience \$wl--no-whole-archive" + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object="no" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="" + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds="" + +# Commands used to build a shared archive. +archive_cmds="\$CC -shared \$pic_flag \$libobjs \$deplibs \$compiler_flags \$wl-soname \$wl\$soname -o \$lib" +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 -shared \$pic_flag \$libobjs \$deplibs \$compiler_flags \$wl-soname \$wl\$soname \$wl-version-script \$wl\$output_objdir/\$libname.ver -o \$lib" + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds="" +module_expsym_cmds="" + +# Whether we are building with GNU ld or not. +with_gnu_ld="yes" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="" + +# Flag that enforces no undefined symbols. +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=" -D__LIBTOOL_IS_A_FOOL__ " + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator="" + +# Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=no + +# 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=no + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=no + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=unsupported + +# 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=no + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=no + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=unknown + +# Set to "yes" if exported symbols are required. +always_export_symbols=no + +# The commands to list exported symbols. +export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED 's/.* //' | sort | uniq > \$export_symbols" + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*" + +# Symbols that must always be exported. +include_expsyms="" + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds="" + +# Commands necessary for finishing linking programs. +postlink_cmds="" + +# Specify filename containing input files. +file_list_spec="" + +# How to hardcode a shared library path into an executable. +hardcode_action=immediate + +# ### END LIBTOOL CONFIG + + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +#! /bin/sh +## DO NOT EDIT - This file generated from ./build-aux/ltmain.in +## by inline-source v2014-01-03.01 + +# libtool (GNU libtool) 2.4.6 +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996-2015 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 this program. If not, see . + + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.4.6 +package_revision=2.4.6 + + +## ------ ## +## Usage. ## +## ------ ## + +# Run './libtool --help' for help with using this script from the +# command line. + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# After configure completes, it has a better idea of some of the +# shell tools we need than the defaults used by the functions shared +# with bootstrap, so set those here where they can still be over- +# ridden by the user, but otherwise take precedence. + +: ${AUTOCONF="autoconf"} +: ${AUTOMAKE="automake"} + + +## -------------------------- ## +## Source external libraries. ## +## -------------------------- ## + +# Much of our low-level functionality needs to be sourced from external +# libraries, which are installed to $pkgauxdir. + +# Set a version string for this script. +scriptversion=2015-01-20.17; # UTC + +# General shell script boiler plate, and helper functions. +# Written by Gary V. Vaughan, 2004 + +# Copyright (C) 2004-2015 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. + +# 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 3 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNES 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 . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# Evaluate this file near the top of your script to gain access to +# the functions and variables defined here: +# +# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh +# +# If you need to override any of the default environment variable +# settings, do that before evaluating this file. + + +## -------------------- ## +## Shell normalisation. ## +## -------------------- ## + +# Some shells need a little help to be as Bourne compatible as possible. +# Before doing anything else, make sure all that help has been provided! + +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 + +# NLS nuisances: We save the old values in case they are required later. +_G_user_locale= +_G_safe_locale= +for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test set = \"\${$_G_var+set}\"; then + save_$_G_var=\$$_G_var + $_G_var=C + export $_G_var + _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" + _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" + fi" +done + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Make sure IFS has a sensible default +sp=' ' +nl=' +' +IFS="$sp $nl" + +# There are apparently some retarded systems that use ';' as a PATH separator! +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 + + + +## ------------------------- ## +## Locate command utilities. ## +## ------------------------- ## + + +# func_executable_p FILE +# ---------------------- +# Check that FILE is an executable regular file. +func_executable_p () +{ + test -f "$1" && test -x "$1" +} + + +# func_path_progs PROGS_LIST CHECK_FUNC [PATH] +# -------------------------------------------- +# Search for either a program that responds to --version with output +# containing "GNU", or else returned by CHECK_FUNC otherwise, by +# trying all the directories in PATH with each of the elements of +# PROGS_LIST. +# +# CHECK_FUNC should accept the path to a candidate program, and +# set $func_check_prog_result if it truncates its output less than +# $_G_path_prog_max characters. +func_path_progs () +{ + _G_progs_list=$1 + _G_check_func=$2 + _G_PATH=${3-"$PATH"} + + _G_path_prog_max=0 + _G_path_prog_found=false + _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} + for _G_dir in $_G_PATH; do + IFS=$_G_save_IFS + test -z "$_G_dir" && _G_dir=. + for _G_prog_name in $_G_progs_list; do + for _exeext in '' .EXE; do + _G_path_prog=$_G_dir/$_G_prog_name$_exeext + func_executable_p "$_G_path_prog" || continue + case `"$_G_path_prog" --version 2>&1` in + *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; + *) $_G_check_func $_G_path_prog + func_path_progs_result=$func_check_prog_result + ;; + esac + $_G_path_prog_found && break 3 + done + done + done + IFS=$_G_save_IFS + test -z "$func_path_progs_result" && { + echo "no acceptable sed could be found in \$PATH" >&2 + exit 1 + } +} + + +# We want to be able to use the functions in this file before configure +# has figured out where the best binaries are kept, which means we have +# to search for them ourselves - except when the results are already set +# where we skip the searches. + +# Unless the user overrides by setting SED, search the path for either GNU +# sed, or the sed that truncates its output the least. +test -z "$SED" && { + _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for _G_i in 1 2 3 4 5 6 7; do + _G_sed_script=$_G_sed_script$nl$_G_sed_script + done + echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed + _G_sed_script= + + func_check_prog_sed () + { + _G_path_prog=$1 + + _G_count=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo '' >> conftest.nl + "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin + rm -f conftest.sed + SED=$func_path_progs_result +} + + +# Unless the user overrides by setting GREP, search the path for either GNU +# grep, or the grep that truncates its output the least. +test -z "$GREP" && { + func_check_prog_grep () + { + _G_path_prog=$1 + + _G_count=0 + _G_path_prog_max=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo 'GREP' >> conftest.nl + "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin + GREP=$func_path_progs_result +} + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# All uppercase variable names are used for environment variables. These +# variables can be overridden by the user before calling a script that +# uses them if a suitable command of that name is not already available +# in the command search PATH. + +: ${CP="cp -f"} +: ${ECHO="printf %s\n"} +: ${EGREP="$GREP -E"} +: ${FGREP="$GREP -F"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} + + +## -------------------- ## +## Useful sed snippets. ## +## -------------------- ## + +sed_dirname='s|/[^/]*$||' +sed_basename='s|^.*/||' + +# 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. +sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' + +# Sed substitution that converts a w32 file name or path +# that contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-'\' parameter expansions in output of sed_double_quote_subst that +# were '\'-ed in input to the same. If an odd number of '\' preceded a +# '$' in input to sed_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 '$'. +_G_bs='\\' +_G_bs2='\\\\' +_G_bs4='\\\\\\\\' +_G_dollar='\$' +sed_double_backslash="\ + s/$_G_bs4/&\\ +/g + s/^$_G_bs2$_G_dollar/$_G_bs&/ + s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g + s/\n//g" + + +## ----------------- ## +## Global variables. ## +## ----------------- ## + +# Except for the global variables explicitly listed below, the following +# functions in the '^func_' namespace, and the '^require_' namespace +# variables initialised in the 'Resource management' section, sourcing +# this file will not pollute your global namespace with anything +# else. There's no portable way to scope variables in Bourne shell +# though, so actually running these functions will sometimes place +# results into a variable named after the function, and often use +# temporary variables in the '^_G_' namespace. If you are careful to +# avoid using those namespaces casually in your sourcing script, things +# should continue to work as you expect. And, of course, you can freely +# overwrite any of the functions or variables defined here before +# calling anything to customize them. + +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. + +# Allow overriding, eg assuming that you follow the convention of +# putting '$debug_cmd' at the start of all your functions, you can get +# bash to show function call trace with: +# +# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +debug_cmd=${debug_cmd-":"} +exit_cmd=: + +# By convention, finish your script with: +# +# exit $exit_status +# +# so that you can set exit_status to non-zero if you want to indicate +# something went wrong during execution without actually bailing out at +# the point of failure. +exit_status=$EXIT_SUCCESS + +# 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. +progname=`$ECHO "$progpath" |$SED "$sed_basename"` + +# Make sure we have an absolute progpath for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` + progdir=`cd "$progdir" && pwd` + progpath=$progdir/$progname + ;; + *) + _G_IFS=$IFS + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS=$_G_IFS + test -x "$progdir/$progname" && break + done + IFS=$_G_IFS + test -n "$progdir" || progdir=`pwd` + progpath=$progdir/$progname + ;; +esac + + +## ----------------- ## +## Standard options. ## +## ----------------- ## + +# The following options affect the operation of the functions defined +# below, and should be set appropriately depending on run-time para- +# meters passed on the command line. + +opt_dry_run=false +opt_quiet=false +opt_verbose=false + +# Categories 'all' and 'none' are always available. Append any others +# you will pass as the first argument to func_warning from your own +# code. +warning_categories= + +# By default, display warnings according to 'opt_warning_types'. Set +# 'warning_func' to ':' to elide all warnings, or func_fatal_error to +# treat the next displayed warning as a fatal error. +warning_func=func_warn_and_continue + +# Set to 'all' to display all warnings, 'none' to suppress all +# warnings, or a space delimited list of some subset of +# 'warning_categories' to display only the listed warnings. +opt_warning_types=all + + +## -------------------- ## +## Resource management. ## +## -------------------- ## + +# This section contains definitions for functions that each ensure a +# particular resource (a file, or a non-empty configuration variable for +# example) is available, and if appropriate to extract default values +# from pertinent package files. Call them using their associated +# 'require_*' variable to ensure that they are executed, at most, once. +# +# It's entirely deliberate that calling these functions can set +# variables that don't obey the namespace limitations obeyed by the rest +# of this file, in order that that they be as useful as possible to +# callers. + + +# require_term_colors +# ------------------- +# Allow display of bold text on terminals that support it. +require_term_colors=func_require_term_colors +func_require_term_colors () +{ + $debug_cmd + + test -t 1 && { + # COLORTERM and USE_ANSI_COLORS environment variables take + # precedence, because most terminfo databases neglect to describe + # whether color sequences are supported. + test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} + + if test 1 = "$USE_ANSI_COLORS"; then + # Standard ANSI escape sequences + tc_reset='' + tc_bold=''; tc_standout='' + tc_red=''; tc_green='' + tc_blue=''; tc_cyan='' + else + # Otherwise trust the terminfo database after all. + test -n "`tput sgr0 2>/dev/null`" && { + tc_reset=`tput sgr0` + test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` + tc_standout=$tc_bold + test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` + test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` + test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` + test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` + test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` + } + fi + } + + require_term_colors=: +} + + +## ----------------- ## +## Function library. ## +## ----------------- ## + +# This section contains a variety of useful functions to call in your +# scripts. Take note of the portable wrappers for features provided by +# some modern shells, which will fall back to slower equivalents on +# less featureful shells. + + +# func_append VAR VALUE +# --------------------- +# Append VALUE onto the existing contents of VAR. + + # We should try to minimise forks, especially on Windows where they are + # unreasonably slow, so skip the feature probes when bash or zsh are + # being used: + if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then + : ${_G_HAVE_ARITH_OP="yes"} + : ${_G_HAVE_XSI_OPS="yes"} + # The += operator was introduced in bash 3.1 + case $BASH_VERSION in + [12].* | 3.0 | 3.0*) ;; + *) + : ${_G_HAVE_PLUSEQ_OP="yes"} + ;; + esac + fi + + # _G_HAVE_PLUSEQ_OP + # Can be empty, in which case the shell is probed, "yes" if += is + # useable or anything else if it does not work. + test -z "$_G_HAVE_PLUSEQ_OP" \ + && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ + && _G_HAVE_PLUSEQ_OP=yes + +if test yes = "$_G_HAVE_PLUSEQ_OP" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_append () + { + $debug_cmd + + eval "$1+=\$2" + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_append () + { + $debug_cmd + + eval "$1=\$$1\$2" + } +fi + + +# func_append_quoted VAR VALUE +# ---------------------------- +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +if test yes = "$_G_HAVE_PLUSEQ_OP"; then + eval 'func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1+=\\ \$func_quote_for_eval_result" + }' +else + func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1=\$$1\\ \$func_quote_for_eval_result" + } +fi + + +# func_append_uniq VAR VALUE +# -------------------------- +# Append unique VALUE onto the existing contents of VAR, assuming +# entries are delimited by the first character of VALUE. For example: +# +# func_append_uniq options " --another-option option-argument" +# +# will only append to $options if " --another-option option-argument " +# is not already present somewhere in $options already (note spaces at +# each end implied by leading space in second argument). +func_append_uniq () +{ + $debug_cmd + + eval _G_current_value='`$ECHO $'$1'`' + _G_delim=`expr "$2" : '\(.\)'` + + case $_G_delim$_G_current_value$_G_delim in + *"$2$_G_delim"*) ;; + *) func_append "$@" ;; + esac +} + + +# func_arith TERM... +# ------------------ +# Set func_arith_result to the result of evaluating TERMs. + test -z "$_G_HAVE_ARITH_OP" \ + && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ + && _G_HAVE_ARITH_OP=yes + +if test yes = "$_G_HAVE_ARITH_OP"; then + eval 'func_arith () + { + $debug_cmd + + func_arith_result=$(( $* )) + }' +else + func_arith () + { + $debug_cmd + + func_arith_result=`expr "$@"` + } +fi + + +# func_basename FILE +# ------------------ +# Set func_basename_result to FILE with everything up to and including +# the last / stripped. +if test yes = "$_G_HAVE_XSI_OPS"; then + # If this shell supports suffix pattern removal, then use it to avoid + # forking. Hide the definitions single quotes in case the shell chokes + # on unsupported syntax... + _b='func_basename_result=${1##*/}' + _d='case $1 in + */*) func_dirname_result=${1%/*}$2 ;; + * ) func_dirname_result=$3 ;; + esac' + +else + # ...otherwise fall back to using sed. + _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' + _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` + if test "X$func_dirname_result" = "X$1"; then + func_dirname_result=$3 + else + func_append func_dirname_result "$2" + fi' +fi + +eval 'func_basename () +{ + $debug_cmd + + '"$_b"' +}' + + +# func_dirname FILE APPEND NONDIR_REPLACEMENT +# ------------------------------------------- +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +eval 'func_dirname () +{ + $debug_cmd + + '"$_d"' +}' + + +# 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" +# For efficiency, we do not delegate to the functions above but instead +# duplicate the functionality here. +eval 'func_dirname_and_basename () +{ + $debug_cmd + + '"$_b"' + '"$_d"' +}' + + +# func_echo ARG... +# ---------------- +# Echo program name prefixed message. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_echo_all ARG... +# -------------------- +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + + +# func_echo_infix_1 INFIX ARG... +# ------------------------------ +# Echo program name, followed by INFIX on the first line, with any +# additional lines not showing INFIX. +func_echo_infix_1 () +{ + $debug_cmd + + $require_term_colors + + _G_infix=$1; shift + _G_indent=$_G_infix + _G_prefix="$progname: $_G_infix: " + _G_message=$* + + # Strip color escape sequences before counting printable length + for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" + do + test -n "$_G_tc" && { + _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` + _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` + } + done + _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes + + func_echo_infix_1_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_infix_1_IFS + $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 + _G_prefix=$_G_indent + done + IFS=$func_echo_infix_1_IFS +} + + +# func_error ARG... +# ----------------- +# Echo program name prefixed message to standard error. +func_error () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 +} + + +# func_fatal_error ARG... +# ----------------------- +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + $debug_cmd + + func_error "$*" + exit $EXIT_FAILURE +} + + +# func_grep EXPRESSION FILENAME +# ----------------------------- +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $debug_cmd + + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_len STRING +# --------------- +# Set func_len_result to the length of STRING. STRING may not +# start with a hyphen. + test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_len () + { + $debug_cmd + + func_len_result=${#1} + }' +else + func_len () + { + $debug_cmd + + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` + } +fi + + +# func_mkdir_p DIRECTORY-PATH +# --------------------------- +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + $debug_cmd + + _G_directory_path=$1 + _G_dir_list= + + if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then + + # Protect directory names starting with '-' + case $_G_directory_path in + -*) _G_directory_path=./$_G_directory_path ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$_G_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + _G_dir_list=$_G_directory_path:$_G_dir_list + + # If the last portion added has no slash in it, the list is done + case $_G_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` + done + _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` + + func_mkdir_p_IFS=$IFS; IFS=: + for _G_dir in $_G_dir_list; do + IFS=$func_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 "$_G_dir" 2>/dev/null || : + done + IFS=$func_mkdir_p_IFS + + # Bail out if we (or some other process) failed to create a directory. + test -d "$_G_directory_path" || \ + func_fatal_error "Failed to create '$1'" + fi +} + + +# func_mktempdir [BASENAME] +# ------------------------- +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, BASENAME is the basename for that directory. +func_mktempdir () +{ + $debug_cmd + + _G_template=${TMPDIR-/tmp}/${1-$progname} + + if test : = "$opt_dry_run"; then + # Return a directory name, but don't create it in dry-run mode + _G_tmpdir=$_G_template-$$ + else + + # If mktemp works, use that first and foremost + _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` + + if test ! -d "$_G_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + _G_tmpdir=$_G_template-${RANDOM-0}$$ + + func_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$_G_tmpdir" + umask $func_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$_G_tmpdir" || \ + func_fatal_error "cannot create temporary directory '$_G_tmpdir'" + fi + + $ECHO "$_G_tmpdir" +} + + +# func_normal_abspath PATH +# ------------------------ +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +func_normal_abspath () +{ + $debug_cmd + + # These SED scripts presuppose an absolute path with a trailing slash. + _G_pathcar='s|^/\([^/]*\).*$|\1|' + _G_pathcdr='s|^/[^/]*||' + _G_removedotparts=':dotsl + s|/\./|/|g + t dotsl + s|/\.$|/|' + _G_collapseslashes='s|/\{1,\}|/|g' + _G_finalslash='s|/*$|/|' + + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` + while :; do + # Processed it all yet? + if test / = "$func_normal_abspath_tpath"; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result"; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + + +# func_notquiet ARG... +# -------------------- +# Echo program name prefixed message only when not in quiet mode. +func_notquiet () +{ + $debug_cmd + + $opt_quiet || 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_relative_path SRCDIR DSTDIR +# -------------------------------- +# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. +func_relative_path () +{ + $debug_cmd + + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=$func_dirname_result + if test -z "$func_relative_path_tlibdir"; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test -n "$func_stripname_result"; then + func_append func_relative_path_result "/$func_stripname_result" + fi + + # Normalisation. If bindir is libdir, return '.' else relative path. + if test -n "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + fi + + test -n "$func_relative_path_result" || func_relative_path_result=. + + : +} + + +# func_quote_for_eval ARG... +# -------------------------- +# Aesthetically quote ARGs to be evaled later. +# This function returns two values: +# i) func_quote_for_eval_result +# double-quoted, suitable for a subsequent eval +# ii) func_quote_for_eval_unquoted_result +# has all characters that are still active within double +# quotes backslashified. +func_quote_for_eval () +{ + $debug_cmd + + func_quote_for_eval_unquoted_result= + func_quote_for_eval_result= + while test 0 -lt $#; do + case $1 in + *[\\\`\"\$]*) + _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; + *) + _G_unquoted_arg=$1 ;; + esac + if test -n "$func_quote_for_eval_unquoted_result"; then + func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" + else + func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" + fi + + case $_G_unquoted_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_quoted_arg=\"$_G_unquoted_arg\" + ;; + *) + _G_quoted_arg=$_G_unquoted_arg + ;; + esac + + if test -n "$func_quote_for_eval_result"; then + func_append func_quote_for_eval_result " $_G_quoted_arg" + else + func_append func_quote_for_eval_result "$_G_quoted_arg" + fi + shift + done +} + + +# 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 () +{ + $debug_cmd + + case $1 in + *[\\\`\"]*) + _G_arg=`$ECHO "$1" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; + *) + _G_arg=$1 ;; + esac + + case $_G_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. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_arg=\"$_G_arg\" + ;; + esac + + func_quote_for_expand_result=$_G_arg +} + + +# func_stripname PREFIX SUFFIX NAME +# --------------------------------- +# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. +# 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). +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_stripname () + { + $debug_cmd + + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary variable first. + func_stripname_result=$3 + func_stripname_result=${func_stripname_result#"$1"} + func_stripname_result=${func_stripname_result%"$2"} + }' +else + func_stripname () + { + $debug_cmd + + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; + esac + } +fi + + +# func_show_eval CMD [FAIL_EXP] +# ----------------------------- +# Unless opt_quiet 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 () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + func_quote_for_expand "$_G_cmd" + eval "func_notquiet $func_quote_for_expand_result" + + $opt_dry_run || { + eval "$_G_cmd" + _G_status=$? + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_show_eval_locale CMD [FAIL_EXP] +# ------------------------------------ +# Unless opt_quiet 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 () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + $opt_quiet || { + func_quote_for_expand "$_G_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + $opt_dry_run || { + eval "$_G_user_locale + $_G_cmd" + _G_status=$? + eval "$_G_safe_locale" + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_tr_sh +# ---------- +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + $debug_cmd + + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_verbose ARG... +# ------------------- +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $debug_cmd + + $opt_verbose && func_echo "$*" + + : +} + + +# func_warn_and_continue ARG... +# ----------------------------- +# Echo program name prefixed warning message to standard error. +func_warn_and_continue () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 +} + + +# func_warning CATEGORY ARG... +# ---------------------------- +# Echo program name prefixed warning message to standard error. Warning +# messages can be filtered according to CATEGORY, where this function +# elides messages where CATEGORY is not listed in the global variable +# 'opt_warning_types'. +func_warning () +{ + $debug_cmd + + # CATEGORY must be in the warning_categories list! + case " $warning_categories " in + *" $1 "*) ;; + *) func_internal_error "invalid warning category '$1'" ;; + esac + + _G_category=$1 + shift + + case " $opt_warning_types " in + *" $_G_category "*) $warning_func ${1+"$@"} ;; + esac +} + + +# func_sort_ver VER1 VER2 +# ----------------------- +# 'sort -V' is not generally available. +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +func_sort_ver () +{ + $debug_cmd + + printf '%s\n%s\n' "$1" "$2" \ + | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n +} + +# func_lt_ver PREV CURR +# --------------------- +# Return true if PREV and CURR are in the correct order according to +# func_sort_ver, otherwise false. Use it like this: +# +# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." +func_lt_ver () +{ + $debug_cmd + + test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: +#! /bin/sh + +# Set a version string for this script. +scriptversion=2014-01-07.03; # UTC + +# A portable, pluggable option parser for Bourne shell. +# Written by Gary V. Vaughan, 2010 + +# Copyright (C) 2010-2015 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. + +# 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 3 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, see . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# This file is a library for parsing options in your shell scripts along +# with assorted other useful supporting features that you can make use +# of too. +# +# For the simplest scripts you might need only: +# +# #!/bin/sh +# . relative/path/to/funclib.sh +# . relative/path/to/options-parser +# scriptversion=1.0 +# func_options ${1+"$@"} +# eval set dummy "$func_options_result"; shift +# ...rest of your script... +# +# In order for the '--version' option to work, you will need to have a +# suitably formatted comment like the one at the top of this file +# starting with '# Written by ' and ending with '# warranty; '. +# +# For '-h' and '--help' to work, you will also need a one line +# description of your script's purpose in a comment directly above the +# '# Written by ' line, like the one at the top of this file. +# +# The default options also support '--debug', which will turn on shell +# execution tracing (see the comment above debug_cmd below for another +# use), and '--verbose' and the func_verbose function to allow your script +# to display verbose messages only when your user has specified +# '--verbose'. +# +# After sourcing this file, you can plug processing for additional +# options by amending the variables from the 'Configuration' section +# below, and following the instructions in the 'Option parsing' +# section further down. + +## -------------- ## +## Configuration. ## +## -------------- ## + +# You should override these variables in your script after sourcing this +# file so that they reflect the customisations you have added to the +# option parser. + +# The usage line for option parsing errors and the start of '-h' and +# '--help' output messages. You can embed shell variables for delayed +# expansion at the time the message is displayed, but you will need to +# quote other shell meta-characters carefully to prevent them being +# expanded when the contents are evaled. +usage='$progpath [OPTION]...' + +# Short help message in response to '-h' and '--help'. Add to this or +# override it after sourcing this library to reflect the full set of +# options your script accepts. +usage_message="\ + --debug enable verbose shell tracing + -W, --warnings=CATEGORY + report the warnings falling in CATEGORY [all] + -v, --verbose verbosely report processing + --version print version information and exit + -h, --help print short or long help message and exit +" + +# Additional text appended to 'usage_message' in response to '--help'. +long_help_message=" +Warning categories include: + 'all' show all warnings + 'none' turn off all the warnings + 'error' warnings are treated as fatal errors" + +# Help message printed before fatal option parsing errors. +fatal_help="Try '\$progname --help' for more information." + + + +## ------------------------- ## +## Hook function management. ## +## ------------------------- ## + +# This section contains functions for adding, removing, and running hooks +# to the main code. A hook is just a named list of of function, that can +# be run in order later on. + +# func_hookable FUNC_NAME +# ----------------------- +# Declare that FUNC_NAME will run hooks added with +# 'func_add_hook FUNC_NAME ...'. +func_hookable () +{ + $debug_cmd + + func_append hookable_fns " $1" +} + + +# func_add_hook FUNC_NAME HOOK_FUNC +# --------------------------------- +# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must +# first have been declared "hookable" by a call to 'func_hookable'. +func_add_hook () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not accept hook functions." ;; + esac + + eval func_append ${1}_hooks '" $2"' +} + + +# func_remove_hook FUNC_NAME HOOK_FUNC +# ------------------------------------ +# Remove HOOK_FUNC from the list of functions called by FUNC_NAME. +func_remove_hook () +{ + $debug_cmd + + eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' +} + + +# func_run_hooks FUNC_NAME [ARG]... +# --------------------------------- +# Run all hook functions registered to FUNC_NAME. +# It is assumed that the list of hook functions contains nothing more +# than a whitespace-delimited list of legal shell function names, and +# no effort is wasted trying to catch shell meta-characters or preserve +# whitespace. +func_run_hooks () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not support hook funcions.n" ;; + esac + + eval _G_hook_fns=\$$1_hooks; shift + + for _G_hook in $_G_hook_fns; do + eval $_G_hook '"$@"' + + # store returned options list back into positional + # parameters for next 'cmd' execution. + eval _G_hook_result=\$${_G_hook}_result + eval set dummy "$_G_hook_result"; shift + done + + func_quote_for_eval ${1+"$@"} + func_run_hooks_result=$func_quote_for_eval_result +} + + + +## --------------- ## +## Option parsing. ## +## --------------- ## + +# In order to add your own option parsing hooks, you must accept the +# full positional parameter list in your hook function, remove any +# options that you action, and then pass back the remaining unprocessed +# options in '_result', escaped suitably for +# 'eval'. Like this: +# +# my_options_prep () +# { +# $debug_cmd +# +# # Extend the existing usage message. +# usage_message=$usage_message' +# -s, --silent don'\''t print informational messages +# ' +# +# func_quote_for_eval ${1+"$@"} +# my_options_prep_result=$func_quote_for_eval_result +# } +# func_add_hook func_options_prep my_options_prep +# +# +# my_silent_option () +# { +# $debug_cmd +# +# # Note that for efficiency, we parse as many options as we can +# # recognise in a loop before passing the remainder back to the +# # caller on the first unrecognised argument we encounter. +# while test $# -gt 0; do +# opt=$1; shift +# case $opt in +# --silent|-s) opt_silent=: ;; +# # Separate non-argument short options: +# -s*) func_split_short_opt "$_G_opt" +# set dummy "$func_split_short_opt_name" \ +# "-$func_split_short_opt_arg" ${1+"$@"} +# shift +# ;; +# *) set dummy "$_G_opt" "$*"; shift; break ;; +# esac +# done +# +# func_quote_for_eval ${1+"$@"} +# my_silent_option_result=$func_quote_for_eval_result +# } +# func_add_hook func_parse_options my_silent_option +# +# +# my_option_validation () +# { +# $debug_cmd +# +# $opt_silent && $opt_verbose && func_fatal_help "\ +# '--silent' and '--verbose' options are mutually exclusive." +# +# func_quote_for_eval ${1+"$@"} +# my_option_validation_result=$func_quote_for_eval_result +# } +# func_add_hook func_validate_options my_option_validation +# +# You'll alse need to manually amend $usage_message to reflect the extra +# options you parse. It's preferable to append if you can, so that +# multiple option parsing hooks can be added safely. + + +# func_options [ARG]... +# --------------------- +# All the functions called inside func_options are hookable. See the +# individual implementations for details. +func_hookable func_options +func_options () +{ + $debug_cmd + + func_options_prep ${1+"$@"} + eval func_parse_options \ + ${func_options_prep_result+"$func_options_prep_result"} + eval func_validate_options \ + ${func_parse_options_result+"$func_parse_options_result"} + + eval func_run_hooks func_options \ + ${func_validate_options_result+"$func_validate_options_result"} + + # save modified positional parameters for caller + func_options_result=$func_run_hooks_result +} + + +# func_options_prep [ARG]... +# -------------------------- +# All initialisations required before starting the option parse loop. +# Note that when calling hook functions, we pass through the list of +# positional parameters. If a hook function modifies that list, and +# needs to propogate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before +# returning. +func_hookable func_options_prep +func_options_prep () +{ + $debug_cmd + + # Option defaults: + opt_verbose=false + opt_warning_types= + + func_run_hooks func_options_prep ${1+"$@"} + + # save modified positional parameters for caller + func_options_prep_result=$func_run_hooks_result +} + + +# func_parse_options [ARG]... +# --------------------------- +# The main option parsing loop. +func_hookable func_parse_options +func_parse_options () +{ + $debug_cmd + + func_parse_options_result= + + # this just eases exit handling + while test $# -gt 0; do + # Defer to hook functions for initial option parsing, so they + # get priority in the event of reusing an option name. + func_run_hooks func_parse_options ${1+"$@"} + + # Adjust func_parse_options positional parameters to match + eval set dummy "$func_run_hooks_result"; shift + + # Break out of the loop if we already parsed every option. + test $# -gt 0 || break + + _G_opt=$1 + shift + case $_G_opt in + --debug|-x) debug_cmd='set -x' + func_echo "enabling shell trace mode" + $debug_cmd + ;; + + --no-warnings|--no-warning|--no-warn) + set dummy --warnings none ${1+"$@"} + shift + ;; + + --warnings|--warning|-W) + test $# = 0 && func_missing_arg $_G_opt && break + case " $warning_categories $1" in + *" $1 "*) + # trailing space prevents matching last $1 above + func_append_uniq opt_warning_types " $1" + ;; + *all) + opt_warning_types=$warning_categories + ;; + *none) + opt_warning_types=none + warning_func=: + ;; + *error) + opt_warning_types=$warning_categories + warning_func=func_fatal_error + ;; + *) + func_fatal_error \ + "unsupported warning category: '$1'" + ;; + esac + shift + ;; + + --verbose|-v) opt_verbose=: ;; + --version) func_version ;; + -\?|-h) func_usage ;; + --help) func_help ;; + + # Separate optargs to long options (plugins may need this): + --*=*) func_split_equals "$_G_opt" + set dummy "$func_split_equals_lhs" \ + "$func_split_equals_rhs" ${1+"$@"} + shift + ;; + + # Separate optargs to short options: + -W*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-v*|-x*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + func_parse_options_result=$func_quote_for_eval_result +} + + +# func_validate_options [ARG]... +# ------------------------------ +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +func_hookable func_validate_options +func_validate_options () +{ + $debug_cmd + + # Display all warnings if -W was not given. + test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" + + func_run_hooks func_validate_options ${1+"$@"} + + # Bail if the options were screwed! + $exit_cmd $EXIT_FAILURE + + # save modified positional parameters for caller + func_validate_options_result=$func_run_hooks_result +} + + + +## ----------------- ## +## Helper functions. ## +## ----------------- ## + +# This section contains the helper functions used by the rest of the +# hookable option parser framework in ascii-betical order. + + +# func_fatal_help ARG... +# ---------------------- +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + eval \$ECHO \""$fatal_help"\" + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + + +# func_help +# --------- +# Echo long help message to standard output and exit. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message" + exit 0 +} + + +# func_missing_arg ARGNAME +# ------------------------ +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $debug_cmd + + func_error "Missing argument for '$1'." + exit_cmd=exit +} + + +# func_split_equals STRING +# ------------------------ +# Set func_split_equals_lhs and func_split_equals_rhs shell variables after +# splitting STRING at the '=' sign. +test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=${1%%=*} + func_split_equals_rhs=${1#*=} + test "x$func_split_equals_lhs" = "x$1" \ + && func_split_equals_rhs= + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` + func_split_equals_rhs= + test "x$func_split_equals_lhs" = "x$1" \ + || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` + } +fi #func_split_equals + + +# func_split_short_opt SHORTOPT +# ----------------------------- +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"} + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` + func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` + } +fi #func_split_short_opt + + +# func_usage +# ---------- +# Echo short help message to standard output and exit. +func_usage () +{ + $debug_cmd + + func_usage_message + $ECHO "Run '$progname --help |${PAGER-more}' for full usage" + exit 0 +} + + +# func_usage_message +# ------------------ +# Echo short help message to standard output. +func_usage_message () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + echo + $SED -n 's|^# || + /^Written by/{ + x;p;x + } + h + /^Written by/q' < "$progpath" + echo + eval \$ECHO \""$usage_message"\" +} + + +# func_version +# ------------ +# Echo version message to standard output and exit. +func_version () +{ + $debug_cmd + + printf '%s\n' "$progname $scriptversion" + $SED -n ' + /(C)/!b go + :more + /\./!{ + N + s|\n# | | + b more + } + :go + /^# Written by /,/# warranty; / { + s|^# || + s|^# *$|| + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + p + } + /^# Written by / { + s|^# || + p + } + /^warranty; /q' < "$progpath" + + exit $? +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: + +# Set a version string. +scriptversion='(GNU libtool) 2.4.6' + + +# func_echo ARG... +# ---------------- +# Libtool also displays the current mode in messages, so override +# funclib.sh func_echo with this custom definition. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + $debug_cmd + + $warning_func ${1+"$@"} +} + + +## ---------------- ## +## Options parsing. ## +## ---------------- ## + +# Hook in the functions to make sure our own options are parsed during +# the option parsing loop. + +usage='$progpath [OPTION]... [MODE-ARG]...' + +# Short help message in response to '-h'. +usage_message="Options: + --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 + --no-warnings equivalent to '-Wnone' + --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 more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message +" + +# Additional text appended to 'usage_message' in response to '--help'. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$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. When passed as first option, +'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. +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) + version: $progname (GNU libtool) 2.4.6 + automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` + autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` + +Report bugs to . +GNU libtool home page: . +General help using GNU software: ." + exit 0 +} + + +# func_lo2o OBJECT-NAME +# --------------------- +# Transform OBJECT-NAME from a '.lo' suffix to the platform specific +# object suffix. + +lo2o=s/\\.lo\$/.$objext/ +o2lo=s/\\.$objext\$/.lo/ + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_lo2o () + { + case $1 in + *.lo) func_lo2o_result=${1%.lo}.$objext ;; + * ) func_lo2o_result=$1 ;; + esac + }' + + # func_xform LIBOBJ-OR-SOURCE + # --------------------------- + # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) + # suffix to a '.lo' libtool-object suffix. + eval 'func_xform () + { + func_xform_result=${1%.*}.lo + }' +else + # ...otherwise fall back to using sed. + func_lo2o () + { + func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` + } + + func_xform () + { + func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` + } +fi + + +# func_fatal_configuration ARG... +# ------------------------------- +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_fatal_error ${1+"$@"} \ + "See the $PACKAGE documentation for more information." \ + "Fatal configuration error." +} + + +# func_config +# ----------- +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + + +# func_features +# ------------- +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test yes = "$build_libtool_libs"; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test yes = "$build_old_libs"; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + + +# func_enable_tag TAGNAME +# ----------------------- +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname=$1 + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf=/$re_begincf/,/$re_endcf/p + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/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 +} + + +# 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 +} + + +# libtool_options_prep [ARG]... +# ----------------------------- +# Preparation for options parsed by libtool. +libtool_options_prep () +{ + $debug_mode + + # Option defaults: + opt_config=false + opt_dlopen= + opt_dry_run=false + opt_help=false + opt_mode= + opt_preserve_dup_deps=false + opt_quiet=false + + nonopt= + preserve_args= + + # 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 + + # Pass back the list of options. + func_quote_for_eval ${1+"$@"} + libtool_options_prep_result=$func_quote_for_eval_result +} +func_add_hook func_options_prep libtool_options_prep + + +# libtool_parse_options [ARG]... +# --------------------------------- +# Provide handling for libtool specific options. +libtool_parse_options () +{ + $debug_cmd + + # Perform our own loop to consume as many options as possible in + # each iteration. + while test $# -gt 0; do + _G_opt=$1 + shift + case $_G_opt in + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + + --config) func_config ;; + + --dlopen|-dlopen) + opt_dlopen="${opt_dlopen+$opt_dlopen +}$1" + shift + ;; + + --preserve-dup-deps) + opt_preserve_dup_deps=: ;; + + --features) func_features ;; + + --finish) set dummy --mode finish ${1+"$@"}; shift ;; + + --help) opt_help=: ;; + + --help-all) opt_help=': help-all' ;; + + --mode) test $# = 0 && func_missing_arg $_G_opt && break + opt_mode=$1 + 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 $_G_opt" + exit_cmd=exit + break + ;; + esac + shift + ;; + + --no-silent|--no-quiet) + opt_quiet=false + func_append preserve_args " $_G_opt" + ;; + + --no-warnings|--no-warning|--no-warn) + opt_warning=false + func_append preserve_args " $_G_opt" + ;; + + --no-verbose) + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --silent|--quiet) + opt_quiet=: + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --tag) test $# = 0 && func_missing_arg $_G_opt && break + opt_tag=$1 + func_append preserve_args " $_G_opt $1" + func_enable_tag "$1" + shift + ;; + + --verbose|-v) opt_quiet=false + opt_verbose=: + func_append preserve_args " $_G_opt" + ;; + + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + libtool_parse_options_result=$func_quote_for_eval_result +} +func_add_hook func_parse_options libtool_parse_options + + + +# libtool_validate_options [ARG]... +# --------------------------------- +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +libtool_validate_options () +{ + # save first non-option argument + if test 0 -lt $#; then + nonopt=$1 + shift + fi + + # preserve --debug + test : = "$debug_cmd" || func_append preserve_args " --debug" + + case $host in + # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 + # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + test yes != "$build_libtool_libs" \ + && test yes != "$build_old_libs" \ + && func_fatal_configuration "not configured to build any kind of library" + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test execute != "$opt_mode"; 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=$opt_mode' for more information." + } + + # Pass back the unparsed argument list + func_quote_for_eval ${1+"$@"} + libtool_validate_options_result=$func_quote_for_eval_result +} +func_add_hook func_validate_options libtool_validate_options + + +# Process options as early as possible so that --help and --version +# can return quickly. +func_options ${1+"$@"} +eval set dummy "$func_options_result"; shift + + + +## ----------- ## +## Main. ## +## ----------- ## + +magic='%%%MAGIC variable%%%' +magic_exe='%%%MAGIC EXE variable%%%' + +# Global variables. +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# func_generated_by_libtool +# True iff stdin has been generated by Libtool. This function is only +# a basic sanity check; it will hardly flush out determined imposters. +func_generated_by_libtool_p () +{ + $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# 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 | func_generated_by_libtool_p +} + +# 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 yes = "$lalib_p" +} + +# 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 () +{ + test -f "$1" && + $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# 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_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper +} + +# 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 () +{ + $debug_cmd + + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + 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 () +{ + $debug_cmd + + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case $lt_sysroot:$1 in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result='='$func_stripname_result + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$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 () +{ + $debug_cmd + + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + 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 "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # 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_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # 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 yes = "$build_libtool_libs"; then + write_lobj=\'$2\' + else + write_lobj=none + fi + + if test yes = "$build_old_libs"; then + write_oldobj=\'$3\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $debug_cmd + + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result= + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result"; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $debug_cmd + + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $debug_cmd + + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $debug_cmd + + if test -z "$2" && test -n "$1"; then + func_error "Could not determine host file name corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result=$1 + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $debug_cmd + + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " '$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result=$3 + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $debug_cmd + + case $4 in + $1 ) func_to_host_path_result=$3$func_to_host_path_result + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via '$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $debug_cmd + + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $debug_cmd + + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result=$1 +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result=$func_convert_core_msys_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result=$func_convert_core_file_wine_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via '$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# 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. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $debug_cmd + + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd=func_convert_path_$func_stripname_result + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $debug_cmd + + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result=$1 +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # 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_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_msys_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_path_wine_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # 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_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_dll_def_p FILE +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with _LT_DLL_DEF_P in libtool.m4 +func_dll_def_p () +{ + $debug_cmd + + func_dll_def_p_tmp=`$SED -n \ + -e 's/^[ ]*//' \ + -e '/^\(;.*\)*$/d' \ + -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ + -e q \ + "$1"` + test DEF = "$func_dll_def_p_tmp" +} + + +# func_mode_compile arg... +func_mode_compile () +{ + $debug_cmd + + # Get the compilation command and the source file. + base_compile= + srcfile=$nonopt # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg=$arg + arg_mode=normal + ;; + + target ) + libobj=$arg + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify '-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs=$IFS; IFS=, + for arg in $args; do + IFS=$save_ifs + func_append_quoted lastarg "$arg" + done + IFS=$save_ifs + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg=$srcfile + srcfile=$arg + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with '-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj=$func_basename_result + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from '$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test yes = "$build_libtool_libs" \ + || func_fatal_configuration "cannot build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && 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 yes = "$build_old_libs"; 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 no = "$pic_mode" && test pass_all != "$deplibs_check_method"; 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 no = "$compiler_c_o"; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; 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 yes = "$need_locks"; 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 warn = "$need_locks"; 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 + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test yes = "$build_libtool_libs"; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test no != "$pic_mode"; 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 + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + 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 yes = "$suppress_opt"; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test yes = "$build_old_libs"; then + if test yes != "$pic_mode"; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test yes = "$compiler_c_o"; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + 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 no != "$need_locks"; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test compile = "$opt_mode" && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_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 build PIC objects only + -prefer-non-pic try to build 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 + -Wc,FLAG pass FLAG directly to the compiler + +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-dir 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 + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -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 + -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) + -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 + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +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 '$opt_mode'" + ;; + esac + + echo + $ECHO "Try '$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test : = "$opt_help"; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | $SED -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + $SED '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $debug_cmd + + # 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 $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "'$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # 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 + func_append 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 + -* | *.la | *.lo ) ;; + *) + # 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_append_quoted args "$file" + done + + if $opt_dry_run; then + # 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 + else + 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 + fi +} + +test execute = "$opt_mode" && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $debug_cmd + + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "'$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument '$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and '=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + 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" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_quiet && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + 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 "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test finish = "$opt_mode" && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $debug_cmd + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac + 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" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=false + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=: ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test X-m = "X$prev" && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_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 -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + 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=: + if $isdir; 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. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # 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 "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir=$func_dirname_result + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -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 "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "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_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme=$stripme + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme= + ;; + esac + ;; + os2*) + 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" && func_append 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 yes = "$build_old_libs"; 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=: + 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 "$lib" | $SED 's%^.*/%%g'` + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "'$lib' has not been installed in '$libdir'" + finalize=false + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test no = "$fast_install" && test -n "$relink_command"; then + $opt_dry_run || { + if $finalize; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file=$func_basename_result + outputname=$tmpdir/$file + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_quiet || { + 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 "$file$stripped_ext" | $SED "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_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_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 install = "$opt_mode" && 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 () +{ + $debug_cmd + + my_outputname=$1 + my_originator=$2 + my_pic_p=${3-false} + my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* External symbol declarations for the compiler. */\ +" + + if test yes = "$dlself"; 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 "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from '$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $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 + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename= + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname"; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename=$func_basename_result + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename"; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + 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 + + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) + {" + $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ + } +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi + + 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" ;; + *) + $my_pic_p && pic_flag_for_symtable=" $pic_flag" + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append 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" "${nlist}I"' + + # 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 "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "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 "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# 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. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $debug_cmd + + 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 + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + case $nm_interface in + "MS dumpbin") + if func_cygming_ms_implib_p "$1" || + func_cygming_gnu_implib_p "$1" + then + win32_nmres=import + else + win32_nmres= + fi + ;; + *) + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s|.*|import| + p + q + } + }'` + ;; + esac + 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_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $debug_cmd + + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $debug_cmd + + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive that possess that section. Heuristic: eliminate + # all those that have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $debug_cmd + + if func_cygming_gnu_implib_p "$1"; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1"; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result= + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $debug_cmd + + f_ex_an_ar_dir=$1; shift + f_ex_an_ar_oldlib=$1 + if test yes = "$lock_old_archive_extraction"; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test yes = "$lock_old_archive_extraction"; then + $opt_dry_run || rm -f "$lockfile" + fi + 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 () +{ + $debug_cmd + + 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` + func_basename "$darwin_archive" + darwin_base_archive=$func_basename_result + 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 "$sed_basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $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 | sort | $NL2SP` + done + + func_extract_archives_result=$my_oldobjs +} + + +# 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 where it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE) $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. +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 + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ that is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options that match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED '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 \"\$file\" | $SED '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 \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_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 \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test yes = "$fast_install"; 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" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test yes = "$shlibpath_overrides_runpath" && 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 \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${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\ +" +} + + +# 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 +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* declarations of non-ANSI functions */ +#if defined __MINGW32__ +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined __CYGWIN__ +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined other_platform || defined ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined _MSC_VER +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +#elif defined __MINGW32__ +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined __CYGWIN__ +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined other platforms ... */ +#endif + +#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 + +/* path handling portability macros */ +#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 */ + +#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 (stale); stale = 0; } \ +} while (0) + +#if defined LT_DEBUGWRAPPER +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +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_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +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_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 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; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + 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]; + size_t tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + 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 = (size_t) (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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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) + { + lt_debugprintf (__FILE__, __LINE__, + "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 + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "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 (STREQ (str, pat)) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + size_t 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) + { + size_t orig_value_len = strlen (orig_value); + size_t 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; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (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 #' */ + size_t len = strlen (new_value); + while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[--len] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (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 + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $debug_cmd + + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_suncc_cstd_abi +# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! +# Several compiler flags select an ABI that is incompatible with the +# Cstd library. Avoid specifying it if any are in CXXFLAGS. +func_suncc_cstd_abi () +{ + $debug_cmd + + case " $compile_command " in + *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) + suncc_use_cstd_abi=no + ;; + *) + suncc_use_cstd_abi=yes + ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $debug_cmd + + 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 + # what 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 that 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 + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + os2dllname= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=false + 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 yes != "$build_libtool_libs" \ + && func_fatal_configuration "cannot build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test yes = "$build_libtool_libs" && 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 + bindir) + bindir=$arg + prev= + continue + ;; + dlfiles|dlprefiles) + $preload || { + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=: + } + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test no = "$dlself"; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test dlprefiles = "$prev"; then + dlself=yes + elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test dlfiles = "$prev"; then + func_append dlfiles " $arg" + else + func_append 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 "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir=$arg + prev= + continue + ;; + mllvm) + # Clang does not use LLVM to link, so we can simply discard any + # '-mllvm $arg' options when doing the link step. + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append 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 none = "$pic_object" && + test none = "$non_pic_object"; 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 none != "$pic_object"; then + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append 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 dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + fi + + # Non-PIC object. + if test none != "$non_pic_object"; 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 none = "$pic_object"; 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 + ;; + os2dllname) + os2dllname=$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 rpath = "$prev"; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds=$arg + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append 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 + ;; + + -bindir) + prev=bindir + 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-export-symbols = "X$arg"; 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" + if test -z "$func_stripname_result"; 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 + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # 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 "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test X-lc = "X$arg" || test X-lm = "X$arg"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # 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-lc = "X$arg" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc due to us having libc/libc_r. + test X-lc = "X$arg" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test X-lc = "X$arg" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test X-lc = "X$arg" && continue + ;; + esac + elif test X-lc_r = "X$arg"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -mllvm) + prev=mllvm + 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|--sysroot) + func_append 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|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append 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 + ;; + + -os2dllname) + prev=os2dllname + 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_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append 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" + func_append arg " $func_quote_for_eval_result" + func_append 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" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append 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 + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # -fstack-protector* stack protector flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -specs=* GCC specs files + # -stdlib=* select c++ std lib with clang + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ + -specs=*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + -Z*) + if test os2 = "`expr $host : '.*\(os2\)'`"; then + # OS/2 uses -Zxxx to specify OS/2-specific options + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case $arg in + -Zlinker | -Zstack) + prev=xcompiler + ;; + esac + continue + else + # Otherwise treat like 'Some other compiler flag' below + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + fi + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + + *.$objext) + # A standard object. + func_append 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 none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + test none = "$pic_object" || { + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append 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 dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + } + + # Non-PIC object. + if test none != "$non_pic_object"; 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 none = "$pic_object"; 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. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test dlfiles = "$prev"; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test dlprefiles = "$prev"; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + 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 yes = "$export_dynamic" && 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 \"\$$shlibpath_var\" \| \$SED \'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\" + + # Definition is injected by LT_CONFIG during libtool generation. + func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" + + func_dirname "$output" "/" "" + output_objdir=$func_dirname_result$objdir + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # 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_preserve_dup_deps; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test lib = "$linkmode"; 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 "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append 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=false + 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 lib,link = "$linkmode,$pass"; 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 lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass"; then + libs=$deplibs + deplibs= + fi + if test prog = "$linkmode"; then + case $pass in + dlopen) libs=$dlfiles ;; + dlpreopen) libs=$dlprefiles ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test lib,dlpreopen = "$linkmode,$pass"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs=$dlprefiles + fi + if test dlopen = "$pass"; then + # Collect dlpreopened libraries + save_deplibs=$deplibs + deplibs= + fi + + for deplib in $libs; do + lib= + found=false + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test lib != "$linkmode" && test prog != "$linkmode"; then + func_warning "'-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test lib = "$linkmode"; 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 .la = "$search_ext"; then + found=: + else + found=false + fi + break 2 + fi + done + done + if $found; then + # 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 yes = "$allow_libtool_libs_with_static_runtimes"; 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=false + func_dirname "$lib" "" "." + ladir=$func_dirname_result + lib=$ladir/$old_library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + else + # deplib doesn't seem to be a libtool library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + *.ltframework) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test conv = "$pass" && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + if test scan = "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "'-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test link = "$pass"; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test conv = "$pass"; 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=false + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=: + fi + ;; + pass_all) + valid_a_lib=: + ;; + esac + if $valid_a_lib; then + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + else + 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." + fi + ;; + esac + continue + ;; + prog) + if test link != "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + elif test prog = "$linkmode"; then + if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=: + continue + ;; + esac # case $deplib + + $found || test -f "$lib" \ + || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" + + # 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 "$inherited_linker_flags" | $SED '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 "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass" || + { test prog != "$linkmode" && test lib != "$linkmode"; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test conv = "$pass"; 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. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + elif test prog != "$linkmode" && test lib != "$linkmode"; then + func_fatal_error "'$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test yes = "$prefer_static_libs" || + test built,no = "$prefer_static_libs,$installed"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib=$l + done + fi + 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 dlopen = "$pass"; then + test -z "$libdir" \ + && func_fatal_error "cannot -dlopen a convenience library: '$lib'" + if test -z "$dlname" || + test yes != "$dlopen_support" || + test no = "$build_libtool_libs" + 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. + func_append dlprefiles " $lib $dependency_libs" + else + func_append 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 yes = "$installed"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library '$lib' was moved." + dir=$ladir + absdir=$abs_ladir + libdir=$abs_ladir + else + dir=$lt_sysroot$libdir + absdir=$lt_sysroot$libdir + fi + test yes = "$hardcode_automatic" && 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 + func_append notinst_path " $abs_ladir" + else + dir=$ladir/$objdir + absdir=$abs_ladir/$objdir + # Remove this search path later + func_append 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 dlpreopen = "$pass"; then + if test -z "$libdir" && test prog = "$linkmode"; then + func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" + fi + case $host in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append 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" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append 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" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test lib = "$linkmode"; then + deplibs="$dir/$old_library $deplibs" + elif test prog,link = "$linkmode,$pass"; 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 prog = "$linkmode" && test link != "$pass"; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=false + if test no != "$link_all_deplibs" || test -z "$library_names" || + test no = "$build_libtool_libs"; then + linkalldeplibs=: + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if $linkalldeplibs; 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_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test prog,link = "$linkmode,$pass"; then + if test -n "$library_names" && + { { test no = "$prefer_static_libs" || + test built,yes = "$prefer_static_libs,$installed"; } || + 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:"*) ;; + *) func_append 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if $alldeplibs && + { test pass_all = "$deplibs_check_method" || + { test yes = "$build_libtool_libs" && + 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 built = "$use_static_libs" && test yes = "$installed"; then + use_static_libs=no + fi + if test -n "$library_names" && + { test no = "$use_static_libs" || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc* | *os2*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test no = "$installed"; then + func_append 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 yes = "$shouldnotlink" && test link = "$pass"; then + echo + if test prog = "$linkmode"; 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 lib = "$linkmode" && + test yes = "$hardcode_into_libs"; 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append 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* | *os2*) + 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 prog = "$linkmode" || test relink != "$opt_mode"; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test no = "$hardcode_direct"; 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 cannot + # 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 no = "$hardcode_minus_L"; then + case $host in + *-*-sunos*) add_shlibpath=$dir ;; + esac + add_dir=-L$dir + add=-l$name + elif test no = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + relink) + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$dir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$absdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test yes != "$lib_linked"; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test prog = "$linkmode"; 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 yes != "$hardcode_direct" && + test yes != "$hardcode_minus_L" && + test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test prog = "$linkmode" || test relink = "$opt_mode"; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$libdir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$libdir + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add=-l$name + elif test yes = "$hardcode_automatic"; 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 + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + fi + + if test prog = "$linkmode"; 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 prog = "$linkmode"; 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 unsupported != "$hardcode_direct"; 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 yes = "$build_libtool_libs"; then + # Not a shared library + if test pass_all != "$deplibs_check_method"; 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 cannot 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 yes = "$module"; 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 no = "$build_old_libs"; 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 lib = "$linkmode"; then + if test -n "$dependency_libs" && + { test yes != "$hardcode_into_libs" || + test yes = "$build_old_libs" || + test yes = "$link_static"; }; 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 "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs=$temp_deplibs + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test no != "$link_all_deplibs"; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path=$deplib ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + 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 + func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" + func_append 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 link = "$pass"; then + if test prog = "$linkmode"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs=$newdependency_libs + if test dlpreopen = "$pass"; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test dlopen != "$pass"; then + test conv = "$pass" || { + # 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 "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + } + + if test prog,link = "$linkmode,$pass"; then + vars="compile_deplibs finalize_deplibs" + else + vars=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 "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + + # Add Sun CC postdeps if required: + test CXX = "$tagname" && { + case $host_os in + linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C++ 5.9 + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + + solaris*) + func_cc_basename "$CC" + case $func_cc_basename_result in + CC* | sunCC*) + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + esac + } + + # 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 + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test prog = "$linkmode"; then + dlfiles=$newdlfiles + fi + if test prog = "$linkmode" || test lib = "$linkmode"; then + dlprefiles=$newdlprefiles + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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 + func_append 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 no = "$module" \ + && func_fatal_help "libtool library '$output' must begin with 'lib'" + + if test no != "$need_lib_prefix"; 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 pass_all != "$deplibs_check_method"; 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!" + func_append libobjs " $objs" + fi + fi + + test no = "$dlself" \ + || func_warning "'-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test 1 -lt "$#" \ + && func_warning "ignoring multiple '-rpath's for a libtool library" + + install_libdir=$1 + + oldlibs= + if test -z "$rpath"; then + if test yes = "$build_libtool_libs"; 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 + # that has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|freebsd-elf|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_revision + ;; + freebsd-aout|qnx|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 + ;; + 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" + # On Darwin other compilers + case $CC in + nagfor*) + verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + ;; + *) + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + esac + ;; + + freebsd-aout) + major=.$current + versuffix=.$current.$revision + ;; + + freebsd-elf) + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + irix | nonstopux) + if test no = "$lt_irix_increment"; 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 0 -ne "$loop"; 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) # correct to gnu/linux during the next big refactor + 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 0 -ne "$loop"; 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. + func_append verstring ":$current.0" + ;; + + qnx) + major=.$current + versuffix=.$current + ;; + + sco) + major=.$current + versuffix=.$current + ;; + + sunos) + major=.$current + versuffix=.$current.$revision + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 file systems. + 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 no = "$need_version"; then + versuffix= + else + versuffix=.0.0 + fi + fi + + # Remove version info from name if versioning should be avoided + if test yes,no = "$avoid_version,$need_version"; then + major= + versuffix= + verstring= + fi + + # Check to see if the archive will have undefined symbols. + if test yes = "$allow_undefined"; then + if test unsupported = "$allow_undefined_flag"; then + if test yes = "$build_old_libs"; then + func_warning "undefined symbols not allowed in $host shared libraries; building static only" + build_libtool_libs=no + else + func_fatal_error "can't build $host shared library unless -no-undefined is specified" + fi + fi + else + # Don't allow undefined symbols. + allow_undefined_flag=$no_undefined_flag + fi + + fi + + func_generate_dlsyms "$libname" "$libname" : + func_append libobjs " $symfileobj" + test " " = "$libobjs" && libobjs= + + if test relink != "$opt_mode"; 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 -n "$precious_files_regex"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "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 + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; 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 "*) ;; + *) func_append 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 "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test yes = "$build_libtool_libs"; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append 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 yes = "$build_libtool_need_lc"; then + func_append 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` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + 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 "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append 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. + func_append 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 yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append 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 \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append 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. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs= + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + for i in $predeps $postdeps; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test none = "$deplibs_check_method"; 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 + ;; + esac + ;; + 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 " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test yes = "$droppeddeps"; then + if test yes = "$module"; 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 no = "$build_old_libs"; 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 no = "$allow_undefined"; 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 no = "$build_old_libs"; 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 " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED '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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append 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 yes = "$build_libtool_libs"; then + # Remove $wl instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test yes = "$hardcode_into_libs"; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath=$finalize_rpath + test relink = "$opt_mode" || rpath=$compile_rpath$rpath + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append 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 relink = "$opt_mode" || 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 + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$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 + func_append 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 + func_dll_def_p "$export_symbols" || { + # 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 + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test yes = "$always_export_symbols" || 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 cmd1 in $cmds; do + IFS=$save_ifs + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test yes = "$try_normal_branch" \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=$output_objdir/$output_la.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + 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 : != "$skipped_export"; 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 "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test : != "$skipped_export" && 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 + func_append 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 "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs=$tmp_deplibs + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test yes = "$compiler_needs_object" && + 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 + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test relink = "$opt_mode"; 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 yes = "$module" && 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 : != "$skipped_export" && + 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 + func_basename "$output" + output_la=$func_basename_result + + # 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 : != "$skipped_export" && test yes = "$with_gnu_ld"; then + output=$output_objdir/$output_la.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then + output=$output_objdir/$output_la.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test yes = "$compiler_needs_object"; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + 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 -z "$objlist" || + 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 1 -eq "$k"; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$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~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + ${skipped_export-false} && { + 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 + } + + 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_quiet || { + 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 relink = "$opt_mode"; 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 + + ${skipped_export-false} && { + 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 "$include_expsyms" | $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 + func_append 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 + } + + 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 yes = "$module" && 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 + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs=$IFS; IFS='~' + for cmd in $cmds; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + $opt_quiet || { + 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 relink = "$opt_mode"; 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 relink = "$opt_mode"; 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 yes = "$module" || test yes = "$export_dynamic"; then + # On all known operating systems, these are identical. + dlname=$soname + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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= + # if reload_cmds runs $LD directly, get rid of -Wl from + # whole_archive_flag_spec and hope we can get by with turning comma + # into space. + case $reload_cmds in + *\$LD[\ \$]*) wl= ;; + esac + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags + else + gentop=$output_objdir/${obj}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test yes = "$build_libtool_libs" || libobjs=$non_pic_objects + + # Create the old-style object. + reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs + + 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 + + test yes = "$build_libtool_libs" || { + 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 + } + + if test -n "$pic_flag" || test default != "$pic_mode"; 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" + + $preload \ + && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ + && 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 " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 CXX = "$tagname"; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " $wl-bind_at_load" + func_append finalize_command " $wl-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs=$new_libs + + + func_append compile_command " $compile_deplibs" + func_append 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 "*) ;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 yes = "$build_old_libs"; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" false + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=: + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=false + ;; + *cygwin* | *mingw* ) + test yes = "$build_libtool_libs" || wrappers_required=false + ;; + *) + if test no = "$need_relink" || test yes != "$build_libtool_libs"; then + wrappers_required=false + fi + ;; + esac + $wrappers_required || { + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED '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=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # 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 + } + + 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 + func_append 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 + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test yes = "$no_install"; 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 "$link_command" | $SED '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 $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + case $hardcode_action,$fast_install in + relink,*) + # 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" + ;; + *,yes) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + ;; + *,no) + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + ;; + *,needless) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command= + ;; + esac + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED '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 $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # 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 "$relink_command" | $SED "$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 + + case $build_libtool_libs in + convenience) + oldobjs="$libobjs_save $symfileobj" + addlibs=$convenience + build_libtool_libs=no + ;; + module) + oldobjs=$libobjs_save + addlibs=$old_convenience + build_libtool_libs=no + ;; + *) + oldobjs="$old_deplibs $non_pic_objects" + $preload && test -f "$symfileobj" \ + && func_append oldobjs " $symfileobj" + addlibs=$old_convenience + ;; + esac + + if test -n "$addlibs"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; 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 + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append 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 + func_append 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" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + 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 + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + 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 -z "$oldobjs"; 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 yes = "$build_old_libs" && 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 "$relink_command" | $SED "$sed_quote_subst"` + if test yes = "$hardcode_automatic"; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test yes = "$installed"; 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 + func_resolve_sysroot "$deplib" + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append 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" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append 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" + func_append newdlprefiles " ${lt_sysroot:+=}$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 + func_append newdlfiles " $abs" + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles=$newdlprefiles + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test -n "$bindir"; then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result/$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE) $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 cannot 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 no,yes = "$installed,$need_relink"; 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 +} + +if test link = "$opt_mode" || test relink = "$opt_mode"; then + func_mode_link ${1+"$@"} +fi + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $debug_cmd + + RM=$nonopt + files= + rmforce=false + 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) func_append RM " $arg"; rmforce=: ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir=$func_dirname_result + if test . = "$dir"; then + odir=$objdir + else + odir=$dir/$objdir + fi + func_basename "$file" + name=$func_basename_result + test uninstall = "$opt_mode" && odir=$dir + + # Remember odir for removal later, being careful to avoid duplicates + if test clean = "$opt_mode"; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + 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 $rmforce; 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 + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case $opt_mode in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" '$rmforce || 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 none != "$pic_object"; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && test none != "$non_pic_object"; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test clean = "$opt_mode"; 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 + func_append 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 + func_append 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 + func_append rmfiles " $odir/$name $odir/${name}S.$objext" + if test yes = "$fast_install" && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name"; then + func_append rmfiles " $odir/lt-$noexename.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # 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 +} + +if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then + func_mode_uninstall ${1+"$@"} +fi + +test -z "$opt_mode" && { + help=$generic_help + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode '$opt_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 +# where 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: diff --git a/ltconfig b/ltconfig new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ltconfig diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 0000000..7f3523d --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,11149 @@ +#! /bin/sh +## DO NOT EDIT - This file generated from ./build-aux/ltmain.in +## by inline-source v2014-01-03.01 + +# libtool (GNU libtool) 2.4.6 +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996-2015 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 this program. If not, see . + + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.4.6 +package_revision=2.4.6 + + +## ------ ## +## Usage. ## +## ------ ## + +# Run './libtool --help' for help with using this script from the +# command line. + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# After configure completes, it has a better idea of some of the +# shell tools we need than the defaults used by the functions shared +# with bootstrap, so set those here where they can still be over- +# ridden by the user, but otherwise take precedence. + +: ${AUTOCONF="autoconf"} +: ${AUTOMAKE="automake"} + + +## -------------------------- ## +## Source external libraries. ## +## -------------------------- ## + +# Much of our low-level functionality needs to be sourced from external +# libraries, which are installed to $pkgauxdir. + +# Set a version string for this script. +scriptversion=2015-01-20.17; # UTC + +# General shell script boiler plate, and helper functions. +# Written by Gary V. Vaughan, 2004 + +# Copyright (C) 2004-2015 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. + +# 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 3 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNES 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 . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# Evaluate this file near the top of your script to gain access to +# the functions and variables defined here: +# +# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh +# +# If you need to override any of the default environment variable +# settings, do that before evaluating this file. + + +## -------------------- ## +## Shell normalisation. ## +## -------------------- ## + +# Some shells need a little help to be as Bourne compatible as possible. +# Before doing anything else, make sure all that help has been provided! + +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 + +# NLS nuisances: We save the old values in case they are required later. +_G_user_locale= +_G_safe_locale= +for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test set = \"\${$_G_var+set}\"; then + save_$_G_var=\$$_G_var + $_G_var=C + export $_G_var + _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" + _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" + fi" +done + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Make sure IFS has a sensible default +sp=' ' +nl=' +' +IFS="$sp $nl" + +# There are apparently some retarded systems that use ';' as a PATH separator! +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 + + + +## ------------------------- ## +## Locate command utilities. ## +## ------------------------- ## + + +# func_executable_p FILE +# ---------------------- +# Check that FILE is an executable regular file. +func_executable_p () +{ + test -f "$1" && test -x "$1" +} + + +# func_path_progs PROGS_LIST CHECK_FUNC [PATH] +# -------------------------------------------- +# Search for either a program that responds to --version with output +# containing "GNU", or else returned by CHECK_FUNC otherwise, by +# trying all the directories in PATH with each of the elements of +# PROGS_LIST. +# +# CHECK_FUNC should accept the path to a candidate program, and +# set $func_check_prog_result if it truncates its output less than +# $_G_path_prog_max characters. +func_path_progs () +{ + _G_progs_list=$1 + _G_check_func=$2 + _G_PATH=${3-"$PATH"} + + _G_path_prog_max=0 + _G_path_prog_found=false + _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} + for _G_dir in $_G_PATH; do + IFS=$_G_save_IFS + test -z "$_G_dir" && _G_dir=. + for _G_prog_name in $_G_progs_list; do + for _exeext in '' .EXE; do + _G_path_prog=$_G_dir/$_G_prog_name$_exeext + func_executable_p "$_G_path_prog" || continue + case `"$_G_path_prog" --version 2>&1` in + *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; + *) $_G_check_func $_G_path_prog + func_path_progs_result=$func_check_prog_result + ;; + esac + $_G_path_prog_found && break 3 + done + done + done + IFS=$_G_save_IFS + test -z "$func_path_progs_result" && { + echo "no acceptable sed could be found in \$PATH" >&2 + exit 1 + } +} + + +# We want to be able to use the functions in this file before configure +# has figured out where the best binaries are kept, which means we have +# to search for them ourselves - except when the results are already set +# where we skip the searches. + +# Unless the user overrides by setting SED, search the path for either GNU +# sed, or the sed that truncates its output the least. +test -z "$SED" && { + _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for _G_i in 1 2 3 4 5 6 7; do + _G_sed_script=$_G_sed_script$nl$_G_sed_script + done + echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed + _G_sed_script= + + func_check_prog_sed () + { + _G_path_prog=$1 + + _G_count=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo '' >> conftest.nl + "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin + rm -f conftest.sed + SED=$func_path_progs_result +} + + +# Unless the user overrides by setting GREP, search the path for either GNU +# grep, or the grep that truncates its output the least. +test -z "$GREP" && { + func_check_prog_grep () + { + _G_path_prog=$1 + + _G_count=0 + _G_path_prog_max=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo 'GREP' >> conftest.nl + "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin + GREP=$func_path_progs_result +} + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# All uppercase variable names are used for environment variables. These +# variables can be overridden by the user before calling a script that +# uses them if a suitable command of that name is not already available +# in the command search PATH. + +: ${CP="cp -f"} +: ${ECHO="printf %s\n"} +: ${EGREP="$GREP -E"} +: ${FGREP="$GREP -F"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} + + +## -------------------- ## +## Useful sed snippets. ## +## -------------------- ## + +sed_dirname='s|/[^/]*$||' +sed_basename='s|^.*/||' + +# 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. +sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' + +# Sed substitution that converts a w32 file name or path +# that contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-'\' parameter expansions in output of sed_double_quote_subst that +# were '\'-ed in input to the same. If an odd number of '\' preceded a +# '$' in input to sed_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 '$'. +_G_bs='\\' +_G_bs2='\\\\' +_G_bs4='\\\\\\\\' +_G_dollar='\$' +sed_double_backslash="\ + s/$_G_bs4/&\\ +/g + s/^$_G_bs2$_G_dollar/$_G_bs&/ + s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g + s/\n//g" + + +## ----------------- ## +## Global variables. ## +## ----------------- ## + +# Except for the global variables explicitly listed below, the following +# functions in the '^func_' namespace, and the '^require_' namespace +# variables initialised in the 'Resource management' section, sourcing +# this file will not pollute your global namespace with anything +# else. There's no portable way to scope variables in Bourne shell +# though, so actually running these functions will sometimes place +# results into a variable named after the function, and often use +# temporary variables in the '^_G_' namespace. If you are careful to +# avoid using those namespaces casually in your sourcing script, things +# should continue to work as you expect. And, of course, you can freely +# overwrite any of the functions or variables defined here before +# calling anything to customize them. + +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. + +# Allow overriding, eg assuming that you follow the convention of +# putting '$debug_cmd' at the start of all your functions, you can get +# bash to show function call trace with: +# +# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +debug_cmd=${debug_cmd-":"} +exit_cmd=: + +# By convention, finish your script with: +# +# exit $exit_status +# +# so that you can set exit_status to non-zero if you want to indicate +# something went wrong during execution without actually bailing out at +# the point of failure. +exit_status=$EXIT_SUCCESS + +# 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. +progname=`$ECHO "$progpath" |$SED "$sed_basename"` + +# Make sure we have an absolute progpath for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` + progdir=`cd "$progdir" && pwd` + progpath=$progdir/$progname + ;; + *) + _G_IFS=$IFS + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS=$_G_IFS + test -x "$progdir/$progname" && break + done + IFS=$_G_IFS + test -n "$progdir" || progdir=`pwd` + progpath=$progdir/$progname + ;; +esac + + +## ----------------- ## +## Standard options. ## +## ----------------- ## + +# The following options affect the operation of the functions defined +# below, and should be set appropriately depending on run-time para- +# meters passed on the command line. + +opt_dry_run=false +opt_quiet=false +opt_verbose=false + +# Categories 'all' and 'none' are always available. Append any others +# you will pass as the first argument to func_warning from your own +# code. +warning_categories= + +# By default, display warnings according to 'opt_warning_types'. Set +# 'warning_func' to ':' to elide all warnings, or func_fatal_error to +# treat the next displayed warning as a fatal error. +warning_func=func_warn_and_continue + +# Set to 'all' to display all warnings, 'none' to suppress all +# warnings, or a space delimited list of some subset of +# 'warning_categories' to display only the listed warnings. +opt_warning_types=all + + +## -------------------- ## +## Resource management. ## +## -------------------- ## + +# This section contains definitions for functions that each ensure a +# particular resource (a file, or a non-empty configuration variable for +# example) is available, and if appropriate to extract default values +# from pertinent package files. Call them using their associated +# 'require_*' variable to ensure that they are executed, at most, once. +# +# It's entirely deliberate that calling these functions can set +# variables that don't obey the namespace limitations obeyed by the rest +# of this file, in order that that they be as useful as possible to +# callers. + + +# require_term_colors +# ------------------- +# Allow display of bold text on terminals that support it. +require_term_colors=func_require_term_colors +func_require_term_colors () +{ + $debug_cmd + + test -t 1 && { + # COLORTERM and USE_ANSI_COLORS environment variables take + # precedence, because most terminfo databases neglect to describe + # whether color sequences are supported. + test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} + + if test 1 = "$USE_ANSI_COLORS"; then + # Standard ANSI escape sequences + tc_reset='' + tc_bold=''; tc_standout='' + tc_red=''; tc_green='' + tc_blue=''; tc_cyan='' + else + # Otherwise trust the terminfo database after all. + test -n "`tput sgr0 2>/dev/null`" && { + tc_reset=`tput sgr0` + test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` + tc_standout=$tc_bold + test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` + test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` + test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` + test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` + test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` + } + fi + } + + require_term_colors=: +} + + +## ----------------- ## +## Function library. ## +## ----------------- ## + +# This section contains a variety of useful functions to call in your +# scripts. Take note of the portable wrappers for features provided by +# some modern shells, which will fall back to slower equivalents on +# less featureful shells. + + +# func_append VAR VALUE +# --------------------- +# Append VALUE onto the existing contents of VAR. + + # We should try to minimise forks, especially on Windows where they are + # unreasonably slow, so skip the feature probes when bash or zsh are + # being used: + if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then + : ${_G_HAVE_ARITH_OP="yes"} + : ${_G_HAVE_XSI_OPS="yes"} + # The += operator was introduced in bash 3.1 + case $BASH_VERSION in + [12].* | 3.0 | 3.0*) ;; + *) + : ${_G_HAVE_PLUSEQ_OP="yes"} + ;; + esac + fi + + # _G_HAVE_PLUSEQ_OP + # Can be empty, in which case the shell is probed, "yes" if += is + # useable or anything else if it does not work. + test -z "$_G_HAVE_PLUSEQ_OP" \ + && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ + && _G_HAVE_PLUSEQ_OP=yes + +if test yes = "$_G_HAVE_PLUSEQ_OP" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_append () + { + $debug_cmd + + eval "$1+=\$2" + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_append () + { + $debug_cmd + + eval "$1=\$$1\$2" + } +fi + + +# func_append_quoted VAR VALUE +# ---------------------------- +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +if test yes = "$_G_HAVE_PLUSEQ_OP"; then + eval 'func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1+=\\ \$func_quote_for_eval_result" + }' +else + func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1=\$$1\\ \$func_quote_for_eval_result" + } +fi + + +# func_append_uniq VAR VALUE +# -------------------------- +# Append unique VALUE onto the existing contents of VAR, assuming +# entries are delimited by the first character of VALUE. For example: +# +# func_append_uniq options " --another-option option-argument" +# +# will only append to $options if " --another-option option-argument " +# is not already present somewhere in $options already (note spaces at +# each end implied by leading space in second argument). +func_append_uniq () +{ + $debug_cmd + + eval _G_current_value='`$ECHO $'$1'`' + _G_delim=`expr "$2" : '\(.\)'` + + case $_G_delim$_G_current_value$_G_delim in + *"$2$_G_delim"*) ;; + *) func_append "$@" ;; + esac +} + + +# func_arith TERM... +# ------------------ +# Set func_arith_result to the result of evaluating TERMs. + test -z "$_G_HAVE_ARITH_OP" \ + && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ + && _G_HAVE_ARITH_OP=yes + +if test yes = "$_G_HAVE_ARITH_OP"; then + eval 'func_arith () + { + $debug_cmd + + func_arith_result=$(( $* )) + }' +else + func_arith () + { + $debug_cmd + + func_arith_result=`expr "$@"` + } +fi + + +# func_basename FILE +# ------------------ +# Set func_basename_result to FILE with everything up to and including +# the last / stripped. +if test yes = "$_G_HAVE_XSI_OPS"; then + # If this shell supports suffix pattern removal, then use it to avoid + # forking. Hide the definitions single quotes in case the shell chokes + # on unsupported syntax... + _b='func_basename_result=${1##*/}' + _d='case $1 in + */*) func_dirname_result=${1%/*}$2 ;; + * ) func_dirname_result=$3 ;; + esac' + +else + # ...otherwise fall back to using sed. + _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' + _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` + if test "X$func_dirname_result" = "X$1"; then + func_dirname_result=$3 + else + func_append func_dirname_result "$2" + fi' +fi + +eval 'func_basename () +{ + $debug_cmd + + '"$_b"' +}' + + +# func_dirname FILE APPEND NONDIR_REPLACEMENT +# ------------------------------------------- +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +eval 'func_dirname () +{ + $debug_cmd + + '"$_d"' +}' + + +# 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" +# For efficiency, we do not delegate to the functions above but instead +# duplicate the functionality here. +eval 'func_dirname_and_basename () +{ + $debug_cmd + + '"$_b"' + '"$_d"' +}' + + +# func_echo ARG... +# ---------------- +# Echo program name prefixed message. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_echo_all ARG... +# -------------------- +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + + +# func_echo_infix_1 INFIX ARG... +# ------------------------------ +# Echo program name, followed by INFIX on the first line, with any +# additional lines not showing INFIX. +func_echo_infix_1 () +{ + $debug_cmd + + $require_term_colors + + _G_infix=$1; shift + _G_indent=$_G_infix + _G_prefix="$progname: $_G_infix: " + _G_message=$* + + # Strip color escape sequences before counting printable length + for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" + do + test -n "$_G_tc" && { + _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` + _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` + } + done + _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes + + func_echo_infix_1_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_infix_1_IFS + $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 + _G_prefix=$_G_indent + done + IFS=$func_echo_infix_1_IFS +} + + +# func_error ARG... +# ----------------- +# Echo program name prefixed message to standard error. +func_error () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 +} + + +# func_fatal_error ARG... +# ----------------------- +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + $debug_cmd + + func_error "$*" + exit $EXIT_FAILURE +} + + +# func_grep EXPRESSION FILENAME +# ----------------------------- +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $debug_cmd + + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_len STRING +# --------------- +# Set func_len_result to the length of STRING. STRING may not +# start with a hyphen. + test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_len () + { + $debug_cmd + + func_len_result=${#1} + }' +else + func_len () + { + $debug_cmd + + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` + } +fi + + +# func_mkdir_p DIRECTORY-PATH +# --------------------------- +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + $debug_cmd + + _G_directory_path=$1 + _G_dir_list= + + if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then + + # Protect directory names starting with '-' + case $_G_directory_path in + -*) _G_directory_path=./$_G_directory_path ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$_G_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + _G_dir_list=$_G_directory_path:$_G_dir_list + + # If the last portion added has no slash in it, the list is done + case $_G_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` + done + _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` + + func_mkdir_p_IFS=$IFS; IFS=: + for _G_dir in $_G_dir_list; do + IFS=$func_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 "$_G_dir" 2>/dev/null || : + done + IFS=$func_mkdir_p_IFS + + # Bail out if we (or some other process) failed to create a directory. + test -d "$_G_directory_path" || \ + func_fatal_error "Failed to create '$1'" + fi +} + + +# func_mktempdir [BASENAME] +# ------------------------- +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, BASENAME is the basename for that directory. +func_mktempdir () +{ + $debug_cmd + + _G_template=${TMPDIR-/tmp}/${1-$progname} + + if test : = "$opt_dry_run"; then + # Return a directory name, but don't create it in dry-run mode + _G_tmpdir=$_G_template-$$ + else + + # If mktemp works, use that first and foremost + _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` + + if test ! -d "$_G_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + _G_tmpdir=$_G_template-${RANDOM-0}$$ + + func_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$_G_tmpdir" + umask $func_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$_G_tmpdir" || \ + func_fatal_error "cannot create temporary directory '$_G_tmpdir'" + fi + + $ECHO "$_G_tmpdir" +} + + +# func_normal_abspath PATH +# ------------------------ +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +func_normal_abspath () +{ + $debug_cmd + + # These SED scripts presuppose an absolute path with a trailing slash. + _G_pathcar='s|^/\([^/]*\).*$|\1|' + _G_pathcdr='s|^/[^/]*||' + _G_removedotparts=':dotsl + s|/\./|/|g + t dotsl + s|/\.$|/|' + _G_collapseslashes='s|/\{1,\}|/|g' + _G_finalslash='s|/*$|/|' + + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` + while :; do + # Processed it all yet? + if test / = "$func_normal_abspath_tpath"; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result"; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + + +# func_notquiet ARG... +# -------------------- +# Echo program name prefixed message only when not in quiet mode. +func_notquiet () +{ + $debug_cmd + + $opt_quiet || 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_relative_path SRCDIR DSTDIR +# -------------------------------- +# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. +func_relative_path () +{ + $debug_cmd + + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=$func_dirname_result + if test -z "$func_relative_path_tlibdir"; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test -n "$func_stripname_result"; then + func_append func_relative_path_result "/$func_stripname_result" + fi + + # Normalisation. If bindir is libdir, return '.' else relative path. + if test -n "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + fi + + test -n "$func_relative_path_result" || func_relative_path_result=. + + : +} + + +# func_quote_for_eval ARG... +# -------------------------- +# Aesthetically quote ARGs to be evaled later. +# This function returns two values: +# i) func_quote_for_eval_result +# double-quoted, suitable for a subsequent eval +# ii) func_quote_for_eval_unquoted_result +# has all characters that are still active within double +# quotes backslashified. +func_quote_for_eval () +{ + $debug_cmd + + func_quote_for_eval_unquoted_result= + func_quote_for_eval_result= + while test 0 -lt $#; do + case $1 in + *[\\\`\"\$]*) + _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; + *) + _G_unquoted_arg=$1 ;; + esac + if test -n "$func_quote_for_eval_unquoted_result"; then + func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" + else + func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" + fi + + case $_G_unquoted_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_quoted_arg=\"$_G_unquoted_arg\" + ;; + *) + _G_quoted_arg=$_G_unquoted_arg + ;; + esac + + if test -n "$func_quote_for_eval_result"; then + func_append func_quote_for_eval_result " $_G_quoted_arg" + else + func_append func_quote_for_eval_result "$_G_quoted_arg" + fi + shift + done +} + + +# 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 () +{ + $debug_cmd + + case $1 in + *[\\\`\"]*) + _G_arg=`$ECHO "$1" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; + *) + _G_arg=$1 ;; + esac + + case $_G_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. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_arg=\"$_G_arg\" + ;; + esac + + func_quote_for_expand_result=$_G_arg +} + + +# func_stripname PREFIX SUFFIX NAME +# --------------------------------- +# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. +# 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). +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_stripname () + { + $debug_cmd + + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary variable first. + func_stripname_result=$3 + func_stripname_result=${func_stripname_result#"$1"} + func_stripname_result=${func_stripname_result%"$2"} + }' +else + func_stripname () + { + $debug_cmd + + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; + esac + } +fi + + +# func_show_eval CMD [FAIL_EXP] +# ----------------------------- +# Unless opt_quiet 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 () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + func_quote_for_expand "$_G_cmd" + eval "func_notquiet $func_quote_for_expand_result" + + $opt_dry_run || { + eval "$_G_cmd" + _G_status=$? + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_show_eval_locale CMD [FAIL_EXP] +# ------------------------------------ +# Unless opt_quiet 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 () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + $opt_quiet || { + func_quote_for_expand "$_G_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + $opt_dry_run || { + eval "$_G_user_locale + $_G_cmd" + _G_status=$? + eval "$_G_safe_locale" + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_tr_sh +# ---------- +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + $debug_cmd + + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_verbose ARG... +# ------------------- +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $debug_cmd + + $opt_verbose && func_echo "$*" + + : +} + + +# func_warn_and_continue ARG... +# ----------------------------- +# Echo program name prefixed warning message to standard error. +func_warn_and_continue () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 +} + + +# func_warning CATEGORY ARG... +# ---------------------------- +# Echo program name prefixed warning message to standard error. Warning +# messages can be filtered according to CATEGORY, where this function +# elides messages where CATEGORY is not listed in the global variable +# 'opt_warning_types'. +func_warning () +{ + $debug_cmd + + # CATEGORY must be in the warning_categories list! + case " $warning_categories " in + *" $1 "*) ;; + *) func_internal_error "invalid warning category '$1'" ;; + esac + + _G_category=$1 + shift + + case " $opt_warning_types " in + *" $_G_category "*) $warning_func ${1+"$@"} ;; + esac +} + + +# func_sort_ver VER1 VER2 +# ----------------------- +# 'sort -V' is not generally available. +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +func_sort_ver () +{ + $debug_cmd + + printf '%s\n%s\n' "$1" "$2" \ + | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n +} + +# func_lt_ver PREV CURR +# --------------------- +# Return true if PREV and CURR are in the correct order according to +# func_sort_ver, otherwise false. Use it like this: +# +# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." +func_lt_ver () +{ + $debug_cmd + + test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: +#! /bin/sh + +# Set a version string for this script. +scriptversion=2014-01-07.03; # UTC + +# A portable, pluggable option parser for Bourne shell. +# Written by Gary V. Vaughan, 2010 + +# Copyright (C) 2010-2015 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. + +# 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 3 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, see . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# This file is a library for parsing options in your shell scripts along +# with assorted other useful supporting features that you can make use +# of too. +# +# For the simplest scripts you might need only: +# +# #!/bin/sh +# . relative/path/to/funclib.sh +# . relative/path/to/options-parser +# scriptversion=1.0 +# func_options ${1+"$@"} +# eval set dummy "$func_options_result"; shift +# ...rest of your script... +# +# In order for the '--version' option to work, you will need to have a +# suitably formatted comment like the one at the top of this file +# starting with '# Written by ' and ending with '# warranty; '. +# +# For '-h' and '--help' to work, you will also need a one line +# description of your script's purpose in a comment directly above the +# '# Written by ' line, like the one at the top of this file. +# +# The default options also support '--debug', which will turn on shell +# execution tracing (see the comment above debug_cmd below for another +# use), and '--verbose' and the func_verbose function to allow your script +# to display verbose messages only when your user has specified +# '--verbose'. +# +# After sourcing this file, you can plug processing for additional +# options by amending the variables from the 'Configuration' section +# below, and following the instructions in the 'Option parsing' +# section further down. + +## -------------- ## +## Configuration. ## +## -------------- ## + +# You should override these variables in your script after sourcing this +# file so that they reflect the customisations you have added to the +# option parser. + +# The usage line for option parsing errors and the start of '-h' and +# '--help' output messages. You can embed shell variables for delayed +# expansion at the time the message is displayed, but you will need to +# quote other shell meta-characters carefully to prevent them being +# expanded when the contents are evaled. +usage='$progpath [OPTION]...' + +# Short help message in response to '-h' and '--help'. Add to this or +# override it after sourcing this library to reflect the full set of +# options your script accepts. +usage_message="\ + --debug enable verbose shell tracing + -W, --warnings=CATEGORY + report the warnings falling in CATEGORY [all] + -v, --verbose verbosely report processing + --version print version information and exit + -h, --help print short or long help message and exit +" + +# Additional text appended to 'usage_message' in response to '--help'. +long_help_message=" +Warning categories include: + 'all' show all warnings + 'none' turn off all the warnings + 'error' warnings are treated as fatal errors" + +# Help message printed before fatal option parsing errors. +fatal_help="Try '\$progname --help' for more information." + + + +## ------------------------- ## +## Hook function management. ## +## ------------------------- ## + +# This section contains functions for adding, removing, and running hooks +# to the main code. A hook is just a named list of of function, that can +# be run in order later on. + +# func_hookable FUNC_NAME +# ----------------------- +# Declare that FUNC_NAME will run hooks added with +# 'func_add_hook FUNC_NAME ...'. +func_hookable () +{ + $debug_cmd + + func_append hookable_fns " $1" +} + + +# func_add_hook FUNC_NAME HOOK_FUNC +# --------------------------------- +# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must +# first have been declared "hookable" by a call to 'func_hookable'. +func_add_hook () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not accept hook functions." ;; + esac + + eval func_append ${1}_hooks '" $2"' +} + + +# func_remove_hook FUNC_NAME HOOK_FUNC +# ------------------------------------ +# Remove HOOK_FUNC from the list of functions called by FUNC_NAME. +func_remove_hook () +{ + $debug_cmd + + eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' +} + + +# func_run_hooks FUNC_NAME [ARG]... +# --------------------------------- +# Run all hook functions registered to FUNC_NAME. +# It is assumed that the list of hook functions contains nothing more +# than a whitespace-delimited list of legal shell function names, and +# no effort is wasted trying to catch shell meta-characters or preserve +# whitespace. +func_run_hooks () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not support hook funcions.n" ;; + esac + + eval _G_hook_fns=\$$1_hooks; shift + + for _G_hook in $_G_hook_fns; do + eval $_G_hook '"$@"' + + # store returned options list back into positional + # parameters for next 'cmd' execution. + eval _G_hook_result=\$${_G_hook}_result + eval set dummy "$_G_hook_result"; shift + done + + func_quote_for_eval ${1+"$@"} + func_run_hooks_result=$func_quote_for_eval_result +} + + + +## --------------- ## +## Option parsing. ## +## --------------- ## + +# In order to add your own option parsing hooks, you must accept the +# full positional parameter list in your hook function, remove any +# options that you action, and then pass back the remaining unprocessed +# options in '_result', escaped suitably for +# 'eval'. Like this: +# +# my_options_prep () +# { +# $debug_cmd +# +# # Extend the existing usage message. +# usage_message=$usage_message' +# -s, --silent don'\''t print informational messages +# ' +# +# func_quote_for_eval ${1+"$@"} +# my_options_prep_result=$func_quote_for_eval_result +# } +# func_add_hook func_options_prep my_options_prep +# +# +# my_silent_option () +# { +# $debug_cmd +# +# # Note that for efficiency, we parse as many options as we can +# # recognise in a loop before passing the remainder back to the +# # caller on the first unrecognised argument we encounter. +# while test $# -gt 0; do +# opt=$1; shift +# case $opt in +# --silent|-s) opt_silent=: ;; +# # Separate non-argument short options: +# -s*) func_split_short_opt "$_G_opt" +# set dummy "$func_split_short_opt_name" \ +# "-$func_split_short_opt_arg" ${1+"$@"} +# shift +# ;; +# *) set dummy "$_G_opt" "$*"; shift; break ;; +# esac +# done +# +# func_quote_for_eval ${1+"$@"} +# my_silent_option_result=$func_quote_for_eval_result +# } +# func_add_hook func_parse_options my_silent_option +# +# +# my_option_validation () +# { +# $debug_cmd +# +# $opt_silent && $opt_verbose && func_fatal_help "\ +# '--silent' and '--verbose' options are mutually exclusive." +# +# func_quote_for_eval ${1+"$@"} +# my_option_validation_result=$func_quote_for_eval_result +# } +# func_add_hook func_validate_options my_option_validation +# +# You'll alse need to manually amend $usage_message to reflect the extra +# options you parse. It's preferable to append if you can, so that +# multiple option parsing hooks can be added safely. + + +# func_options [ARG]... +# --------------------- +# All the functions called inside func_options are hookable. See the +# individual implementations for details. +func_hookable func_options +func_options () +{ + $debug_cmd + + func_options_prep ${1+"$@"} + eval func_parse_options \ + ${func_options_prep_result+"$func_options_prep_result"} + eval func_validate_options \ + ${func_parse_options_result+"$func_parse_options_result"} + + eval func_run_hooks func_options \ + ${func_validate_options_result+"$func_validate_options_result"} + + # save modified positional parameters for caller + func_options_result=$func_run_hooks_result +} + + +# func_options_prep [ARG]... +# -------------------------- +# All initialisations required before starting the option parse loop. +# Note that when calling hook functions, we pass through the list of +# positional parameters. If a hook function modifies that list, and +# needs to propogate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before +# returning. +func_hookable func_options_prep +func_options_prep () +{ + $debug_cmd + + # Option defaults: + opt_verbose=false + opt_warning_types= + + func_run_hooks func_options_prep ${1+"$@"} + + # save modified positional parameters for caller + func_options_prep_result=$func_run_hooks_result +} + + +# func_parse_options [ARG]... +# --------------------------- +# The main option parsing loop. +func_hookable func_parse_options +func_parse_options () +{ + $debug_cmd + + func_parse_options_result= + + # this just eases exit handling + while test $# -gt 0; do + # Defer to hook functions for initial option parsing, so they + # get priority in the event of reusing an option name. + func_run_hooks func_parse_options ${1+"$@"} + + # Adjust func_parse_options positional parameters to match + eval set dummy "$func_run_hooks_result"; shift + + # Break out of the loop if we already parsed every option. + test $# -gt 0 || break + + _G_opt=$1 + shift + case $_G_opt in + --debug|-x) debug_cmd='set -x' + func_echo "enabling shell trace mode" + $debug_cmd + ;; + + --no-warnings|--no-warning|--no-warn) + set dummy --warnings none ${1+"$@"} + shift + ;; + + --warnings|--warning|-W) + test $# = 0 && func_missing_arg $_G_opt && break + case " $warning_categories $1" in + *" $1 "*) + # trailing space prevents matching last $1 above + func_append_uniq opt_warning_types " $1" + ;; + *all) + opt_warning_types=$warning_categories + ;; + *none) + opt_warning_types=none + warning_func=: + ;; + *error) + opt_warning_types=$warning_categories + warning_func=func_fatal_error + ;; + *) + func_fatal_error \ + "unsupported warning category: '$1'" + ;; + esac + shift + ;; + + --verbose|-v) opt_verbose=: ;; + --version) func_version ;; + -\?|-h) func_usage ;; + --help) func_help ;; + + # Separate optargs to long options (plugins may need this): + --*=*) func_split_equals "$_G_opt" + set dummy "$func_split_equals_lhs" \ + "$func_split_equals_rhs" ${1+"$@"} + shift + ;; + + # Separate optargs to short options: + -W*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-v*|-x*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + func_parse_options_result=$func_quote_for_eval_result +} + + +# func_validate_options [ARG]... +# ------------------------------ +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +func_hookable func_validate_options +func_validate_options () +{ + $debug_cmd + + # Display all warnings if -W was not given. + test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" + + func_run_hooks func_validate_options ${1+"$@"} + + # Bail if the options were screwed! + $exit_cmd $EXIT_FAILURE + + # save modified positional parameters for caller + func_validate_options_result=$func_run_hooks_result +} + + + +## ----------------- ## +## Helper functions. ## +## ----------------- ## + +# This section contains the helper functions used by the rest of the +# hookable option parser framework in ascii-betical order. + + +# func_fatal_help ARG... +# ---------------------- +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + eval \$ECHO \""$fatal_help"\" + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + + +# func_help +# --------- +# Echo long help message to standard output and exit. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message" + exit 0 +} + + +# func_missing_arg ARGNAME +# ------------------------ +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $debug_cmd + + func_error "Missing argument for '$1'." + exit_cmd=exit +} + + +# func_split_equals STRING +# ------------------------ +# Set func_split_equals_lhs and func_split_equals_rhs shell variables after +# splitting STRING at the '=' sign. +test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=${1%%=*} + func_split_equals_rhs=${1#*=} + test "x$func_split_equals_lhs" = "x$1" \ + && func_split_equals_rhs= + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` + func_split_equals_rhs= + test "x$func_split_equals_lhs" = "x$1" \ + || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` + } +fi #func_split_equals + + +# func_split_short_opt SHORTOPT +# ----------------------------- +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"} + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` + func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` + } +fi #func_split_short_opt + + +# func_usage +# ---------- +# Echo short help message to standard output and exit. +func_usage () +{ + $debug_cmd + + func_usage_message + $ECHO "Run '$progname --help |${PAGER-more}' for full usage" + exit 0 +} + + +# func_usage_message +# ------------------ +# Echo short help message to standard output. +func_usage_message () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + echo + $SED -n 's|^# || + /^Written by/{ + x;p;x + } + h + /^Written by/q' < "$progpath" + echo + eval \$ECHO \""$usage_message"\" +} + + +# func_version +# ------------ +# Echo version message to standard output and exit. +func_version () +{ + $debug_cmd + + printf '%s\n' "$progname $scriptversion" + $SED -n ' + /(C)/!b go + :more + /\./!{ + N + s|\n# | | + b more + } + :go + /^# Written by /,/# warranty; / { + s|^# || + s|^# *$|| + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + p + } + /^# Written by / { + s|^# || + p + } + /^warranty; /q' < "$progpath" + + exit $? +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: + +# Set a version string. +scriptversion='(GNU libtool) 2.4.6' + + +# func_echo ARG... +# ---------------- +# Libtool also displays the current mode in messages, so override +# funclib.sh func_echo with this custom definition. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + $debug_cmd + + $warning_func ${1+"$@"} +} + + +## ---------------- ## +## Options parsing. ## +## ---------------- ## + +# Hook in the functions to make sure our own options are parsed during +# the option parsing loop. + +usage='$progpath [OPTION]... [MODE-ARG]...' + +# Short help message in response to '-h'. +usage_message="Options: + --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 + --no-warnings equivalent to '-Wnone' + --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 more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message +" + +# Additional text appended to 'usage_message' in response to '--help'. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$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. When passed as first option, +'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. +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) + version: $progname (GNU libtool) 2.4.6 + automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` + autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` + +Report bugs to . +GNU libtool home page: . +General help using GNU software: ." + exit 0 +} + + +# func_lo2o OBJECT-NAME +# --------------------- +# Transform OBJECT-NAME from a '.lo' suffix to the platform specific +# object suffix. + +lo2o=s/\\.lo\$/.$objext/ +o2lo=s/\\.$objext\$/.lo/ + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_lo2o () + { + case $1 in + *.lo) func_lo2o_result=${1%.lo}.$objext ;; + * ) func_lo2o_result=$1 ;; + esac + }' + + # func_xform LIBOBJ-OR-SOURCE + # --------------------------- + # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) + # suffix to a '.lo' libtool-object suffix. + eval 'func_xform () + { + func_xform_result=${1%.*}.lo + }' +else + # ...otherwise fall back to using sed. + func_lo2o () + { + func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` + } + + func_xform () + { + func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` + } +fi + + +# func_fatal_configuration ARG... +# ------------------------------- +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_fatal_error ${1+"$@"} \ + "See the $PACKAGE documentation for more information." \ + "Fatal configuration error." +} + + +# func_config +# ----------- +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + + +# func_features +# ------------- +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test yes = "$build_libtool_libs"; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test yes = "$build_old_libs"; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + + +# func_enable_tag TAGNAME +# ----------------------- +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname=$1 + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf=/$re_begincf/,/$re_endcf/p + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/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 +} + + +# 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 +} + + +# libtool_options_prep [ARG]... +# ----------------------------- +# Preparation for options parsed by libtool. +libtool_options_prep () +{ + $debug_mode + + # Option defaults: + opt_config=false + opt_dlopen= + opt_dry_run=false + opt_help=false + opt_mode= + opt_preserve_dup_deps=false + opt_quiet=false + + nonopt= + preserve_args= + + # 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 + + # Pass back the list of options. + func_quote_for_eval ${1+"$@"} + libtool_options_prep_result=$func_quote_for_eval_result +} +func_add_hook func_options_prep libtool_options_prep + + +# libtool_parse_options [ARG]... +# --------------------------------- +# Provide handling for libtool specific options. +libtool_parse_options () +{ + $debug_cmd + + # Perform our own loop to consume as many options as possible in + # each iteration. + while test $# -gt 0; do + _G_opt=$1 + shift + case $_G_opt in + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + + --config) func_config ;; + + --dlopen|-dlopen) + opt_dlopen="${opt_dlopen+$opt_dlopen +}$1" + shift + ;; + + --preserve-dup-deps) + opt_preserve_dup_deps=: ;; + + --features) func_features ;; + + --finish) set dummy --mode finish ${1+"$@"}; shift ;; + + --help) opt_help=: ;; + + --help-all) opt_help=': help-all' ;; + + --mode) test $# = 0 && func_missing_arg $_G_opt && break + opt_mode=$1 + 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 $_G_opt" + exit_cmd=exit + break + ;; + esac + shift + ;; + + --no-silent|--no-quiet) + opt_quiet=false + func_append preserve_args " $_G_opt" + ;; + + --no-warnings|--no-warning|--no-warn) + opt_warning=false + func_append preserve_args " $_G_opt" + ;; + + --no-verbose) + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --silent|--quiet) + opt_quiet=: + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --tag) test $# = 0 && func_missing_arg $_G_opt && break + opt_tag=$1 + func_append preserve_args " $_G_opt $1" + func_enable_tag "$1" + shift + ;; + + --verbose|-v) opt_quiet=false + opt_verbose=: + func_append preserve_args " $_G_opt" + ;; + + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + libtool_parse_options_result=$func_quote_for_eval_result +} +func_add_hook func_parse_options libtool_parse_options + + + +# libtool_validate_options [ARG]... +# --------------------------------- +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +libtool_validate_options () +{ + # save first non-option argument + if test 0 -lt $#; then + nonopt=$1 + shift + fi + + # preserve --debug + test : = "$debug_cmd" || func_append preserve_args " --debug" + + case $host in + # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 + # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + test yes != "$build_libtool_libs" \ + && test yes != "$build_old_libs" \ + && func_fatal_configuration "not configured to build any kind of library" + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test execute != "$opt_mode"; 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=$opt_mode' for more information." + } + + # Pass back the unparsed argument list + func_quote_for_eval ${1+"$@"} + libtool_validate_options_result=$func_quote_for_eval_result +} +func_add_hook func_validate_options libtool_validate_options + + +# Process options as early as possible so that --help and --version +# can return quickly. +func_options ${1+"$@"} +eval set dummy "$func_options_result"; shift + + + +## ----------- ## +## Main. ## +## ----------- ## + +magic='%%%MAGIC variable%%%' +magic_exe='%%%MAGIC EXE variable%%%' + +# Global variables. +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# func_generated_by_libtool +# True iff stdin has been generated by Libtool. This function is only +# a basic sanity check; it will hardly flush out determined imposters. +func_generated_by_libtool_p () +{ + $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# 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 | func_generated_by_libtool_p +} + +# 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 yes = "$lalib_p" +} + +# 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 () +{ + test -f "$1" && + $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# 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_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper +} + +# 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 () +{ + $debug_cmd + + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + 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 () +{ + $debug_cmd + + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case $lt_sysroot:$1 in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result='='$func_stripname_result + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$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 () +{ + $debug_cmd + + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + 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 "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # 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_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # 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 yes = "$build_libtool_libs"; then + write_lobj=\'$2\' + else + write_lobj=none + fi + + if test yes = "$build_old_libs"; then + write_oldobj=\'$3\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $debug_cmd + + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result= + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result"; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $debug_cmd + + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $debug_cmd + + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $debug_cmd + + if test -z "$2" && test -n "$1"; then + func_error "Could not determine host file name corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result=$1 + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $debug_cmd + + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " '$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result=$3 + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $debug_cmd + + case $4 in + $1 ) func_to_host_path_result=$3$func_to_host_path_result + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via '$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $debug_cmd + + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $debug_cmd + + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result=$1 +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result=$func_convert_core_msys_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result=$func_convert_core_file_wine_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via '$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# 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. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $debug_cmd + + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd=func_convert_path_$func_stripname_result + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $debug_cmd + + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result=$1 +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # 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_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_msys_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_path_wine_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # 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_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_dll_def_p FILE +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with _LT_DLL_DEF_P in libtool.m4 +func_dll_def_p () +{ + $debug_cmd + + func_dll_def_p_tmp=`$SED -n \ + -e 's/^[ ]*//' \ + -e '/^\(;.*\)*$/d' \ + -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ + -e q \ + "$1"` + test DEF = "$func_dll_def_p_tmp" +} + + +# func_mode_compile arg... +func_mode_compile () +{ + $debug_cmd + + # Get the compilation command and the source file. + base_compile= + srcfile=$nonopt # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg=$arg + arg_mode=normal + ;; + + target ) + libobj=$arg + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify '-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs=$IFS; IFS=, + for arg in $args; do + IFS=$save_ifs + func_append_quoted lastarg "$arg" + done + IFS=$save_ifs + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg=$srcfile + srcfile=$arg + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with '-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj=$func_basename_result + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from '$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test yes = "$build_libtool_libs" \ + || func_fatal_configuration "cannot build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && 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 yes = "$build_old_libs"; 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 no = "$pic_mode" && test pass_all != "$deplibs_check_method"; 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 no = "$compiler_c_o"; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; 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 yes = "$need_locks"; 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 warn = "$need_locks"; 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 + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test yes = "$build_libtool_libs"; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test no != "$pic_mode"; 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 + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + 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 yes = "$suppress_opt"; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test yes = "$build_old_libs"; then + if test yes != "$pic_mode"; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test yes = "$compiler_c_o"; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + 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 no != "$need_locks"; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test compile = "$opt_mode" && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_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 build PIC objects only + -prefer-non-pic try to build 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 + -Wc,FLAG pass FLAG directly to the compiler + +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-dir 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 + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -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 + -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) + -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 + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +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 '$opt_mode'" + ;; + esac + + echo + $ECHO "Try '$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test : = "$opt_help"; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | $SED -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + $SED '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $debug_cmd + + # 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 $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "'$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # 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 + func_append 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 + -* | *.la | *.lo ) ;; + *) + # 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_append_quoted args "$file" + done + + if $opt_dry_run; then + # 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 + else + 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 + fi +} + +test execute = "$opt_mode" && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $debug_cmd + + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "'$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument '$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and '=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + 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" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_quiet && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + 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 "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test finish = "$opt_mode" && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $debug_cmd + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac + 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" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=false + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=: ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test X-m = "X$prev" && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_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 -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + 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=: + if $isdir; 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. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # 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 "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir=$func_dirname_result + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -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 "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "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_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme=$stripme + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme= + ;; + esac + ;; + os2*) + 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" && func_append 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 yes = "$build_old_libs"; 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=: + 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 "$lib" | $SED 's%^.*/%%g'` + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "'$lib' has not been installed in '$libdir'" + finalize=false + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test no = "$fast_install" && test -n "$relink_command"; then + $opt_dry_run || { + if $finalize; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file=$func_basename_result + outputname=$tmpdir/$file + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_quiet || { + 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 "$file$stripped_ext" | $SED "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_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_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 install = "$opt_mode" && 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 () +{ + $debug_cmd + + my_outputname=$1 + my_originator=$2 + my_pic_p=${3-false} + my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* External symbol declarations for the compiler. */\ +" + + if test yes = "$dlself"; 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 "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from '$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $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 + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename= + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname"; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename=$func_basename_result + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename"; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + 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 + + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) + {" + $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ + } +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi + + 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" ;; + *) + $my_pic_p && pic_flag_for_symtable=" $pic_flag" + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append 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" "${nlist}I"' + + # 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 "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "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 "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# 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. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $debug_cmd + + 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 + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + case $nm_interface in + "MS dumpbin") + if func_cygming_ms_implib_p "$1" || + func_cygming_gnu_implib_p "$1" + then + win32_nmres=import + else + win32_nmres= + fi + ;; + *) + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s|.*|import| + p + q + } + }'` + ;; + esac + 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_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $debug_cmd + + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $debug_cmd + + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive that possess that section. Heuristic: eliminate + # all those that have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $debug_cmd + + if func_cygming_gnu_implib_p "$1"; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1"; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result= + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $debug_cmd + + f_ex_an_ar_dir=$1; shift + f_ex_an_ar_oldlib=$1 + if test yes = "$lock_old_archive_extraction"; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test yes = "$lock_old_archive_extraction"; then + $opt_dry_run || rm -f "$lockfile" + fi + 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 () +{ + $debug_cmd + + 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` + func_basename "$darwin_archive" + darwin_base_archive=$func_basename_result + 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 "$sed_basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $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 | sort | $NL2SP` + done + + func_extract_archives_result=$my_oldobjs +} + + +# 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 where it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE) $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. +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 + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ that is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options that match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED '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 \"\$file\" | $SED '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 \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_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 \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test yes = "$fast_install"; 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" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test yes = "$shlibpath_overrides_runpath" && 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 \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${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\ +" +} + + +# 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 +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* declarations of non-ANSI functions */ +#if defined __MINGW32__ +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined __CYGWIN__ +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined other_platform || defined ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined _MSC_VER +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +#elif defined __MINGW32__ +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined __CYGWIN__ +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined other platforms ... */ +#endif + +#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 + +/* path handling portability macros */ +#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 */ + +#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 (stale); stale = 0; } \ +} while (0) + +#if defined LT_DEBUGWRAPPER +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +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_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +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_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 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; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + 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]; + size_t tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + 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 = (size_t) (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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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) + { + lt_debugprintf (__FILE__, __LINE__, + "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 + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "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 (STREQ (str, pat)) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + size_t 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) + { + size_t orig_value_len = strlen (orig_value); + size_t 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; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (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 #' */ + size_t len = strlen (new_value); + while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[--len] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (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 + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $debug_cmd + + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_suncc_cstd_abi +# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! +# Several compiler flags select an ABI that is incompatible with the +# Cstd library. Avoid specifying it if any are in CXXFLAGS. +func_suncc_cstd_abi () +{ + $debug_cmd + + case " $compile_command " in + *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) + suncc_use_cstd_abi=no + ;; + *) + suncc_use_cstd_abi=yes + ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $debug_cmd + + 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 + # what 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 that 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 + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + os2dllname= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=false + 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 yes != "$build_libtool_libs" \ + && func_fatal_configuration "cannot build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test yes = "$build_libtool_libs" && 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 + bindir) + bindir=$arg + prev= + continue + ;; + dlfiles|dlprefiles) + $preload || { + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=: + } + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test no = "$dlself"; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test dlprefiles = "$prev"; then + dlself=yes + elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test dlfiles = "$prev"; then + func_append dlfiles " $arg" + else + func_append 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 "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir=$arg + prev= + continue + ;; + mllvm) + # Clang does not use LLVM to link, so we can simply discard any + # '-mllvm $arg' options when doing the link step. + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append 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 none = "$pic_object" && + test none = "$non_pic_object"; 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 none != "$pic_object"; then + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append 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 dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + fi + + # Non-PIC object. + if test none != "$non_pic_object"; 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 none = "$pic_object"; 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 + ;; + os2dllname) + os2dllname=$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 rpath = "$prev"; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds=$arg + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append 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 + ;; + + -bindir) + prev=bindir + 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-export-symbols = "X$arg"; 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" + if test -z "$func_stripname_result"; 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 + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # 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 "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test X-lc = "X$arg" || test X-lm = "X$arg"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # 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-lc = "X$arg" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc due to us having libc/libc_r. + test X-lc = "X$arg" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test X-lc = "X$arg" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test X-lc = "X$arg" && continue + ;; + esac + elif test X-lc_r = "X$arg"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -mllvm) + prev=mllvm + 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|--sysroot) + func_append 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|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append 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 + ;; + + -os2dllname) + prev=os2dllname + 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_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append 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" + func_append arg " $func_quote_for_eval_result" + func_append 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" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append 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 + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # -fstack-protector* stack protector flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -specs=* GCC specs files + # -stdlib=* select c++ std lib with clang + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ + -specs=*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + -Z*) + if test os2 = "`expr $host : '.*\(os2\)'`"; then + # OS/2 uses -Zxxx to specify OS/2-specific options + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case $arg in + -Zlinker | -Zstack) + prev=xcompiler + ;; + esac + continue + else + # Otherwise treat like 'Some other compiler flag' below + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + fi + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + + *.$objext) + # A standard object. + func_append 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 none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + test none = "$pic_object" || { + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append 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 dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + } + + # Non-PIC object. + if test none != "$non_pic_object"; 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 none = "$pic_object"; 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. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test dlfiles = "$prev"; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test dlprefiles = "$prev"; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + 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 yes = "$export_dynamic" && 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 \"\$$shlibpath_var\" \| \$SED \'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\" + + # Definition is injected by LT_CONFIG during libtool generation. + func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" + + func_dirname "$output" "/" "" + output_objdir=$func_dirname_result$objdir + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # 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_preserve_dup_deps; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test lib = "$linkmode"; 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 "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append 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=false + 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 lib,link = "$linkmode,$pass"; 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 lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass"; then + libs=$deplibs + deplibs= + fi + if test prog = "$linkmode"; then + case $pass in + dlopen) libs=$dlfiles ;; + dlpreopen) libs=$dlprefiles ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test lib,dlpreopen = "$linkmode,$pass"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs=$dlprefiles + fi + if test dlopen = "$pass"; then + # Collect dlpreopened libraries + save_deplibs=$deplibs + deplibs= + fi + + for deplib in $libs; do + lib= + found=false + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test lib != "$linkmode" && test prog != "$linkmode"; then + func_warning "'-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test lib = "$linkmode"; 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 .la = "$search_ext"; then + found=: + else + found=false + fi + break 2 + fi + done + done + if $found; then + # 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 yes = "$allow_libtool_libs_with_static_runtimes"; 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=false + func_dirname "$lib" "" "." + ladir=$func_dirname_result + lib=$ladir/$old_library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + else + # deplib doesn't seem to be a libtool library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + *.ltframework) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test conv = "$pass" && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + if test scan = "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "'-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test link = "$pass"; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test conv = "$pass"; 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=false + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=: + fi + ;; + pass_all) + valid_a_lib=: + ;; + esac + if $valid_a_lib; then + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + else + 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." + fi + ;; + esac + continue + ;; + prog) + if test link != "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + elif test prog = "$linkmode"; then + if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=: + continue + ;; + esac # case $deplib + + $found || test -f "$lib" \ + || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" + + # 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 "$inherited_linker_flags" | $SED '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 "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass" || + { test prog != "$linkmode" && test lib != "$linkmode"; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test conv = "$pass"; 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. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + elif test prog != "$linkmode" && test lib != "$linkmode"; then + func_fatal_error "'$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test yes = "$prefer_static_libs" || + test built,no = "$prefer_static_libs,$installed"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib=$l + done + fi + 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 dlopen = "$pass"; then + test -z "$libdir" \ + && func_fatal_error "cannot -dlopen a convenience library: '$lib'" + if test -z "$dlname" || + test yes != "$dlopen_support" || + test no = "$build_libtool_libs" + 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. + func_append dlprefiles " $lib $dependency_libs" + else + func_append 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 yes = "$installed"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library '$lib' was moved." + dir=$ladir + absdir=$abs_ladir + libdir=$abs_ladir + else + dir=$lt_sysroot$libdir + absdir=$lt_sysroot$libdir + fi + test yes = "$hardcode_automatic" && 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 + func_append notinst_path " $abs_ladir" + else + dir=$ladir/$objdir + absdir=$abs_ladir/$objdir + # Remove this search path later + func_append 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 dlpreopen = "$pass"; then + if test -z "$libdir" && test prog = "$linkmode"; then + func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" + fi + case $host in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append 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" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append 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" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test lib = "$linkmode"; then + deplibs="$dir/$old_library $deplibs" + elif test prog,link = "$linkmode,$pass"; 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 prog = "$linkmode" && test link != "$pass"; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=false + if test no != "$link_all_deplibs" || test -z "$library_names" || + test no = "$build_libtool_libs"; then + linkalldeplibs=: + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if $linkalldeplibs; 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_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test prog,link = "$linkmode,$pass"; then + if test -n "$library_names" && + { { test no = "$prefer_static_libs" || + test built,yes = "$prefer_static_libs,$installed"; } || + 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:"*) ;; + *) func_append 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if $alldeplibs && + { test pass_all = "$deplibs_check_method" || + { test yes = "$build_libtool_libs" && + 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 built = "$use_static_libs" && test yes = "$installed"; then + use_static_libs=no + fi + if test -n "$library_names" && + { test no = "$use_static_libs" || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc* | *os2*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test no = "$installed"; then + func_append 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 yes = "$shouldnotlink" && test link = "$pass"; then + echo + if test prog = "$linkmode"; 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 lib = "$linkmode" && + test yes = "$hardcode_into_libs"; 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append 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* | *os2*) + 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 prog = "$linkmode" || test relink != "$opt_mode"; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test no = "$hardcode_direct"; 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 cannot + # 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 no = "$hardcode_minus_L"; then + case $host in + *-*-sunos*) add_shlibpath=$dir ;; + esac + add_dir=-L$dir + add=-l$name + elif test no = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + relink) + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$dir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$absdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test yes != "$lib_linked"; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test prog = "$linkmode"; 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 yes != "$hardcode_direct" && + test yes != "$hardcode_minus_L" && + test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test prog = "$linkmode" || test relink = "$opt_mode"; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$libdir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$libdir + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add=-l$name + elif test yes = "$hardcode_automatic"; 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 + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + fi + + if test prog = "$linkmode"; 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 prog = "$linkmode"; 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 unsupported != "$hardcode_direct"; 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 yes = "$build_libtool_libs"; then + # Not a shared library + if test pass_all != "$deplibs_check_method"; 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 cannot 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 yes = "$module"; 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 no = "$build_old_libs"; 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 lib = "$linkmode"; then + if test -n "$dependency_libs" && + { test yes != "$hardcode_into_libs" || + test yes = "$build_old_libs" || + test yes = "$link_static"; }; 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 "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs=$temp_deplibs + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test no != "$link_all_deplibs"; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path=$deplib ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + 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 + func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" + func_append 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 link = "$pass"; then + if test prog = "$linkmode"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs=$newdependency_libs + if test dlpreopen = "$pass"; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test dlopen != "$pass"; then + test conv = "$pass" || { + # 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 "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + } + + if test prog,link = "$linkmode,$pass"; then + vars="compile_deplibs finalize_deplibs" + else + vars=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 "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + + # Add Sun CC postdeps if required: + test CXX = "$tagname" && { + case $host_os in + linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C++ 5.9 + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + + solaris*) + func_cc_basename "$CC" + case $func_cc_basename_result in + CC* | sunCC*) + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + esac + } + + # 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 + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test prog = "$linkmode"; then + dlfiles=$newdlfiles + fi + if test prog = "$linkmode" || test lib = "$linkmode"; then + dlprefiles=$newdlprefiles + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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 + func_append 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 no = "$module" \ + && func_fatal_help "libtool library '$output' must begin with 'lib'" + + if test no != "$need_lib_prefix"; 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 pass_all != "$deplibs_check_method"; 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!" + func_append libobjs " $objs" + fi + fi + + test no = "$dlself" \ + || func_warning "'-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test 1 -lt "$#" \ + && func_warning "ignoring multiple '-rpath's for a libtool library" + + install_libdir=$1 + + oldlibs= + if test -z "$rpath"; then + if test yes = "$build_libtool_libs"; 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 + # that has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|freebsd-elf|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_revision + ;; + freebsd-aout|qnx|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 + ;; + 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" + # On Darwin other compilers + case $CC in + nagfor*) + verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + ;; + *) + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + esac + ;; + + freebsd-aout) + major=.$current + versuffix=.$current.$revision + ;; + + freebsd-elf) + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + irix | nonstopux) + if test no = "$lt_irix_increment"; 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 0 -ne "$loop"; 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) # correct to gnu/linux during the next big refactor + 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 0 -ne "$loop"; 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. + func_append verstring ":$current.0" + ;; + + qnx) + major=.$current + versuffix=.$current + ;; + + sco) + major=.$current + versuffix=.$current + ;; + + sunos) + major=.$current + versuffix=.$current.$revision + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 file systems. + 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 no = "$need_version"; then + versuffix= + else + versuffix=.0.0 + fi + fi + + # Remove version info from name if versioning should be avoided + if test yes,no = "$avoid_version,$need_version"; then + major= + versuffix= + verstring= + fi + + # Check to see if the archive will have undefined symbols. + if test yes = "$allow_undefined"; then + if test unsupported = "$allow_undefined_flag"; then + if test yes = "$build_old_libs"; then + func_warning "undefined symbols not allowed in $host shared libraries; building static only" + build_libtool_libs=no + else + func_fatal_error "can't build $host shared library unless -no-undefined is specified" + fi + fi + else + # Don't allow undefined symbols. + allow_undefined_flag=$no_undefined_flag + fi + + fi + + func_generate_dlsyms "$libname" "$libname" : + func_append libobjs " $symfileobj" + test " " = "$libobjs" && libobjs= + + if test relink != "$opt_mode"; 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 -n "$precious_files_regex"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "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 + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; 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 "*) ;; + *) func_append 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 "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test yes = "$build_libtool_libs"; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append 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 yes = "$build_libtool_need_lc"; then + func_append 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` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + 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 "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append 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. + func_append 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 yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append 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 \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append 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. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs= + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + for i in $predeps $postdeps; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test none = "$deplibs_check_method"; 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 + ;; + esac + ;; + 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 " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test yes = "$droppeddeps"; then + if test yes = "$module"; 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 no = "$build_old_libs"; 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 no = "$allow_undefined"; 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 no = "$build_old_libs"; 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 " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED '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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append 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 yes = "$build_libtool_libs"; then + # Remove $wl instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test yes = "$hardcode_into_libs"; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath=$finalize_rpath + test relink = "$opt_mode" || rpath=$compile_rpath$rpath + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append 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 relink = "$opt_mode" || 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 + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$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 + func_append 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 + func_dll_def_p "$export_symbols" || { + # 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 + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test yes = "$always_export_symbols" || 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 cmd1 in $cmds; do + IFS=$save_ifs + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test yes = "$try_normal_branch" \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=$output_objdir/$output_la.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + 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 : != "$skipped_export"; 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 "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test : != "$skipped_export" && 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 + func_append 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 "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs=$tmp_deplibs + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test yes = "$compiler_needs_object" && + 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 + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test relink = "$opt_mode"; 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 yes = "$module" && 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 : != "$skipped_export" && + 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 + func_basename "$output" + output_la=$func_basename_result + + # 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 : != "$skipped_export" && test yes = "$with_gnu_ld"; then + output=$output_objdir/$output_la.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then + output=$output_objdir/$output_la.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test yes = "$compiler_needs_object"; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + 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 -z "$objlist" || + 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 1 -eq "$k"; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$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~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + ${skipped_export-false} && { + 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 + } + + 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_quiet || { + 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 relink = "$opt_mode"; 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 + + ${skipped_export-false} && { + 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 "$include_expsyms" | $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 + func_append 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 + } + + 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 yes = "$module" && 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 + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs=$IFS; IFS='~' + for cmd in $cmds; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + $opt_quiet || { + 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 relink = "$opt_mode"; 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 relink = "$opt_mode"; 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 yes = "$module" || test yes = "$export_dynamic"; then + # On all known operating systems, these are identical. + dlname=$soname + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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= + # if reload_cmds runs $LD directly, get rid of -Wl from + # whole_archive_flag_spec and hope we can get by with turning comma + # into space. + case $reload_cmds in + *\$LD[\ \$]*) wl= ;; + esac + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags + else + gentop=$output_objdir/${obj}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test yes = "$build_libtool_libs" || libobjs=$non_pic_objects + + # Create the old-style object. + reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs + + 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 + + test yes = "$build_libtool_libs" || { + 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 + } + + if test -n "$pic_flag" || test default != "$pic_mode"; 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" + + $preload \ + && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ + && 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 " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 CXX = "$tagname"; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " $wl-bind_at_load" + func_append finalize_command " $wl-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED '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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs=$new_libs + + + func_append compile_command " $compile_deplibs" + func_append 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 "*) ;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 yes = "$build_old_libs"; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" false + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=: + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=false + ;; + *cygwin* | *mingw* ) + test yes = "$build_libtool_libs" || wrappers_required=false + ;; + *) + if test no = "$need_relink" || test yes != "$build_libtool_libs"; then + wrappers_required=false + fi + ;; + esac + $wrappers_required || { + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED '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=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # 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 + } + + 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 + func_append 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 + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test yes = "$no_install"; 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 "$link_command" | $SED '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 $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + case $hardcode_action,$fast_install in + relink,*) + # 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" + ;; + *,yes) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + ;; + *,no) + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + ;; + *,needless) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command= + ;; + esac + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED '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 $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # 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 "$relink_command" | $SED "$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 + + case $build_libtool_libs in + convenience) + oldobjs="$libobjs_save $symfileobj" + addlibs=$convenience + build_libtool_libs=no + ;; + module) + oldobjs=$libobjs_save + addlibs=$old_convenience + build_libtool_libs=no + ;; + *) + oldobjs="$old_deplibs $non_pic_objects" + $preload && test -f "$symfileobj" \ + && func_append oldobjs " $symfileobj" + addlibs=$old_convenience + ;; + esac + + if test -n "$addlibs"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; 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 + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append 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 + func_append 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" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + 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 + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + 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 -z "$oldobjs"; 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 yes = "$build_old_libs" && 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 "$relink_command" | $SED "$sed_quote_subst"` + if test yes = "$hardcode_automatic"; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test yes = "$installed"; 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 + func_resolve_sysroot "$deplib" + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append 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" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append 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" + func_append newdlprefiles " ${lt_sysroot:+=}$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 + func_append newdlfiles " $abs" + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles=$newdlprefiles + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test -n "$bindir"; then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result/$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE) $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 cannot 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 no,yes = "$installed,$need_relink"; 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 +} + +if test link = "$opt_mode" || test relink = "$opt_mode"; then + func_mode_link ${1+"$@"} +fi + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $debug_cmd + + RM=$nonopt + files= + rmforce=false + 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) func_append RM " $arg"; rmforce=: ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir=$func_dirname_result + if test . = "$dir"; then + odir=$objdir + else + odir=$dir/$objdir + fi + func_basename "$file" + name=$func_basename_result + test uninstall = "$opt_mode" && odir=$dir + + # Remember odir for removal later, being careful to avoid duplicates + if test clean = "$opt_mode"; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + 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 $rmforce; 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 + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case $opt_mode in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" '$rmforce || 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 none != "$pic_object"; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && test none != "$non_pic_object"; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test clean = "$opt_mode"; 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 + func_append 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 + func_append 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 + func_append rmfiles " $odir/$name $odir/${name}S.$objext" + if test yes = "$fast_install" && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name"; then + func_append rmfiles " $odir/lt-$noexename.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # 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 +} + +if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then + func_mode_uninstall ${1+"$@"} +fi + +test -z "$opt_mode" && { + help=$generic_help + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode '$opt_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 +# where 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: 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..a644432 --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,8372 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996-2001, 2003-2015 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) 2014 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 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 this program. If not, see . +]) + +# serial 58 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.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +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 + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +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_PREPARE_CC_BASENAME +# ----------------------- +m4_defun([_LT_PREPARE_CC_BASENAME], [ +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in @S|@*""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} +])# _LT_PREPARE_CC_BASENAME + + +# _LT_CC_BASENAME(CC) +# ------------------- +# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, +# but that macro is also expanded into generated libtool script, which +# arranges for $SED and $ECHO to be set by different means. +m4_defun([_LT_CC_BASENAME], +[m4_require([_LT_PREPARE_CC_BASENAME])dnl +AC_REQUIRE([_LT_DECL_SED])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl +func_cc_basename $1 +cc_basename=$func_cc_basename_result +]) + + +# _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 +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +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_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl +m4_require([_LT_CMD_TRUNCATE])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options that 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 + +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 set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# 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_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify 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' +]) + +# _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 "$][$1" | $SED "$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 "$" | $SED "$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' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + 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 \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# '#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test 0 = "$lt_write_fail" && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_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]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +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) 2011 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. +lt_cl_success=: +test yes = "$silent" && + 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) +])# 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 that 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 +# Generated automatically by $as_me ($PACKAGE) $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. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +_LT_COPYING +_LT_LIBTOOL_TAGS + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +_LT_PREPARE_MUNGE_PATH_LIST +_LT_PREPARE_CC_BASENAME + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_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 set != "${COLLECT_NAMES+set}"; 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 '$q' "$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' + 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)], + [Go], [_LT_LANG(GO)], + [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 + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _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([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +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)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +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], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _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 there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; 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 + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + 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 yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; 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" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# 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 + if test yes = "$lt_cv_ld_force_load"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + _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 yes != "$lt_cv_apple_cc_single_mod"; 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([TAGNAME]) +# ---------------------------------- +# 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. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`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 "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script that will find a shell with a builtin +# printf (that we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case $ECHO in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [Search for dependent libraries within DIR (or the compiler's sysroot + if not specified).])], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([$with_sysroot]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and where our libraries should be installed.])]) + +# _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 no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode + # options accordingly. + 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 what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test yes = "$lt_cv_prog_gnu_ld"; 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* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + 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*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + 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" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + 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 yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + 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*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + 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_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +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 + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_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_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _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" ## exclude from sc_useless_quotes_in_assignment + # 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:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 yes = "[$]$2"; 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 "$_lt_linker_boilerplate" | $SED '/^$/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 yes = "[$]$2"; 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; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + 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; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # 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 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + 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" && \ + test undefined != "$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`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 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 yes = "$cross_compiling"; 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 $LINENO "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 + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* 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 yes != "$enable_dlopen"; 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 + ]) + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + 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 no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && 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 yes = "$lt_cv_dlopen_self"; 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:$LINENO: $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:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; 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 no = "$hard_links"; 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 where 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 yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then + + # We can hardcode non-existent directories. + if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && + # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && + test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; 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 relink = "$_LT_TAGVAR(hardcode_action, $1)" || + test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; 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_PREPARE_MUNGE_PATH_LIST +# --------------------------- +# Make sure func_munge_path_list() is defined correctly. +m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], +[[# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x@S|@2 in + x) + ;; + *:) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" + ;; + x:*) + eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" + ;; + *) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + esac +} +]])# _LT_PREPARE_PATH_LIST + + +# _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 +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # 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 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # 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` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + 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" + elif test -n "$lt_multi_os_dir"; then + 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; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +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 + +AC_ARG_VAR([LT_SYS_LIBRARY_PATH], +[User-defined run-time library search path.]) + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; 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 + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # 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' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a[(]lib.so.V[)]' + # 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' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + 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=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $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 # correct to gnu/linux during the next big refactor + 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,$cc_basename in + yes,*) + # gcc + 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' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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 # correct to gnu/linux during the next big refactor + 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 + ;; + +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[[23]].*) 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$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + 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 + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # 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 + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + 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], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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 + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) 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;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $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' + ;; + +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 # correct to gnu/linux during the next big refactor + 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* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + 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 + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + 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' + ;; + +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 # correct to gnu/linux during the next big refactor + 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 yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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=sco + 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 yes = "$with_gnu_ld"; 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 # correct to gnu/linux during the next big refactor + 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 # correct to gnu/linux during the next big refactor + 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 no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + +_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([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_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], [configure_time_dlsearch_path], [2], + [Detected run-time system search path for libraries]) +_LT_DECL([], [configure_time_lt_sys_library_path], [2], + [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program that 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 that 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 +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test no = "$withval" || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test yes = "$GCC"; 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 yes = "$with_gnu_ld"; 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 conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], +[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi]) +rm -f conftest.i conftest2.i conftest.out]) +])# _LT_PATH_DD + + +# _LT_CMD_TRUNCATE +# ---------------- +# find command to truncate a binary pipe +m4_defun([_LT_CMD_TRUNCATE], +[m4_require([_LT_PATH_DD]) +AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) +_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], + [Command to truncate a binary pipe]) +])# _LT_CMD_TRUNCATE + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[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 +# that 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 + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + 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 + ;; + +haiku*) + 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])(-bit)?( [LM]SB)? 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + 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* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +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_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob 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 + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + 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 no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + 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:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $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:$LINENO: 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_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# _LT_DLL_DEF_P([FILE]) +# --------------------- +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with func_dll_def_p in the libtool script +AC_DEFUN([_LT_DLL_DEF_P], +[dnl + test DEF = "`$SED -n dnl + -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace + -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments + -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl + -e q dnl Only consider the first "real" line + $1`" dnl +])# _LT_DLL_DEF_P + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-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 yes = "$GCC"; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _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([AC_PROG_AWK])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 ia64 = "$host_cpu"; 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 + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# 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"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$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"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, + # D for any global variable and I for any imported 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};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,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 + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # 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 +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#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. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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_globsym_save_LIBS=$LIBS + lt_globsym_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_globsym_save_LIBS + CFLAGS=$lt_globsym_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 yes = "$pipe_works"; 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 + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +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_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) +_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_DECL([nm_interface], [lt_cv_nm_interface], [1], + [The name lister interface]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _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)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; 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 ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + 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']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + 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)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $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 ia64 = "$host_cpu"; 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 + ;; + 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). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + 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 ia64 != "$host_cpu"; 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 | 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* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _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*) + ;; + *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* | sunCC*) + # 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 yes = "$GCC"; 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 ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + 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']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + 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' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + 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 + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + 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 ia64 = "$host_cpu"; 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 + ;; + + 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' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + + 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']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + 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 | 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' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny 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)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # 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* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _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\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # 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)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _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 ' + ;; + *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,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + 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* | sunf77* | sunf90* | sunf95*) + _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 that 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_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# 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]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# 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_PATH_MANIFEST_TOOL])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' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + 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 GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX 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") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + 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_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 yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([^)]\+)\s\+//' 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 ia64 != "$host_cpu"; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, 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 install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_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(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _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/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + 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, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); 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 + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + 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; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # 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; func_echo_all \"$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' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + 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; func_echo_all \"$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 yes = "$supports_anon_versioning"; 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 + tcc*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # 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)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; 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 $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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 cannot +*** 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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 no = "$_LT_TAGVAR(ld_shlibs, $1)"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX 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") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + 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,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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([$1]) + _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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; 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([$1]) + _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' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + 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. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _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' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _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 `func_echo_all "$deplibs" | $SED '\''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(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + 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 + ;; + + # 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 $pic_flag -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 yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $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 no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$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 yes,no = "$GCC,$with_gnu_ld"; 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 $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $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' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_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 no = "$with_gnu_ld"; 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 yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $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. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS=$save_LDFLAGS]) + if test yes = "$lt_cv_irix_exported_symbol"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -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" && func_echo_all "-set_version $verstring"` -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 + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(ld_shlibs, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd*) + 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* | bitrig*) + 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__`"; 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 + _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' + 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 + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + osf3*) + if test yes = "$GCC"; 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" && func_echo_all "$wl-set_version $wl$verstring"` $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" && func_echo_all "-set_version $verstring"` -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 yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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 yes = "$GCC"; then + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $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 $pic_flag $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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; 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 no = "$_LT_TAGVAR(ld_shlibs, $1)" && 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 yes,yes = "$GCC,$enable_shared"; 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_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$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_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_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* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_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_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([], [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([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_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 what 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC=$lt_save_CC +])# _LT_LANG_C_CONFIG + + +# _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], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +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_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(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 yes != "$_lt_caught_CXX_error"; 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_CFLAGS=$CFLAGS + 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++"} + CFLAGS=$CXXFLAGS + 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 yes = "$GXX"; 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 yes = "$GXX"; 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 yes = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -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 -v "^Configured with:" | $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 ia64 = "$host_cpu"; 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 + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + 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 + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + 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,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GXX"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; 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([$1]) + _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' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + 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*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # 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 + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _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(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _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, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); 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 + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + 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 + ;; + + freebsd2.*) + # 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 + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + 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 "x$output_objdir/$soname" = "x$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; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$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 no = "$with_gnu_ld"; 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; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; 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 $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $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" && func_echo_all "-set_version $verstring"` -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 yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -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 | 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; func_echo_all "$list"' + + _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 | sort | $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 | sort | $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 | sort | $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 | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above 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; func_echo_all \"$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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # 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 yes = "$supports_anon_versioning"; 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; func_echo_all \"$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='func_echo_all' + + # 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 + ;; + + openbsd* | bitrig*) + 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__`"; 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=func_echo_all + 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" && func_echo_all "$wl-set_version $verstring"` -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" && func_echo_all "-set_version $verstring"` -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 "-set_version $verstring"` -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=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; 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" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $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 -v "^Configured with:" | $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* | sunCC*) + # 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='func_echo_all' + + # 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 yes,no = "$GXX,$with_gnu_ld"; 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 $pic_flag -nostdlib $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 $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -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 -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $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 $wl-h $wl$soname -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 -v "^Configured with:" | $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 CANNOT 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(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _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 no = "$_LT_TAGVAR(ld_shlibs, $1)" && 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 + CFLAGS=$lt_save_CFLAGS + 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 yes != "$_lt_caught_CXX_error" + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf 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). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case @S|@2 in + .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; + *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + + +# _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 +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])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 +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +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 $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev 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 + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$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 no = "$pre_test_object_deps_done"; 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 +CFLAGS=$_lt_libdeps_save_CFLAGS + +# 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)= + ;; +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_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_LANG_PUSH(Fortran 77) +if test -z "$F77" || test no = "$F77"; then + _lt_disable_F77=yes +fi + +_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_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(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 yes != "$_lt_disable_F77"; 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 + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || 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 + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_F77" + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _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_LANG_PUSH(Fortran) + +if test -z "$FC" || test no = "$FC"; then + _lt_disable_FC=yes +fi + +_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_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(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 yes != "$_lt_disable_FC"; 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 + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || 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 + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_FC" + +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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +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 +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# 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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# Go 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 +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_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 +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +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 +CFLAGS=$lt_save_CFLAGS +])# _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 set = "${GCJFLAGS+set}" || 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_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# 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_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _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 10 -lt "$lt_ac_count" && 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], +[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_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine what file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 0000000..94b0829 --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,437 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004-2005, 2007-2009, 2011-2015 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 8 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_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], + [_LT_WITH_AIX_SONAME([aix])]) + ]) +])# _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], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [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_AIX_SONAME([DEFAULT]) +# ---------------------------------- +# implement the --with-aix-soname flag, and support the `aix-soname=aix' +# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT +# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +m4_define([_LT_WITH_AIX_SONAME], +[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl +shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[[5-9]]*,yes) + AC_MSG_CHECKING([which variant of shared library versioning to provide]) + AC_ARG_WITH([aix-soname], + [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) + with_aix_soname=$lt_cv_with_aix_soname]) + AC_MSG_RESULT([$with_aix_soname]) + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + +_LT_DECL([], [shared_archive_member_spec], [0], + [Shared archive member basename, for filename based shared library versioning on AIX])dnl +])# _LT_WITH_AIX_SONAME + +LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) + + +# _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@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [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..48bc934 --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,124 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007-2008, 2011-2015 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..fa04b52 --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004, 2011-2015 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. + +# @configure_input@ + +# serial 4179 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.6]) +m4_define([LT_PACKAGE_REVISION], [2.4.6]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.6' +macro_revision='2.4.6' +_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..c6b26f8 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,99 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 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 5 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_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])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/missing b/missing new file mode 100755 index 0000000..625aeb1 --- /dev/null +++ b/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# Originally written 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 + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +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 + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# 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..d60218b --- /dev/null +++ b/modules/Makefile.in @@ -0,0 +1,634 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = mixer +am__DIST_COMMON = $(srcdir)/Makefile.in +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am 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-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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..068861f --- /dev/null +++ b/modules/mixer/Makefile.in @@ -0,0 +1,634 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am 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-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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..6805484 --- /dev/null +++ b/modules/mixer/simple/Makefile.am @@ -0,0 +1,37 @@ +alsaplugindir = @ALSA_PLUGIN_DIR@ +pkglibdir = $(alsaplugindir)/smixer + +AM_CFLAGS = -g -O2 -W -Wall + +AM_CPPFLAGS=-I$(top_srcdir)/include + +pkglib_LTLIBRARIES = + +if BUILD_MIXER_MODULES +pkglib_LTLIBRARIES += smixer-sbase.la \ + smixer-ac97.la \ + smixer-hda.la +endif + +if BUILD_MIXER_PYMODULES +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 + +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) diff --git a/modules/mixer/simple/Makefile.in b/modules/mixer/simple/Makefile.in new file mode 100644 index 0000000..07197b4 --- /dev/null +++ b/modules/mixer/simple/Makefile.in @@ -0,0 +1,753 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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_MIXER_MODULES_TRUE@am__append_1 = smixer-sbase.la \ +@BUILD_MIXER_MODULES_TRUE@ smixer-ac97.la \ +@BUILD_MIXER_MODULES_TRUE@ smixer-hda.la + +@BUILD_MIXER_PYMODULES_TRUE@am__append_2 = smixer-python.la +subdir = modules/mixer/simple +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +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 \ + $@ +@BUILD_MIXER_MODULES_TRUE@am_smixer_ac97_la_rpath = -rpath \ +@BUILD_MIXER_MODULES_TRUE@ $(pkglibdir) +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 $@ +@BUILD_MIXER_MODULES_TRUE@am_smixer_hda_la_rpath = -rpath $(pkglibdir) +am__DEPENDENCIES_1 = +smixer_python_la_DEPENDENCIES = ../../../src/libasound.la \ + $(am__DEPENDENCIES_1) +am_smixer_python_la_OBJECTS = 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_MIXER_PYMODULES_TRUE@am_smixer_python_la_rpath = -rpath \ +@BUILD_MIXER_PYMODULES_TRUE@ $(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 $@ +@BUILD_MIXER_MODULES_TRUE@am_smixer_sbase_la_rpath = -rpath \ +@BUILD_MIXER_MODULES_TRUE@ $(pkglibdir) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/ac97.Plo ./$(DEPDIR)/hda.Plo \ + ./$(DEPDIR)/sbase.Plo ./$(DEPDIR)/sbasedl.Plo \ + ./$(DEPDIR)/smixer_python_la-python.Plo +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_CC_1 = +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_CCLD_1 = +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) \ + $(smixer_python_la_SOURCES) $(smixer_sbase_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkglibdir = $(alsaplugindir)/smixer +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +pkglib_LTLIBRARIES = $(am__append_1) $(am__append_2) +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 +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) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @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 " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ + 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)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +smixer-ac97.la: $(smixer_ac97_la_OBJECTS) $(smixer_ac97_la_DEPENDENCIES) $(EXTRA_smixer_ac97_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_ac97_la_LINK) $(am_smixer_ac97_la_rpath) $(smixer_ac97_la_OBJECTS) $(smixer_ac97_la_LIBADD) $(LIBS) + +smixer-hda.la: $(smixer_hda_la_OBJECTS) $(smixer_hda_la_DEPENDENCIES) $(EXTRA_smixer_hda_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_hda_la_LINK) $(am_smixer_hda_la_rpath) $(smixer_hda_la_OBJECTS) $(smixer_hda_la_LIBADD) $(LIBS) + +smixer-python.la: $(smixer_python_la_OBJECTS) $(smixer_python_la_DEPENDENCIES) $(EXTRA_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) $(EXTRA_smixer_sbase_la_DEPENDENCIES) + $(AM_V_CCLD)$(smixer_sbase_la_LINK) $(am_smixer_sbase_la_rpath) $(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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hda.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbase.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbasedl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smixer_python_la-python.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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 $@ $< + +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 +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)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@ $(AM_V_CC@am__nodep@)$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/ac97.Plo + -rm -f ./$(DEPDIR)/hda.Plo + -rm -f ./$(DEPDIR)/sbase.Plo + -rm -f ./$(DEPDIR)/sbasedl.Plo + -rm -f ./$(DEPDIR)/smixer_python_la-python.Plo + -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 -f ./$(DEPDIR)/ac97.Plo + -rm -f ./$(DEPDIR)/hda.Plo + -rm -f ./$(DEPDIR)/sbase.Plo + -rm -f ./$(DEPDIR)/sbasedl.Plo + -rm -f ./$(DEPDIR)/smixer_python_la-python.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + cscopelist-am ctags ctags-am 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 tags-am uninstall \ + uninstall-am uninstall-pkglibLTLIBRARIES + +.PRECIOUS: Makefile + + +# 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..a87b446 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..e62d4b0 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..3a627ab --- /dev/null +++ b/modules/mixer/simple/python.c @@ -0,0 +1,1149 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "Python.h" +#include +#include "config.h" +#include "asoundlib.h" +#include "mixer_abst.h" + +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + +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; + +#if PY_MAJOR_VERSION >= 3 + #define PyInt_FromLong PyLong_FromLong +#endif + +static inline int get_long(PyObject *o, long *val) +{ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(o)) { + *val = PyInt_AsLong(o); + return 0; + } +#endif + if (PyLong_Check(o)) { + *val = PyLong_AsLong(o); + return 0; + } + return 1; +} + +static inline PyObject *InternFromString(const char *name) +{ +#if PY_MAJOR_VERSION < 3 + return PyString_InternFromString(name); +#else + return PyUnicode_InternFromString(name); +#endif +} + +static void *get_C_ptr(PyObject *obj, const char *attr) +{ + PyObject *o; + long val; + + o = PyObject_GetAttr(obj, InternFromString(attr)); + if (!o) { + PyErr_Format(PyExc_TypeError, "missing '%s' attribute", attr); + return NULL; + } + if (get_long(o, &val)) { + PyErr_Format(PyExc_TypeError, "'%s' attribute is not Int or Long", attr); + return NULL; + } + return (void *)val; +} + +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; + long xres = 0; + + if (_res) + *_res = NULL; + obj = PyObject_GetAttr(obj, 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 (PyLong_Check(res)) { + xres = PyLong_AsLong(res); +#if PY_MAJOR_VERSION < 3 + } else if (PyInt_Check(res)) { + xres = PyInt_AsLong(res); +#endif + } 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, *t1, *t2, *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) { + t1 = PyTuple_GetItem(res, 1); + t2 = PyTuple_GetItem(res, 2); + if (PyLong_Check(t1) && PyLong_Check(t2)) { + *min = PyLong_AsLong(PyTuple_GetItem(res, 1)); + *max = PyLong_AsLong(PyTuple_GetItem(res, 2)); + err = 0; +#if PY_MAJOR_VERSION < 3 + } else if (PyInt_Check(t1) && PyInt_Check(t2)) { + *min = PyInt_AsLong(PyTuple_GetItem(res, 1)); + *max = PyInt_AsLong(PyTuple_GetItem(res, 2)); + err = 0; +#endif + } else { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } + } + 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, *t1, *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) { + t1 = PyTuple_GetItem(res, 1); + if (PyLong_Check(t1)) { + *value = PyLong_AsLong(t1); + err = 0; +#if PY_MAJOR_VERSION < 3 + } else if (PyInt_Check(t1)) { + *value = PyInt_AsLong(t1); + err = 0; +#endif + } else { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } + } + 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, *t1, *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) { + t1 = PyTuple_GetItem(res, 1); + if (PyLong_Check(t1)) { + *dbValue = PyLong_AsLong(t1); + err = 0; +#if PY_MAJOR_VERSION < 3 + } else if (PyInt_Check(t1)) { + *dbValue = PyInt_AsLong(t1); + err = 0; +#endif + } else { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } + } + 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, *obj2, *t1, *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) { + t1 = PyTuple_GetItem(res, 1); + if (PyUnicode_Check(t1)) { + obj2 = PyUnicode_AsEncodedString(t1, "utf-8", "strict"); + if (obj2) { + s = PyBytes_AsString(obj2); + len = strlen(s); + if (maxlen - 1 > len) + len = maxlen - 1; + memcpy(buf, s, len); + buf[len] = '\0'; + Py_DECREF(obj2); + } else { + goto errlbl; + } +#if PY_MAJOR_VERSION < 3 + } else if (PyString_Check(t1)) { + s = PyString_AsString(t1); + len = strlen(s); + if (maxlen - 1 > len) + len = maxlen - 1; + memcpy(buf, s, len); + buf[len] = '\0'; +#endif + } else { +errlbl: + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } + } + 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, *t1, *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) { + t1 = PyTuple_GetItem(res, 1); + if (PyLong_Check(t1)) { + *itemp = PyLong_AsLong(t1); + err = 0; +#if PY_MAJOR_VERSION < 3 + } else if (PyInt_Check(t1)) { + *itemp = PyInt_AsLong(t1); + err = 0; +#endif + } else { + PyErr_Format(PyExc_TypeError, "wrong result (invalid tuple)"); + PyErr_Print(); + PyErr_Clear(); + err = -EIO; + } + } + 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 PyUnicode_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 (PyLong_Check(val)) { + pymelem->selem.caps = PyLong_AsLong(val); + return 0; + } +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(val)) { + pymelem->selem.caps = PyInt_AsLong(val); + return 0; + } +#endif + PyErr_SetString(PyExc_TypeError, "The last attribute value must be an integer"); + return -1; +} + +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); +} + +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 = { + PyVarObject_HEAD_INIT(NULL, 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, PyUnicode_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); +} + +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 = { + PyVarObject_HEAD_INIT(NULL, 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; + PyObject *t, *o, *r; + int res = -ENOMEM; + + tstate = PyThreadState_New(main_interpreter); + 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 (PyLong_Check(r)) { + res = PyLong_AsLong(r); +#if PY_MAJOR_VERSION < 3 + } else if (PyInt_Check(r)) { + res = PyInt_AsLong(r); +#endif + } 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); +} + +static int alsa_mixer_simple_pyinit(struct python_priv *priv, + PyObject *py_mod, + FILE *fp, + const char *file, + snd_mixer_class_t *class, + snd_mixer_t *mixer, + const char *device) +{ + PyObject *obj, *obj1, *obj2, *mdict; + + mdict = priv->py_mdict = PyModule_GetDict(py_mod); + obj = PyUnicode_FromString(file); + if (obj) + PyDict_SetItemString(mdict, "__file__", obj); + Py_XDECREF(obj); + obj = PyUnicode_FromString(device); + if (obj) + PyDict_SetItemString(mdict, "device", obj); + Py_XDECREF(obj); + Py_INCREF(&pymelem_type); + 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; +} + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef smixer_python_module = { + PyModuleDef_HEAD_INIT, + "smixer_python", + NULL, + 0, + python_methods, + NULL, + NULL, + NULL, + NULL +}; +#endif + +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, *py_mod; + + 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 || + PyType_Ready(&pymixer_type) < 0) { + fclose(fp); + return -EIO; + } +#if PY_MAJOR_VERSION < 3 + Py_InitModule("smixer_python", python_methods); +#else + PyModule_Create(&smixer_python_module); +#endif + priv->py_initialized = 1; + main_interpreter = PyThreadState_Get()->interp; + obj = PyImport_GetModuleDict(); + py_mod = PyDict_GetItemString(obj, "__main__"); + if (py_mod) + alsa_mixer_simple_pyinit(priv, py_mod, fp, file, class, mixer, device); + return 0; +} diff --git a/modules/mixer/simple/sbase.c b/modules/mixer/simple/sbase.c new file mode 100644 index 0000000..29c853a --- /dev/null +++ b/modules/mixer/simple/sbase.c @@ -0,0 +1,586 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + 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); + 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); + free(hsimple); + 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..3e587cc --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..d8cbf0f --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, errbuf[256]; + 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, errbuf, sizeof(errbuf)); + if (h == NULL) { + SNDERR("Unable to open library '%s': %s", xlib, errbuf); + 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) + snd_dlclose(h); + free(xlib); + return -ENXIO; +} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..43fd333 --- /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 += conf +libasound_la_LIBADD += @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 + +topology/libtopology.la: + $(MAKE) -C topology libtopology.la + +instr/libinstr.la: + $(MAKE) -C instr libinstr.la + +alisp/libalisp.la: + $(MAKE) -C alisp libalisp.la + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..03263f8 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,894 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +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) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libasound_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libasound_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/async.Plo ./$(DEPDIR)/conf.Plo \ + ./$(DEPDIR)/confmisc.Plo ./$(DEPDIR)/dlmisc.Plo \ + ./$(DEPDIR)/error.Plo ./$(DEPDIR)/input.Plo \ + ./$(DEPDIR)/names.Plo ./$(DEPDIR)/output.Plo \ + ./$(DEPDIR)/shmarea.Plo ./$(DEPDIR)/socket.Plo \ + ./$(DEPDIR)/userfile.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libasound_la_SOURCES) +DIST_SOURCES = $(libasound_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = control mixer pcm timer rawmidi hwdep seq ucm alisp \ + conf +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Versions.in \ + $(top_srcdir)/depcomp +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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) 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) \ + @ALSA_DEPLIBS@ $(am__empty) +libasound_la_LDFLAGS = -version-info $(COMPATNUM) $(VSYMS) $(SYMFUNCS) $(LDFLAGS_NOUNDEFINED) +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) + @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 " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + 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)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libasound.la: $(libasound_la_OBJECTS) $(libasound_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/confmisc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dlmisc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/names.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shmarea.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userfile.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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 + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/async.Plo + -rm -f ./$(DEPDIR)/conf.Plo + -rm -f ./$(DEPDIR)/confmisc.Plo + -rm -f ./$(DEPDIR)/dlmisc.Plo + -rm -f ./$(DEPDIR)/error.Plo + -rm -f ./$(DEPDIR)/input.Plo + -rm -f ./$(DEPDIR)/names.Plo + -rm -f ./$(DEPDIR)/output.Plo + -rm -f ./$(DEPDIR)/shmarea.Plo + -rm -f ./$(DEPDIR)/socket.Plo + -rm -f ./$(DEPDIR)/userfile.Plo + -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 -f ./$(DEPDIR)/async.Plo + -rm -f ./$(DEPDIR)/conf.Plo + -rm -f ./$(DEPDIR)/confmisc.Plo + -rm -f ./$(DEPDIR)/dlmisc.Plo + -rm -f ./$(DEPDIR)/error.Plo + -rm -f ./$(DEPDIR)/input.Plo + -rm -f ./$(DEPDIR)/names.Plo + -rm -f ./$(DEPDIR)/output.Plo + -rm -f ./$(DEPDIR)/shmarea.Plo + -rm -f ./$(DEPDIR)/socket.Plo + -rm -f ./$(DEPDIR)/userfile.Plo + -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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am 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-am uninstall uninstall-am \ + uninstall-libLTLIBRARIES + +.PRECIOUS: Makefile + + +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 + +topology/libtopology.la: + $(MAKE) -C topology libtopology.la + +instr/libinstr.la: + $(MAKE) -C instr libinstr.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 b/src/Versions new file mode 100644 index 0000000..de97abe --- /dev/null +++ b/src/Versions @@ -0,0 +1,136 @@ +ALSA_0.9 { + global: + snd_*; + + _snd_*_open; + _snd_*_dlsym_*; + _snd_*_poll_descriptor; + _snd_pcm_hook_*; + + __snd_pcm_hw_params_*; + __snd_pcm_sw_params_*; + __snd_*_dlsym_*; + + local: + *; +}; + +ALSA_0.9.0rc4 { + global: + + snd_pcm_hw_params_get_access; + snd_pcm_hw_params_set_access_first; + snd_pcm_hw_params_set_access_last; + + snd_pcm_hw_params_get_format; + snd_pcm_hw_params_set_format_first; + snd_pcm_hw_params_set_format_last; + + snd_pcm_hw_params_get_subformat; + snd_pcm_hw_params_set_subformat_first; + snd_pcm_hw_params_set_subformat_last; + + snd_pcm_hw_params_get_channels; + snd_pcm_hw_params_get_channels_min; + snd_pcm_hw_params_get_channels_max; + snd_pcm_hw_params_set_channels_near; + snd_pcm_hw_params_set_channels_first; + snd_pcm_hw_params_set_channels_last; + + snd_pcm_hw_params_get_rate; + snd_pcm_hw_params_get_rate_min; + snd_pcm_hw_params_get_rate_max; + snd_pcm_hw_params_set_rate_near; + snd_pcm_hw_params_set_rate_first; + snd_pcm_hw_params_set_rate_last; + + snd_pcm_hw_params_get_period_time; + snd_pcm_hw_params_get_period_time_min; + snd_pcm_hw_params_get_period_time_max; + snd_pcm_hw_params_set_period_time_near; + snd_pcm_hw_params_set_period_time_first; + snd_pcm_hw_params_set_period_time_last; + + snd_pcm_hw_params_get_period_size; + snd_pcm_hw_params_get_period_size_min; + snd_pcm_hw_params_get_period_size_max; + snd_pcm_hw_params_set_period_size_near; + snd_pcm_hw_params_set_period_size_first; + snd_pcm_hw_params_set_period_size_last; + + snd_pcm_hw_params_get_periods; + snd_pcm_hw_params_get_periods_min; + snd_pcm_hw_params_get_periods_max; + snd_pcm_hw_params_set_periods_near; + snd_pcm_hw_params_set_periods_first; + snd_pcm_hw_params_set_periods_last; + + snd_pcm_hw_params_get_buffer_time; + snd_pcm_hw_params_get_buffer_time_min; + snd_pcm_hw_params_get_buffer_time_max; + snd_pcm_hw_params_set_buffer_time_near; + snd_pcm_hw_params_set_buffer_time_first; + snd_pcm_hw_params_set_buffer_time_last; + + snd_pcm_hw_params_get_buffer_size; + snd_pcm_hw_params_get_buffer_size_min; + snd_pcm_hw_params_get_buffer_size_max; + snd_pcm_hw_params_set_buffer_size_near; + snd_pcm_hw_params_set_buffer_size_first; + snd_pcm_hw_params_set_buffer_size_last; + + snd_pcm_hw_params_get_tick_time; + snd_pcm_hw_params_get_tick_time_min; + snd_pcm_hw_params_get_tick_time_max; + snd_pcm_hw_params_set_tick_time_near; + snd_pcm_hw_params_set_tick_time_first; + snd_pcm_hw_params_set_tick_time_last; + +} ALSA_0.9; + +ALSA_0.9.0rc8 { + global: + + snd_pcm_forward; + snd_pcm_status_get_trigger_htstamp; + snd_pcm_status_get_htstamp; + +} ALSA_0.9.0rc4; + +ALSA_0.9.0 { + global: + + snd_pcm_type_name; + snd_timer_query_info; + snd_timer_query_params; + snd_timer_query_status; + snd_timer_params_set_exclusive; + snd_timer_params_get_exclusive; + snd_timer_params_set_filter; + snd_timer_params_get_filter; +} ALSA_0.9.0rc8; + +ALSA_0.9.3 { + global: + + snd_ctl_elem_info_get_dimensions; + snd_ctl_elem_info_get_dimension; +} ALSA_0.9.0; + +ALSA_0.9.5 { + global: + + alsa_lisp; +} ALSA_0.9.3; + +ALSA_0.9.7 { + global: + + alsa_lisp_*; +} ALSA_0.9.5; + +ALSA_1.1.6 { + global: + + snd_dlopen; +} ALSA_0.9.7; diff --git a/src/Versions.in b/src/Versions.in new file mode 100644 index 0000000..5daccbd --- /dev/null +++ b/src/Versions.in @@ -0,0 +1,136 @@ +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; + +ALSA_1.1.6 { + global: + + @SYMBOL_PREFIX@snd_dlopen; +} ALSA_0.9.7; diff --git a/src/alisp/Makefile.am b/src/alisp/Makefile.am new file mode 100644 index 0000000..1234e11 --- /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 + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/alisp/Makefile.in b/src/alisp/Makefile.in new file mode 100644 index 0000000..a9c40ee --- /dev/null +++ b/src/alisp/Makefile.in @@ -0,0 +1,602 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/alisp.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libalisp_la_SOURCES) +DIST_SOURCES = $(libalisp_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libalisp.la: $(libalisp_la_OBJECTS) $(libalisp_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/alisp.Plo + -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 -f ./$(DEPDIR)/alisp.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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..476d0d5 --- /dev/null +++ b/src/alisp/alisp.c @@ -0,0 +1,3494 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 writing (%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 writing (%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, snd_config_topdir()); + } + 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 *)calloc(1, sizeof(struct alisp_instance)); + if (instance == NULL) { + nomem(); + return -ENOMEM; + } + 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 retval; +} + +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..af63884 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "../control/control_local.h" + +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 = {0}; + 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; + 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 = {0}; + 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; + } + 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 = {0}; + snd_ctl_elem_id_t id = {0}; + 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; + 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, "writable", 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 = INTERNAL(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, INTERNAL(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 = {0}; + snd_ctl_elem_value_t value = {0}; + 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; + 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 = {0}; + snd_ctl_elem_value_t value = {0}; + 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; + } + 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 = {0}; + 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; + 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..e6a8b5f --- /dev/null +++ b/src/async.c @@ -0,0 +1,212 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "pcm/pcm_local.h" +#include "control/control_local.h" +#include + +static struct sigaction previous_action; +#define MAX_SIG_FUNCTION_CODE 10 /* i.e. SIG_DFL SIG_IGN SIG_HOLD et al */ + +#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); + if (signo == SIGIO + && (unsigned long)(previous_action.sa_sigaction) > MAX_SIG_FUNCTION_CODE) + previous_action.sa_sigaction(signo, siginfo, context); + 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); + assert(!previous_action.sa_sigaction); + err = sigaction(snd_async_signo, &act, &previous_action); + 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; + int was_empty = list_empty(&snd_async_handlers); + assert(handler); + list_del(&handler->glist); + if (!was_empty + && list_empty(&snd_async_handlers)) { + err = sigaction(snd_async_signo, &previous_action, NULL); + if (err < 0) { + SYSERR("sigaction"); + return -errno; + } + memset(&previous_action, 0, sizeof(previous_action)); + } + 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/conf.c b/src/conf.c new file mode 100644 index 0000000..e430650 --- /dev/null +++ b/src/conf.c @@ -0,0 +1,5291 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "local.h" +#include +#include +#include +#include +#include +#ifdef HAVE_LIBPTHREAD +#include +#endif + +#ifndef DOC_HIDDEN + +#ifdef HAVE_LIBPTHREAD +static pthread_mutex_t snd_config_update_mutex; +static pthread_once_t snd_config_update_mutex_once = PTHREAD_ONCE_INIT; +#endif + +struct _snd_config { + char *id; + snd_config_type_t type; + int refcount; /* default = 0 */ + 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; + + /* list of the include paths (configuration directories), + * defined by , + * for searching its included files. + */ + struct list_head include_paths; +}; + +/* path to search included files */ +struct include_path { + char *dir; + struct list_head list; +}; + +#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 void snd_config_init_mutex(void) +{ + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); +#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif + pthread_mutex_init(&snd_config_update_mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + +static inline void snd_config_lock(void) +{ + pthread_once(&snd_config_update_mutex_once, snd_config_init_mutex); + 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 + +/* + * Add a diretory to the paths to search included files. + * param fd - File object that owns these paths to search files included by it. + * param dir - Path of the directory to add. Allocated externally and need to +* be freed manually later. + * return - Zero if successful, otherwise a negative error code. + * + * The direcotry should be a subdiretory of top configuration directory + * "/usr/share/alsa/". + */ +static int add_include_path(struct filedesc *fd, const char *dir) +{ + struct include_path *path; + struct filedesc *fd1; + struct list_head *pos; + + /* check, if dir is already registered (also in parents) */ + for (fd1 = fd; fd1; fd1 = fd1->next) { + list_for_each(pos, &fd1->include_paths) { + path = list_entry(pos, struct include_path, list); + if (strcmp(path->dir, dir) == 0) + return 0; + } + } + + path = calloc(1, sizeof(*path)); + if (!path) + return -ENOMEM; + + path->dir = strdup(dir); + if (path->dir == NULL) { + free(path); + return -ENOMEM; + } + + list_add_tail(&path->list, &fd->include_paths); + return 0; +} + +/* + * Free all include paths of a file descriptor. + * param fd - File object that owns these paths to search files included by it. + */ +static void free_include_paths(struct filedesc *fd) +{ + struct list_head *pos, *npos, *base; + struct include_path *path; + + base = &fd->include_paths; + list_for_each_safe(pos, npos, base) { + path = list_entry(pos, struct include_path, list); + list_del(&path->list); + if (path->dir) + free(path->dir); + free(path); + } +} + +/** + * \brief Returns the default top-level config directory + * \return The top-level config directory path string + * + * This function returns the string of the top-level config directory path. + * If the path is specified via the environment variable \c ALSA_CONFIG_DIR + * and the value is a valid path, it returns this value. If unspecified, it + * returns the default value, "/usr/share/alsa". + */ +const char *snd_config_topdir(void) +{ + static char *topdir; + + if (!topdir) { + topdir = getenv("ALSA_CONFIG_DIR"); + if (!topdir || *topdir != '/' || strlen(topdir) >= PATH_MAX) + topdir = ALSA_CONFIG_DIR; + } + return topdir; +} + +static char *_snd_config_path(const char *name) +{ + const char *root = snd_config_topdir(); + char *path = malloc(strlen(root) + strlen(name) + 2); + if (!path) + return NULL; + sprintf(path, "%s/%s", root, name); + return path; +} + +/* + * Search and open a file, and creates a new input object reading from the file. + * param inputp - The functions puts the pointer to the new input object + * at the address specified by \p inputp. + * param file - Name of the configuration file. + * param include_paths - Optional, addtional directories to search the file. + * return - Zero if successful, otherwise a negative error code. + * + * This function will search and open the file in the following order + * of priority: + * 1. directly open the file by its name (only if absolute) + * 2. search for the file name in in additional configuration directories + * specified by users, via alsaconf syntax + * ; + * These directories should be subdirectories of /usr/share/alsa. + */ +static int input_stdio_open(snd_input_t **inputp, const char *file, + struct filedesc *current) +{ + struct list_head *pos; + struct include_path *path; + char full_path[PATH_MAX]; + int err; + + if (file[0] == '/') + return snd_input_stdio_open(inputp, file, "r"); + + /* search file in user specified include paths. These directories + * are subdirectories of /usr/share/alsa. + */ + err = -ENOENT; + while (current) { + list_for_each(pos, ¤t->include_paths) { + path = list_entry(pos, struct include_path, list); + if (!path->dir) + continue; + + snprintf(full_path, PATH_MAX, "%s/%s", path->dir, file); + err = snd_input_stdio_open(inputp, full_path, "r"); + if (err == 0) + return 0; + } + current = current->next; + } + + return err; +} + +static int safe_strtoll(const char *str, long long *val) +{ + long long v; + int endidx; + if (!*str) + return -EINVAL; + errno = 0; + if (sscanf(str, "%lli%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; + DIR *dirp; + int err = get_delimstring(&str, '>', input); + if (err < 0) + return err; + + if (!strncmp(str, "searchdir:", 10)) { + /* directory to search included files */ + char *tmp = _snd_config_path(str + 10); + free(str); + if (tmp == NULL) + return -ENOMEM; + str = tmp; + + dirp = opendir(str); + if (!dirp) { + SNDERR("Invalid search dir %s", str); + free(str); + return -EINVAL; + } + closedir(dirp); + + err = add_include_path(input->current, str); + free(str); + if (err < 0) { + SNDERR("Cannot add search dir %s", str); + return err; + } + continue; + } + + if (!strncmp(str, "confdir:", 8)) { + /* file in the specified directory */ + char *tmp = _snd_config_path(str + 8); + free(str); + if (tmp == NULL) + return -ENOMEM; + str = tmp; + err = snd_input_stdio_open(&in, str, "r"); + } else { /* absolute or relative file path */ + err = input_stdio_open(&in, str, input->current); + } + + 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; + INIT_LIST_HEAD(&fd->include_paths); + 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': case '1': case '2': case '3': + case '4': case '5': case '6': case '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; + /* fall through */ + 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': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': + goto quoted; + } + } + loop: + switch (*p) { + case 0: + goto nonquoted; + case ' ': + case '=': + case ';': + case ',': + case '.': + case '{': + case '}': + case '\'': + case '"': + goto quoted; + default: + if (*p <= 31 || *p >= 127) + goto quoted; + 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; + default: + if (c >= 32 && c <= 126 && c != '\'') + snd_output_putc(out, c); + else + 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, "%lld", 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); +} + +#ifndef DOC_HIDDEN +int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in, + int override, const char * const *include_paths) +{ + 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; + INIT_LIST_HEAD(&fd->include_paths); + if (include_paths) { + for (; *include_paths; include_paths++) { + err = add_include_path(fd, *include_paths); + if (err < 0) + goto _end; + } + } else { + err = add_include_path(fd, snd_config_topdir()); + if (err < 0) + goto _end; + } + 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_include_paths(fd); + free(fd); + fd = fd_next; + } + + free_include_paths(fd); + free(fd); + return err; +} +#endif + +/** + * \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_load_with_include(config, in, 0, NULL); +} + +/** + * \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_load_with_include(config, in, 1, NULL); +} + +/** + * \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 Adds a child after another child configuration node. + * \param after Handle to the start 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 parent of + * the node \a after. + * + * 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. + *
+ */ +int snd_config_add_after(snd_config_t *after, snd_config_t *child) +{ + snd_config_iterator_t i, next; + snd_config_t *parent; + assert(after && child); + parent = after->parent; + assert(parent); + 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_insert(&child->list, &after->list, after->list.next); + return 0; +} + +/** + * \brief Adds a child before another child configuration node. + * \param before Handle to the start 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 parent of + * the node \a before. + * + * 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. + *
+ */ +int snd_config_add_before(snd_config_t *before, snd_config_t *child) +{ + snd_config_iterator_t i, next; + snd_config_t *parent; + assert(before && child); + parent = before->parent; + assert(parent); + 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_insert(&child->list, before->list.prev, &before->list); + 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. + * + * The function is supposed to be called only for locally copied config + * trees. For the global tree, take the reference via #snd_config_update_ref + * and free it via #snd_config_unref. + * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_config_remove + */ +int snd_config_delete(snd_config_t *config) +{ + assert(config); + if (config->refcount > 0) { + config->refcount--; + return 0; + } + 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; +} + +int snd_config_imake_safe_string(snd_config_t **config, const char *id, const char *value) +{ + int err; + snd_config_t *tmp; + char *c; + + 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; + } + + for (c = tmp->u.string; *c; c++) { + if (*c == ' ' || *c == '-' || *c == '_' || + (*c >= '0' && *c <= '9') || + (*c >= 'a' && *c <= 'z') || + (*c >= 'A' && *c <= 'Z')) + continue; + *c = '_'; + } + } 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), "%lli", 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) { \ + va_end(arg); \ + 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) { \ + va_end(arg); \ + 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" + +/** + * \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, errbuf[256]; + 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); + err = -EINVAL; + 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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", lib, errbuf); + 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; +} + +static int config_filename_filter(const struct dirent *dirent) +{ + size_t flen; + + if (dirent == NULL) + return 0; + if (dirent->d_type == DT_DIR) + return 0; + + flen = strlen(dirent->d_name); + if (flen <= 5) + return 0; + + if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0) + return 1; + + return 0; +} + +static int config_file_open(snd_config_t *root, const char *filename) +{ + snd_input_t *in; + int err; + + err = snd_input_stdio_open(&in, filename, "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", filename); + } else + SNDERR("cannot access file %s", filename); + + 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++) { + struct stat st; + if (!errors && access(fi[idx].name, R_OK) < 0) + continue; + if (stat(fi[idx].name, &st) < 0) { + SNDERR("cannot stat file/directory %s", fi[idx].name); + continue; + } + if (S_ISDIR(st.st_mode)) { + struct dirent **namelist; + int n; + +#ifndef DOC_HIDDEN +#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID) +#define SORTFUNC versionsort +#else +#define SORTFUNC alphasort +#endif +#endif + n = scandir(fi[idx].name, &namelist, config_filename_filter, SORTFUNC); + if (n > 0) { + int j; + err = 0; + for (j = 0; j < n; ++j) { + if (err >= 0) { + int sl = strlen(fi[idx].name) + strlen(namelist[j]->d_name) + 2; + char *filename = malloc(sl); + snprintf(filename, sl, "%s/%s", fi[idx].name, namelist[j]->d_name); + filename[sl-1] = '\0'; + + err = config_file_open(root, filename); + free(filename); + } + free(namelist[j]); + } + free(namelist); + if (err < 0) + goto _err; + } + } else if ((err = config_file_open(root, fi[idx].name)) < 0) + goto _err; + } + *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) { + const char *topdir = snd_config_topdir(); + char *s = alloca(strlen(topdir) + + strlen("alsa.conf") + 2); + sprintf(s, "%s/alsa.conf", topdir); + configs = s; + } + } + 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. + * For safer operations, use #snd_config_update_ref and release the config + * via #snd_config_unref. + * + * \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 Updates #snd_config and takes its reference. + * \return 0 if #snd_config was up to date, 1 if #snd_config was + * updated, otherwise a negative error code. + * + * Unlike #snd_config_update, this function increases a reference counter + * so that the obtained tree won't be deleted until unreferenced by + * #snd_config_unref. + * + * This function is supposed to be thread-safe. + */ +int snd_config_update_ref(snd_config_t **top) +{ + int err; + + if (top) + *top = NULL; + snd_config_lock(); + err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL); + if (err >= 0) { + if (snd_config) { + if (top) { + snd_config->refcount++; + *top = snd_config; + } + } else { + err = -ENODEV; + } + } + snd_config_unlock(); + return err; +} + +/** + * \brief Take the reference of the config tree. + * + * Increases a reference counter of the given config tree. + * + * This function is supposed to be thread-safe. + */ +void snd_config_ref(snd_config_t *cfg) +{ + snd_config_lock(); + if (cfg) + cfg->refcount++; + snd_config_unlock(); +} + +/** + * \brief Unreference the config tree. + * + * Decreases a reference counter of the given config tree, and eventually + * deletes the tree if all references are gone. This is the counterpart of + * #snd_config_unref. + * + * Also, the config taken via #snd_config_update_ref must be unreferenced + * by this function, too. + * + * This function is supposed to be thread-safe. + */ +void snd_config_unref(snd_config_t *cfg) +{ + snd_config_lock(); + if (cfg) + snd_config_delete(cfg); + snd_config_unlock(); +} + +/** + * \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, errbuf[256]; + 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); + err = -EINVAL; + 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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", lib, errbuf); + 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': case '1': case '2': case '3': + case '4': case '5': case '6': case '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) { + if (alloc > bufsize) + free(buf); + 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); + if (!buf) + return -ENOMEM; + memcpy(buf, _buf, old_alloc); + } else { + char *buf2 = realloc(buf, alloc); + if (!buf2) { + free(buf); + return -ENOMEM; + } + buf = buf2; + } + } + 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 + +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; +} diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am new file mode 100644 index 0000000..b82591a --- /dev/null +++ b/src/conf/Makefile.am @@ -0,0 +1,17 @@ +SUBDIRS=cards pcm + +cfg_files = alsa.conf +if BUILD_ALISP +cfg_files += sndo-mixer.alisp +endif +if BUILD_MODULES +if BUILD_MIXER_MODULES +cfg_files += smixer.conf +endif +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..c68c06f --- /dev/null +++ b/src/conf/Makefile.in @@ -0,0 +1,696 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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_MIXER_MODULES_TRUE@@BUILD_MODULES_TRUE@am__append_2 = smixer.conf +subdir = src/conf +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +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_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(alsadir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(alsadir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(alsadir)'; $(am__uninstall_files_from_dir) + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am 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-am uninstall \ + uninstall-alsaDATA uninstall-am + +.PRECIOUS: Makefile + + +# 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..0998058 --- /dev/null +++ b/src/conf/alsa.conf @@ -0,0 +1,629 @@ +# +# ALSA library configuration file +# + +# pre-load the configuration files + +@hooks [ + { + func load + files [ + "/etc/alsa/conf.d" + "/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.channels 2 +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.surround21.card defaults.pcm.card +defaults.pcm.surround21.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.sysdefault 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.surround21 cards.pcm.surround21 +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.sysdefault { + type hw + card { + @func getenv + vars [ + ALSA_CTL_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.ctl.card + } + } + hint.description "Default control device" +} +ctl.default ctl.sysdefault + +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 + hint.description "Direct control device" +} + +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 + } + } + hint.description "Default raw MIDI 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 + hint.description "Default sequencer device" +} + +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 + } + } + hint.description "Default hardware dependent 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 + hint { + description "Direct hardware dependent device" + 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 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 + hint { + description "Direct timer device" + device $DEV + } +} 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..42540d6 --- /dev/null +++ b/src/conf/cards/ATIIXP-SPDMA.conf @@ -0,0 +1,166 @@ +# +# 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..c4d33ef --- /dev/null +++ b/src/conf/cards/ATIIXP.conf @@ -0,0 +1,185 @@ +# +# 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..1c92496 --- /dev/null +++ b/src/conf/cards/Audigy.conf @@ -0,0 +1,322 @@ +# +# Configuration for the Audigy chip +# + + + +Audigy.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "FL,FR" ] + } + 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 + chmap [ "UNKNOWN" "RL,RR" ] + } + 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 + chmap [ "UNKNOWN" "FC,LFE" ] + } + 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..cbec783 --- /dev/null +++ b/src/conf/cards/Audigy2.conf @@ -0,0 +1,430 @@ +# +# Configuration for the Audigy2 chip +# + + + +Audigy2.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "FL,FR" ] + } + 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 + chmap [ "UNKNOWN" "RL,RR" ] + } + 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 + chmap [ "UNKNOWN" "FC,LFE" ] + } + 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 + chmap [ "UNKNOWN" "SL,SR" ] + } + 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..07be4a7 --- /dev/null +++ b/src/conf/cards/Aureon51.conf @@ -0,0 +1,180 @@ +# +# 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..a43ce2c --- /dev/null +++ b/src/conf/cards/Aureon71.conf @@ -0,0 +1,191 @@ +# +# 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..2f0eaf0 --- /dev/null +++ b/src/conf/cards/CA0106.conf @@ -0,0 +1,281 @@ +# +# 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..edc67d4 --- /dev/null +++ b/src/conf/cards/CMI8738-MC6.conf @@ -0,0 +1,162 @@ +# +# 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..ddff753 --- /dev/null +++ b/src/conf/cards/CMI8738-MC8.conf @@ -0,0 +1,231 @@ +# +# 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..edcb0c9 --- /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..b71c30a --- /dev/null +++ b/src/conf/cards/CS46xx.conf @@ -0,0 +1,219 @@ +# +# 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..ef193fe --- /dev/null +++ b/src/conf/cards/EMU10K1.conf @@ -0,0 +1,329 @@ +# +# Configuration for the EMU10K1 chip +# + + + +EMU10K1.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "FL,FR" ] + } + 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 ] + } + ] + } + } + capture.pcm { + type hw + card $CARD + } +} + + + +EMU10K1.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "RL,RR" ] + } + 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 asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "FC,LFE" ] + } + hooks.0 { + type ctl_elems + hook_args [ + { + name "Headphone Center Playback Switch" + index 1 + preserve true + # lock true + optional true + value true + } + { + name "Headphone LFE Playback Switch" + index 1 + preserve true + # lock true + optional 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..f742863 --- /dev/null +++ b/src/conf/cards/EMU10K1X.conf @@ -0,0 +1,202 @@ +# +# 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/Echo_Echo3G.conf b/src/conf/cards/Echo_Echo3G.conf new file mode 100644 index 0000000..766f13f --- /dev/null +++ b/src/conf/cards/Echo_Echo3G.conf @@ -0,0 +1,318 @@ +# +# Configuration for the Echo3G driver +# + + +Echo_Echo3G.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 0 + subdevice 0 +} + + +Echo_Echo3G.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 0 + subdevice 4 +} + + +Echo_Echo3G.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 0 + subdevice 2 +} + + +Echo_Echo3G.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 0 + subdevice 6 +} + + +Echo_Echo3G.pcm.surround40.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] +} + + +Echo_Echo3G.pcm.surround41.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.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 } + ] +} + + +Echo_Echo3G.pcm.surround50.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.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 1 } + ] +} + + +Echo_Echo3G.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.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 } + ] +} + + +Echo_Echo3G.pcm.surround71.0 { + @args [ CARD ] + @args.CARD { + type string + } + type multi + slaves [ + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.front.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.rear.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.pcm.center_lfe.0:CARD=" $CARD + ] + } + channels 2 + } + { + pcm { + @func concat + strings [ + "cards.Echo_Echo3G.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 } + ] +} + + +Echo_Echo3G.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 Default" + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/FM801.conf b/src/conf/cards/FM801.conf new file mode 100644 index 0000000..0ddf799 --- /dev/null +++ b/src/conf/cards/FM801.conf @@ -0,0 +1,88 @@ +# +# 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/FWSpeakers.conf b/src/conf/cards/FWSpeakers.conf new file mode 100644 index 0000000..cd6fa60 --- /dev/null +++ b/src/conf/cards/FWSpeakers.conf @@ -0,0 +1,26 @@ +# +# Configuration for the LaCie Firewire speakers +# + +FWSpeakers.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32" ] + } +} + + + +FWSpeakers.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} diff --git a/src/conf/cards/FireWave.conf b/src/conf/cards/FireWave.conf new file mode 100644 index 0000000..fcfc83c --- /dev/null +++ b/src/conf/cards/FireWave.conf @@ -0,0 +1,51 @@ +# +# Configuration for the Griffin FireWave Surround +# + +FireWave.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32" ] + } +} + + + +FireWave.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + + + + + + +FireWave.pcm.surround51.0 { + @args [ CARD ] + @args.CARD { + type string + } + type route + ttable [ + [ 1 0 0 0 0 0 ] + [ 0 1 0 0 0 0 ] + [ 0 0 0 0 1 0 ] + [ 0 0 0 0 0 1 ] + [ 0 0 1 0 0 0 ] + [ 0 0 0 1 0 0 ] + ] + slave.pcm { + type hw + card $CARD + } +} 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..fa9f694 --- /dev/null +++ b/src/conf/cards/HDA-Intel.conf @@ -0,0 +1,412 @@ +# +# Configuration for the Intel HD audio (ICH6/ICH7) +# + + + +HDA-Intel.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type softvol + slave.pcm { + type hw + card $CARD + subdevice 0 + } + control { + name "PCM Playback Volume" + card $CARD + } + } + capture.pcm { + type hw + 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" + index 16 + optional true + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + { + name "IEC958 Playback Switch" + index 16 + optional true + value true + # if this element is present, skip the rest + skip_rest true + } + { + 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.hdmi.4 { + @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=10," + "CTLINDEX=4," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + +HDA-Intel.pcm.hdmi.5 { + @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=11," + "CTLINDEX=5," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + +HDA-Intel.pcm.hdmi.6 { + @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=12," + "CTLINDEX=6," + "AES0=" $AES0 "," + "AES1=" $AES1 "," + "AES2=" $AES2 "," + "AES3=" $AES3 + ] + } +} + +HDA-Intel.pcm.hdmi.7 { + @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=13," + "CTLINDEX=7," + "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/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf new file mode 100644 index 0000000..a1e493d --- /dev/null +++ b/src/conf/cards/HdmiLpeAudio.conf @@ -0,0 +1,118 @@ +# +# Configuration for the Intel HDMI/DP LPE audio +# + + + +HdmiLpeAudio.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 + } + type hooks + slave.pcm { + type hw + card $CARD + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + device 0 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} + +HdmiLpeAudio.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 + } + type hooks + slave.pcm { + type hw + card $CARD + device 1 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback Default" + device 1 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} + +HdmiLpeAudio.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 + } + 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 + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } +} diff --git a/src/conf/cards/ICE1712.conf b/src/conf/cards/ICE1712.conf new file mode 100644 index 0000000..db62684 --- /dev/null +++ b/src/conf/cards/ICE1712.conf @@ -0,0 +1,180 @@ +# +# 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 asym + playback.pcm { + type route + ttable.0.0 1 + ttable.1.1 1 + slave.pcm { + type hw + card $CARD + } + slave.channels 10 + } + capture.pcm { + type route + ttable.0.0 1 + ttable.1.1 1 + slave.pcm { + type hw + card $CARD + } + slave.channels 12 + } +} + + + +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 + } + slave.channels 10 +} + + + + + + + +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 + } + slave.channels 10 +} + +ICE1712.pcm.surround71.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 + ttable.6.6 1 + ttable.7.7 1 + slave.pcm { + type hw + card $CARD + } + slave.channels 10 +} + + + +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..61cac01 --- /dev/null +++ b/src/conf/cards/ICE1724.conf @@ -0,0 +1,225 @@ +# +# 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..6fc9a5a --- /dev/null +++ b/src/conf/cards/ICH.conf @@ -0,0 +1,223 @@ +# +# 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..64ec883 --- /dev/null +++ b/src/conf/cards/ICH4.conf @@ -0,0 +1,214 @@ +# +# 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/Loopback.conf b/src/conf/cards/Loopback.conf new file mode 100644 index 0000000..1ae6d45 --- /dev/null +++ b/src/conf/cards/Loopback.conf @@ -0,0 +1,75 @@ +# +# Configuration for the virtual loopback driver (snd-aloop) +# + + + +Loopback.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 +Loopback.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 +} + + + + + + + + +Loopback.pcm.surround40.0 cards.Loopback.pcm.front.0 +Loopback.pcm.surround51.0 cards.Loopback.pcm.front.0 +Loopback.pcm.surround71.0 cards.Loopback.pcm.front.0 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..00999f0 --- /dev/null +++ b/src/conf/cards/Makefile.am @@ -0,0 +1,81 @@ +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 \ + Echo_Echo3G.conf \ + EMU10K1.conf \ + EMU10K1X.conf \ + ENS1370.conf \ + ENS1371.conf \ + ES1968.conf \ + FM801.conf \ + FWSpeakers.conf \ + FireWave.conf \ + GUS.conf \ + HDA-Intel.conf \ + HdmiLpeAudio.conf \ + ICE1712.conf \ + ICE1724.conf \ + ICH.conf \ + ICH4.conf \ + ICH-MODEM.conf \ + Loopback.conf \ + Maestro3.conf \ + NFORCE.conf \ + PC-Speaker.conf \ + pistachio-card.conf \ + PMac.conf \ + PMacToonie.conf \ + PS3.conf \ + RME9636.conf \ + RME9652.conf \ + SI7018.conf \ + SB-XFi.conf \ + TRID4DWAVENX.conf \ + USB-Audio.conf \ + YMF744.conf \ + vc4-hdmi.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..e8cef25 --- /dev/null +++ b/src/conf/cards/Makefile.in @@ -0,0 +1,559 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(SI7018dir)" "$(DESTDIR)$(alsadir)" +DATA = $(SI7018_DATA) $(alsa_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 Echo_Echo3G.conf \ + EMU10K1.conf EMU10K1X.conf ENS1370.conf ENS1371.conf \ + ES1968.conf FM801.conf FWSpeakers.conf FireWave.conf GUS.conf \ + HDA-Intel.conf HdmiLpeAudio.conf ICE1712.conf ICE1724.conf \ + ICH.conf ICH4.conf ICH-MODEM.conf Loopback.conf Maestro3.conf \ + NFORCE.conf PC-Speaker.conf pistachio-card.conf PMac.conf \ + PMacToonie.conf PS3.conf RME9636.conf RME9652.conf SI7018.conf \ + SB-XFi.conf TRID4DWAVENX.conf USB-Audio.conf YMF744.conf \ + vc4-hdmi.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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) + @list='$(SI7018_DATA)'; test -n "$(SI7018dir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(SI7018dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(SI7018dir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(SI7018dir)'; $(am__uninstall_files_from_dir) +install-alsaDATA: $(alsa_DATA) + @$(NORMAL_INSTALL) + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(alsadir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(alsadir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(alsadir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 -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 \ + cscopelist-am ctags-am 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 tags-am uninstall \ + uninstall-SI7018DATA uninstall-alsaDATA uninstall-am + +.PRECIOUS: Makefile + + +# 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..64d1547 --- /dev/null +++ b/src/conf/cards/NFORCE.conf @@ -0,0 +1,296 @@ +# +# 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..eb2218b --- /dev/null +++ b/src/conf/cards/SB-XFi.conf @@ -0,0 +1,109 @@ +# +# 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..02b8fc8 --- /dev/null +++ b/src/conf/cards/SI7018.conf @@ -0,0 +1,169 @@ +# +# 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 + chmap [ "UNKNOWN" "FL,FR" ] +} + + + +SI7018.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "RL,RR" ] + } + 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/TRID4DWAVENX.conf b/src/conf/cards/TRID4DWAVENX.conf new file mode 100644 index 0000000..717b140 --- /dev/null +++ b/src/conf/cards/TRID4DWAVENX.conf @@ -0,0 +1,131 @@ +# +# Configuration for the Trident 4D-Wave NX chip +# + + + +TRID4DWAVENX.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + chmap [ "UNKNOWN" "FL,FR" ] +} + + + +TRID4DWAVENX.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hooks + slave.pcm { + type hw + card $CARD + chmap [ "UNKNOWN" "RL,RR" ] + } + 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..1c67793 --- /dev/null +++ b/src/conf/cards/USB-Audio.conf @@ -0,0 +1,489 @@ +# +# 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 + "USB AudioSport Quattro (tm)" two_stereo_devices +} + +# 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 + "USB Sound Blaster HD" 1 + "Xonar U7" 1 + + # The below don't have digital in/out, so prevent them from being opened. + "Andrea PureAudio USB-SA Headset" 999 + "Blue Snowball" 999 + "HP Digital Stereo Headset" 999 + "GN 9330" 999 + "Logitech Speaker Lapdesk N700" 999 + "Logitech G35 Headset" 999 + "Logitech USB Headset" 999 + "Logitech USB Headset H540" 999 + "Logitech Wireless Headset" 999 + "Plantronics GameCom 780" 999 + "Plantronics USB Headset" 999 + "Plantronics Wireless Audio" 999 + "SB WoW Headset" 999 + "Scarlett 2i2 USB" 999 + "Scarlett 2i4 USB" 999 + "Sennheiser USB headset" 999 + "SWTOR Gaming Headset by Razer" 999 + "USB Device 0x46d_0x821" 999 + "USB Device 0x46d_0x992" 999 + "WD15 Dock" 999 + "WD19 Dock" 999 +} + +# Second iec958 device number, if any. +USB-Audio.pcm.iec958_2_device { + "PHIREE U2" 1 # 0 = PCM S/PDIF, 1 = non-PCM S/PDIF + "PHIREE U2SX" 1 # 0 = PCM S/PDIF, 1 = non-PCM S/PDIF +} + + +# If a device requires non-standard definitions for front, default, 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:DEV=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 + } +} + +# For this card we can (and must to get IEC61937) set AES bits +USB-Audio."MicroII".pcm.iec958 "cards.USB-Audio.Audio Advantage MicroII.pcm.iec958" +USB-Audio."Audio Advantage MicroII".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 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 ] + } + { + name "IEC958 Playback Switch" + lock true + preserve true + value 1 + } + ] + } +} + +################################################################################ + + + +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 } + @func refer + name { + @func concat + strings [ + "cards.USB-Audio." + { @func card_name card $CARD } + ".pcm.default:CARD=" $CARD + ] + } + default { + 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 + } + } +} + +USB-Audio.pcm.iec958.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.USB-Audio." + { @func card_name card $CARD } + ".pcm.iec958_2: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_2_device." + { @func card_name card $CARD } + ] + } + default 999 + } + } +} + +# 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..9ad321f --- /dev/null +++ b/src/conf/cards/VIA8233.conf @@ -0,0 +1,201 @@ +# +# 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..679fccf --- /dev/null +++ b/src/conf/cards/VIA8233A.conf @@ -0,0 +1,205 @@ +# +# 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..29d8e00 --- /dev/null +++ b/src/conf/cards/VIA8237.conf @@ -0,0 +1,191 @@ +# +# 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.conf b/src/conf/cards/aliases.conf new file mode 100644 index 0000000..18a920f --- /dev/null +++ b/src/conf/cards/aliases.conf @@ -0,0 +1,63 @@ +# +# 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 +pistachio cards.pistachio-card +VC4-HDMI cards.vc4-hdmi + + + + diff --git a/src/conf/cards/pistachio-card.conf b/src/conf/cards/pistachio-card.conf new file mode 100644 index 0000000..59cd920 --- /dev/null +++ b/src/conf/cards/pistachio-card.conf @@ -0,0 +1,58 @@ +# +# Configuration for the pistachio chip. +# +# The data sheet of the chip and technical reference manual can be +found at +https://docs.creatordev.io/ci40/guides/hardwaredocs/cXT200_datasheet2.p +df # and +https://docs.creatordev.io/ci40/guides/hardwaredocs/MIPS_Creator_cXT200_Technical_Reference_Manual_1.0.112.pdf. +# +# The list of hardware devices is as per below: +# +# root@OpenWrt:/# arecord -l +# **** List of CAPTURE Hardware Devices **** card 0: pistachiocard [pistachio-card], device 1: pistachio-spdif-in snd-soc-dummy-dai-1 [] +# Subdevices: 1/1 +# Subdevice #0: subdevice #0 +# card 0: pistachiocard [pistachio-card], device 4: pistachio-i2s-in-0 snd-soc-dummy-dai-4 [] +# Subdevices: 1/1 +# Subdevice #0: subdevice #0 +# +# root@OpenWrt:/# aplay -l +# **** List of PLAYBACK Hardware Devices **** card 0: pistachiocard [pistachio-card], device 0: pistachio-spdif-out snd-soc-dummy-dai-0 [] +# Subdevices: 1/1 +# Subdevice #0: subdevice #0 +# card 0: pistachiocard [pistachio-card], device 2: pistachio-parallel-out pistachio_internal_dac-2 [] +# Subdevices: 1/1 +# Subdevice #0: subdevice #0 +# card 0: pistachiocard [pistachio-card], device 3: pistachio-i2s-out snd-soc-dummy-dai-3 [] +# Subdevices: 1/1 +# Subdevice #0: subdevice #0 +# + +pistachio-card.pcm.default{ + @args [ CARD ] + @args.CARD { + type string + default "pistachio" + } + @args.DEVICE { + type integer + default 2 + } + + type asym + capture.pcm { + type multi + slaves.a.pcm "hw:0,4" + slaves.a.channels 12 + bindings.0.slave a + bindings.0.channel 4 + bindings.1.slave a + bindings.1.channel 5 + } + + playback.pcm { + type hw + card $CARD + device $DEVICE + diff --git a/src/conf/cards/vc4-hdmi.conf b/src/conf/cards/vc4-hdmi.conf new file mode 100644 index 0000000..027804a --- /dev/null +++ b/src/conf/cards/vc4-hdmi.conf @@ -0,0 +1,64 @@ +# +# Configuration for the VC4-HDMI sound card using software IEC958 +# subframe conversion +# + + + +vc4-hdmi.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD +} + +# default with dmix +vc4-hdmi.pcm.default { + @args [ CARD ] + @args.CARD { + type string + } + type asym + playback.pcm { + type plug + slave.pcm { + @func concat + strings [ "dmix:" $CARD ] + } + } +} + + + +vc4-hdmi.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 { + format IEC958_SUBFRAME_LE + pcm { + type plug + slave.pcm { + type hw + card $CARD + } + } + } + status [ $AES0 $AES1 $AES2 $AES3 ] +} diff --git a/src/conf/pcm/Makefile.am b/src/conf/pcm/Makefile.am new file mode 100644 index 0000000..c548660 --- /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\ + surround21.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..0cfaa40 --- /dev/null +++ b/src/conf/pcm/Makefile.in @@ -0,0 +1,519 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(alsadir)" +DATA = $(alsa_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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\ + surround21.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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) + @list='$(alsa_DATA)'; test -n "$(alsadir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(alsadir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(alsadir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(alsadir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 -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 \ + cscopelist-am ctags-am 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 tags-am uninstall \ + uninstall-alsaDATA uninstall-am + +.PRECIOUS: Makefile + + +# 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..7fa5c8b --- /dev/null +++ b/src/conf/pcm/dmix.conf @@ -0,0 +1,123 @@ +# +# dmix output +# + +pcm.!dmix { + @args [ CARD DEV SUBDEV FORMAT RATE CHANNELS ] + @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 + } + } + @args.CHANNELS { + type integer + default { + @func refer + name defaults.pcm.dmix.channels + } + } + 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 + channels $CHANNELS + 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_output $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..abbd44f --- /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_input $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/surround21.conf b/src/conf/pcm/surround21.conf new file mode 100644 index 0000000..1cf1b7a --- /dev/null +++ b/src/conf/pcm/surround21.conf @@ -0,0 +1,61 @@ +# +# Hardware output from 2.1 speakers. +# Samples must be positioned: +# chn0 - front left +# chn1 - front right +# chn2 - LFE +# + +pcm.!surround21 { + @args [ CARD DEV ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_SURROUND21_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.pcm.surround21.card + } + } + } + @args.DEV { + type integer + default { + @func igetenv + vars [ + ALSA_SURROUND21_DEVICE + ] + default { + @func refer + name defaults.pcm.surround21.device + } + } + } + type route + slave.pcm { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".pcm.surround51." $DEV ":CARD=" $CARD + ] + } + } + ttable.0.FL 1 + ttable.1.FR 1 + ttable.2.LFE 1 + hint { + description "2.1 Surround output to Front and Subwoofer speakers" + device_output $DEV + } +} diff --git a/src/conf/pcm/surround40.conf b/src/conf/pcm/surround40.conf new file mode 100644 index 0000000..9788ad4 --- /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_output $DEV + } +} diff --git a/src/conf/pcm/surround41.conf b/src/conf/pcm/surround41.conf new file mode 100644 index 0000000..7b4ef3b --- /dev/null +++ b/src/conf/pcm/surround41.conf @@ -0,0 +1,65 @@ +# +# 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 + ] + } + } + ttable.0.FL 1 + ttable.1.FR 1 + ttable.2.RL 1 + ttable.3.RR 1 + ttable.4.LFE 1 + hint { + description "4.1 Surround output to Front, Rear and Subwoofer speakers" + device_output $DEV + } +} diff --git a/src/conf/pcm/surround50.conf b/src/conf/pcm/surround50.conf new file mode 100644 index 0000000..7d9a9e7 --- /dev/null +++ b/src/conf/pcm/surround50.conf @@ -0,0 +1,65 @@ +# +# 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 + ] + } + } + ttable.0.FL 1 + ttable.1.FR 1 + ttable.2.RL 1 + ttable.3.RR 1 + ttable.4.FC 1 + hint { + description "5.0 Surround output to Front, Center and Rear speakers" + device_output $DEV + } +} diff --git a/src/conf/pcm/surround51.conf b/src/conf/pcm/surround51.conf new file mode 100644 index 0000000..e67f007 --- /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_output $DEV + } +} diff --git a/src/conf/pcm/surround71.conf b/src/conf/pcm/surround71.conf new file mode 100644 index 0000000..a26c3f3 --- /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 +# chn6 - side left +# chn7 - 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_output $DEV + } +} diff --git a/src/confmisc.c b/src/confmisc.c new file mode 100644 index 0000000..eb8218c --- /dev/null +++ b/src/confmisc.c @@ -0,0 +1,1312 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, snd_config_topdir()); +} +#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 = {0}; + char *res = NULL; + int err; + + assert(card >= 0 && card <= SND_MAX_CARDS); + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %i", card); + goto __error; + } + 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 = {0}; + 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; + } + 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 = {0}; + 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; + } + 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_safe_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 = {0}; + 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_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 = {0}; + 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; + } + + 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; + 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 = {0}; + 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; + } + 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 + +#ifndef DOC_HIDDEN +int _snd_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; +} +#endif diff --git a/src/control/Makefile.am b/src/control/Makefile.am new file mode 100644 index 0000000..3d476a2 --- /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 + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/control/Makefile.in b/src/control/Makefile.in new file mode 100644 index 0000000..7084edb --- /dev/null +++ b/src/control/Makefile.in @@ -0,0 +1,647 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/cards.Plo ./$(DEPDIR)/control.Plo \ + ./$(DEPDIR)/control_ext.Plo ./$(DEPDIR)/control_hw.Plo \ + ./$(DEPDIR)/control_shm.Plo ./$(DEPDIR)/control_symbols.Plo \ + ./$(DEPDIR)/ctlparse.Plo ./$(DEPDIR)/hcontrol.Plo \ + ./$(DEPDIR)/namehint.Plo ./$(DEPDIR)/setup.Plo \ + ./$(DEPDIR)/tlv.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libcontrol_la_SOURCES) +DIST_SOURCES = $(am__libcontrol_la_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libcontrol.la: $(libcontrol_la_OBJECTS) $(libcontrol_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_ext.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_shm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control_symbols.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctlparse.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hcontrol.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namehint.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setup.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlv.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/cards.Plo + -rm -f ./$(DEPDIR)/control.Plo + -rm -f ./$(DEPDIR)/control_ext.Plo + -rm -f ./$(DEPDIR)/control_hw.Plo + -rm -f ./$(DEPDIR)/control_shm.Plo + -rm -f ./$(DEPDIR)/control_symbols.Plo + -rm -f ./$(DEPDIR)/ctlparse.Plo + -rm -f ./$(DEPDIR)/hcontrol.Plo + -rm -f ./$(DEPDIR)/namehint.Plo + -rm -f ./$(DEPDIR)/setup.Plo + -rm -f ./$(DEPDIR)/tlv.Plo + -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 -f ./$(DEPDIR)/cards.Plo + -rm -f ./$(DEPDIR)/control.Plo + -rm -f ./$(DEPDIR)/control_ext.Plo + -rm -f ./$(DEPDIR)/control_hw.Plo + -rm -f ./$(DEPDIR)/control_shm.Plo + -rm -f ./$(DEPDIR)/control_symbols.Plo + -rm -f ./$(DEPDIR)/ctlparse.Plo + -rm -f ./$(DEPDIR)/hcontrol.Plo + -rm -f ./$(DEPDIR)/namehint.Plo + -rm -f ./$(DEPDIR)/setup.Plo + -rm -f ./$(DEPDIR)/tlv.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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..e57457c --- /dev/null +++ b/src/control/cards.c @@ -0,0 +1,222 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 < SND_MAX_CARDS; 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 >= SND_MAX_CARDS) + 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 < SND_MAX_CARDS; 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 + * + * The value returned in name is allocated with strdup and should be + * freed when no longer used. + */ +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 + * + * The value returned in name is allocated with strdup and should be + * freed when no longer used. + */ +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..3365015 --- /dev/null +++ b/src/control/control.c @@ -0,0 +1,3149 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 + +In ALSA control feature, each sound card can have control elements. The elements +are managed according to below model. + + - element set + - A set of elements with the same attribute (i.e. name, get/put operations). + Some element sets can be added to a sound card by drivers in kernel and + userspace applications. + - element + - An element can be identified by userspace applications. Each element has + own identical information. + - member + - An element includes some members to have a value. The value of each member + can be changed by both of userspace applications and drivers in kernel. + +Each element can be identified by two ways; a combination of name and index, or +numerical number (numid). + +The type of element set is one of integer, integerr64, boolean, enumerators, +bytes and IEC958 structure. This indicates the type of value for each member in +elements included in the element set. + +When the value of member is changed, corresponding events are transferred to +userspace applications. The applications should subscribe any events in advance. + +\section tlv_blob Supplemental data for elements in an element set + +TLV feature is designed to transfer data in a shape of Type/Length/Value, +between a driver and any userspace applications. The main purpose is to attach +supplement information for elements to an element set; e.g. dB range. + +At first, this feature was implemented to add pre-defined data readable to +userspace applications. Soon, it was extended to handle several operations; +read, write and command. The original implementation remains as the read +operation. The command operation allows drivers to have own implementations +against requests from userspace applications. + +This feature was introduced to ALSA control feature in 2006, at commit +c7a0708a2362, corresponding to a series of work for Linux kernel (42750b04c5ba +and 8aa9b586e420). + +There's no limitation about maximum size of the data, therefore it can be used +to deliver quite large arbitrary data from userspace to in-kernel drivers via +ALSA control character device. Focusing on this nature, as of 2016, some +in-kernel implementations utilize this feature for I/O operations. This is +against the original design. +*/ + +#include +#include +#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, 2 = abort + * \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, -1 = check subscribe or not + * \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); +} + +static bool validate_element_member_dimension(snd_ctl_elem_info_t *info) +{ + unsigned int members; + unsigned int i; + + if (info->dimen.d[0] == 0) + return true; + + members = 1; + for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) { + if (info->dimen.d[i] == 0) + break; + members *= info->dimen.d[i]; + + if (members > info->count) + return false; + } + + for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) { + if (info->dimen.d[i] > 0) + return false; + } + + return members == info->count; +} + +/** + * \brief Create and add some user-defined control elements of integer type. + * \param ctl A handle of backend module for control interface. + * \param info Common iformation for a new element set, with ID of the first new + * element. + * \param element_count The number of elements added by this operation. + * \param member_count The number of members which a element has to + * represent its states. + * \param min Minimum value for each member of the elements. + * \param max Maximum value for each member of the elements. + * \param step The step of value for each member in the elements. + * \return Zero on success, otherwise a negative error code. + * + * This function creates some user elements with integer type. These elements + * are not controlled by device drivers in kernel. They can be operated by the + * same way as usual elements added by the device drivers. + * + * The name field of \a id must be set with unique value to identify new control + * elements. After returning, all fields of \a id are filled. A element can be + * identified by the combination of name and index, or by numid. + * + * All of members in the new elements are locked. The value of each member is + * initialized with the minimum value. + * + * \par Errors: + *

+ *
-EBUSY + *
A element with ID \a id already exists. + *
-EINVAL + *
Some arguments include invalid value; i.e. ID field in \a info has no + * name, or the number of members is not between 1 to 127. + *
-ENOMEM + *
Out of memory, or there are too many user elements. + *
-ENXIO + *
This backend module does not support user elements of integer type. + *
-ENODEV + *
Device unplugged. + *
+ * + * \par Compatibility: + * This function is added in version 1.1.2. + */ +int snd_ctl_add_integer_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count, + long min, long max, long step) +{ + snd_ctl_elem_value_t data = {0}; + unsigned int i; + unsigned int j; + unsigned int numid; + int err; + + if (ctl == NULL || info == NULL || info->id.name[0] == '\0') + return -EINVAL; + + info->type = SND_CTL_ELEM_TYPE_INTEGER; + info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_USER; + info->owner = element_count; + info->count = member_count; + info->value.integer.min = min; + info->value.integer.max = max; + info->value.integer.step = step; + + if (!validate_element_member_dimension(info)) + return -EINVAL; + + err = ctl->ops->element_add(ctl, info); + if (err < 0) + return err; + numid = snd_ctl_elem_id_get_numid(&info->id); + + /* Set initial value to all of members in all of added elements. */ + data.id = info->id; + for (i = 0; i < element_count; i++) { + snd_ctl_elem_id_set_numid(&data.id, numid + i); + + for (j = 0; j < member_count; j++) + data.value.integer.value[j] = min; + + err = ctl->ops->element_write(ctl, &data); + if (err < 0) + return err; + } + + return 0; +} + +/** + * \brief Create and add some user-defined control elements of integer64 type. + * \param ctl A handle of backend module for control interface. + * \param info Common iformation for a new element set, with ID of the first new + * element. + * \param element_count The number of elements added by this operation. + * \param member_count The number of members which a element has to + * represent its states. + * \param min Minimum value for each member of the elements. + * \param max Maximum value for each member of the elements. + * \param step The step of value for each member in the elements. + * \return Zero on success, otherwise a negative error code. + * + * This function creates some user elements with integer64 type. These elements + * are not controlled by device drivers in kernel. They can be operated by the + * same way as usual elements added by the device drivers. + * + * The name field of \a id must be set with unique value to identify new control + * elements. After returning, all fields of \a id are filled. A element can be + * identified by the combination of name and index, or by numid. + * + * All of members in the new elements are locked. The value of each member is + * initialized with the minimum value. + * + * \par Errors: + *
+ *
-EBUSY + *
A element with ID \a id already exists. + *
-EINVAL + *
Some arguments include invalid value; i.e. ID has no name, or the number + * of members is not between 1 to 127. + *
-ENOMEM + *
Out of memory, or there are too many user elements. + *
-ENXIO + *
This backend module does not support user elements of integer64 type. + *
-ENODEV + *
Device unplugged. + *
+ * + * \par Compatibility: + * This function is added in version 1.1.2. + */ +int snd_ctl_add_integer64_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count, + long long min, long long max, long long step) +{ + snd_ctl_elem_value_t data = {0}; + unsigned int i; + unsigned int j; + unsigned int numid; + int err; + + if (ctl == NULL || info == NULL || info->id.name[0] == '\0') + return -EINVAL; + + info->type = SND_CTL_ELEM_TYPE_INTEGER64; + info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_USER; + info->owner = element_count; + info->count = member_count; + info->value.integer64.min = min; + info->value.integer64.max = max; + info->value.integer64.step = step; + + if (!validate_element_member_dimension(info)) + return -EINVAL; + + err = ctl->ops->element_add(ctl, info); + if (err < 0) + return err; + numid = snd_ctl_elem_id_get_numid(&info->id); + + /* Set initial value to all of members in all of added elements. */ + data.id = info->id; + for (i = 0; i < element_count; i++) { + snd_ctl_elem_id_set_numid(&data.id, numid + i); + + for (j = 0; j < member_count; j++) + data.value.integer64.value[j] = min; + + err = ctl->ops->element_write(ctl, &data); + if (err < 0) + return err; + } + + return 0; +} + +/** + * \brief Create and add some user-defined control elements of boolean type. + * \param ctl A handle of backend module for control interface. + * \param info Common iformation for a new element set, with ID of the first new + * element. + * \param element_count The number of elements added by this operation. + * \param member_count The number of members which a element has to + * represent its states. + * + * This function creates some user elements with boolean type. These elements + * are not controlled by device drivers in kernel. They can be operated by the + * same way as usual elements added by the device drivers. + * + * The name field of \a id must be set with unique value to identify new control + * elements. After returning, all fields of \a id are filled. A element can be + * identified by the combination of name and index, or by numid. + * + * All of members in the new elements are locked. The value of each member is + * initialized with false. + * + * \par Errors: + *
+ *
-EBUSY + *
A element with ID \a id already exists. + *
-EINVAL + *
Some parameters include invalid value; i.e. ID has no name, or the number + * of members is not between 1 to 127. + *
-ENOMEM + *
Out of memory, or there are too many user elements. + *
-ENXIO + *
This backend module does not support user elements of boolean type. + *
-ENODEV + *
Device unplugged. + *
+ * + * \par Compatibility: + * This function is added in version 1.1.2. + */ +int snd_ctl_add_boolean_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count) +{ + if (ctl == NULL || info == NULL || info->id.name[0] == '\0') + return -EINVAL; + + info->type = SND_CTL_ELEM_TYPE_BOOLEAN; + info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_USER; + info->owner = element_count; + info->count = member_count; + info->value.integer.min = 0; + info->value.integer.max = 1; + + if (!validate_element_member_dimension(info)) + return -EINVAL; + + return ctl->ops->element_add(ctl, info); +} + +/** + * \brief Create and add some user-defined control elements of enumerated type. + * \param ctl A handle of backend module for control interface. + * \param info Common iformation for a new element set, with ID of the first new + * element. + * \param element_count The number of elements added by this operation. + * \param member_count The number of members which a element has to + * represent its states. + * \param items Range of possible values (0 ... \a items - 1). + * \param labels An array containing \a items strings. + * \return Zero on success, otherwise a negative error code. + * + * This function creates some user elements with enumerated type. These elements + * are not controlled by device drivers in kernel. They can be operated by the + * same way as usual elements added by the device drivers. + * + * The name field of \a id must be set with unique value to identify new control + * elements. After returning, all fields of \a id are filled. A element can be + * identified by the combination of name and index, or by numid. + * + * All of members in the new elements are locked. The value of each member is + * initialized with the first entry of labels. + * + * \par Errors: + *
+ *
-EBUSY + *
A control element with ID \a id already exists. + *
-EINVAL + *
Some arguments include invalid value; i.e. \a element_count is not + * between 1 to 127, or \a items is not at least one, or a string in \a + * labels is empty, or longer than 63 bytes, or total length of the labels + * requires more than 64 KiB storage. + *
-ENOMEM + *
Out of memory, or there are too many user control elements. + *
-ENXIO + *
This driver does not support (enumerated) user controls. + *
-ENODEV + *
Device unplugged. + *
+ * + * \par Compatibility: + * This function is added in version 1.1.2. + */ +int snd_ctl_add_enumerated_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count, + unsigned int items, + const char *const labels[]) +{ + unsigned int i, bytes; + char *buf, *p; + int err; + + if (ctl == NULL || info == NULL || info->id.name[0] == '\0' || + labels == NULL) + return -EINVAL; + + info->type = SND_CTL_ELEM_TYPE_ENUMERATED; + info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_USER; + info->owner = element_count; + info->count = member_count; + info->value.enumerated.items = items; + + bytes = 0; + for (i = 0; i < items; ++i) + bytes += strlen(labels[i]) + 1; + if (bytes == 0) + return -EINVAL; + buf = malloc(bytes); + if (buf == NULL) + return -ENOMEM; + info->value.enumerated.names_ptr = (uintptr_t)buf; + info->value.enumerated.names_length = bytes; + p = buf; + for (i = 0; i < items; ++i) { + strcpy(p, labels[i]); + p += strlen(labels[i]) + 1; + } + + if (!validate_element_member_dimension(info)) + return -EINVAL; + + err = ctl->ops->element_add(ctl, info); + + free(buf); + + return err; +} + +/** + * \brief Create and add some user-defined control elements of bytes type. + * \param ctl A handle of backend module for control interface. + * \param info Common iformation for a new element set, with ID of the first new + * element. + * \param element_count The number of elements added by this operation. + * \param member_count The number of members which a element has to + * represent its states. + * \return Zero on success, otherwise a negative error code. + * + * This function creates some user elements with bytes type. These elements are + * not controlled by device drivers in kernel. They can be operated by the same + * way as usual elements added by the device drivers. + * + * The name field of \a id must be set with unique value to identify new control + * elements. After returning, all fields of \a id are filled. A element can be + * identified by the combination of name and index, or by numid. + * + * All of members in the new elements are locked. The value of each member is + * initialized with the minimum value. + * + * \par Errors: + *
+ *
-EBUSY + *
A element with ID \a id already exists. + *
-EINVAL + *
Some arguments include invalid value; i.e. ID has no name, or the number + * of members is not between 1 to 511. + *
-ENOMEM + *
Out of memory, or there are too many user elements. + *
-ENXIO + *
This backend module does not support user elements of bytes type. + *
-ENODEV + *
Device unplugged. + *
+ * + * \par Compatibility: + * This function is added in version 1.1.2. + */ +int snd_ctl_add_bytes_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, + unsigned int element_count, + unsigned int member_count) +{ + if (ctl == NULL || info == NULL || info->id.name[0] == '\0') + return -EINVAL; + + info->type = SND_CTL_ELEM_TYPE_BYTES; + info->access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_USER; + info->owner = element_count; + info->count = member_count; + + if (!validate_element_member_dimension(info)) + return -EINVAL; + + return ctl->ops->element_add(ctl, info); +} + +/** + * \brief Create and add an user-defined control element of integer type. + * + * This is a wrapper function to snd_ctl_add_integer_elem_set() for a control + * element. This doesn't fill the id data with full information, thus it's + * recommended to use snd_ctl_add_integer_elem_set(), instead. + */ +int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int member_count, + long min, long max, long step) +{ + snd_ctl_elem_info_t info = {0}; + + assert(ctl && id && id->name[0]); + + info.id = *id; + + return snd_ctl_add_integer_elem_set(ctl, &info, 1, member_count, + min, max, step); +} + +/** + * \brief Create and add an user-defined control element of integer64 type. + * + * This is a wrapper function to snd_ctl_add_integer64_elem_set() for a single + * control element. This doesn't fill the id data with full information, thus + * it's recommended to use snd_ctl_add_integer64_elem_set(), instead. + */ +int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int member_count, + long long min, long long max, long long step) +{ + snd_ctl_elem_info_t info = {0}; + + assert(ctl && id && id->name[0]); + + info.id = *id; + + return snd_ctl_add_integer64_elem_set(ctl, &info, 1, member_count, + min, max, step); +} + +/** + * \brief Create and add an user-defined control element of boolean type. + * + * This is a wrapper function to snd_ctl_add_boolean_elem_set() for a single + * control element. This doesn't fill the id data with full information, thus + * it's recommended to use snd_ctl_add_boolean_elem_set(), instead. + */ +int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int member_count) +{ + snd_ctl_elem_info_t info = {0}; + + assert(ctl && id && id->name[0]); + + info.id = *id; + + return snd_ctl_add_boolean_elem_set(ctl, &info, 1, member_count); +} + +/** + * \brief Create and add a user-defined control element of enumerated type. + * + * This is a wrapper function to snd_ctl_add_enumerated_elem_set() for a single + * control element. This doesn't fill the id data with full information, thus + * it's recommended to use snd_ctl_add_enumerated_elem_set(), instead. + * + * This function is added in version 1.0.25. + */ +int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + unsigned int member_count, unsigned int items, + const char *const labels[]) +{ + snd_ctl_elem_info_t info = {0}; + + assert(ctl && id && id->name[0] && labels); + + info.id = *id; + + return snd_ctl_add_enumerated_elem_set(ctl, &info, 1, member_count, + items, labels); +} + +/** + * \brief Create and add a user-defined control element of IEC958 type. + * \param[in] ctl A handle of backend module for control interface. + * \param[in,out] id ID of the new control element. + * + * This function creates an user element with IEC958 type. This element is not + * controlled by device drivers in kernel. It can be operated by the same way as + * usual elements added by the device drivers. + * + * The name field of \a id must be set with unique value to identify a new + * control element. After returning, all fields of \a id are filled. A element + * can be identified by the combination of name and index, or by numid. + * + * A member in the new element is locked and filled with zero. + * + * \par Errors: + *
+ *
-EBUSY + *
A control element with ID \a id already exists. + *
-EINVAL + *
ID has no name. + *
-ENOMEM + *
Out of memory, or there are too many user elements. + *
-ENXIO + *
This backend module does not support user elements of IEC958 type. + *
-ENODEV + *
Device unplugged. + *
+ */ +int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id) +{ + snd_ctl_elem_info_t info = {0}; + + assert(ctl && id && id->name[0]); + + info.id = *id; + info.type = SND_CTL_ELEM_TYPE_IEC958; + info.owner = 1; + 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 data Data of an element. + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data) +{ + assert(ctl && data && (data->id.name[0] || data->id.numid)); + return ctl->ops->element_read(ctl, data); +} + +/** + * \brief Set CTL element value + * \param ctl CTL handle + * \param data Data of an element. + * \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 *data) +{ + assert(ctl && data && (data->id.name[0] || data->id.numid)); + return ctl->ops->element_write(ctl, data); +} + +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 Read structured data from an element set to given buffer. + * \param ctl A handle of backend module for control interface. + * \param id ID of an element. + * \param tlv An array with members of unsigned int type. + * \param tlv_size The length of the array. + * \return 0 on success otherwise a negative error code + * + * The format of an array of \a tlv argument is: + * tlv[0]: Type. One of SND_CTL_TLVT_XXX. + * tlv[1]: Length. The length of value in units of byte. + * tlv[2..]: Value. Depending on the type. + * + * Details are described in . + */ +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[SNDRV_CTL_TLVO_TYPE] = -1; + tlv[SNDRV_CTL_TLVO_LEN] = 0; + err = snd_ctl_tlv_do(ctl, 0, id, tlv, tlv_size); + if (err >= 0 && tlv[SNDRV_CTL_TLVO_TYPE] == (unsigned int)-1) + err = -ENXIO; + return err; +} + +/** + * \brief Write structured data from given buffer to an element set. + * \param ctl A handle of backend module for control interface. + * \param id ID of an element. + * \param tlv An array with members of unsigned int type. The second member + * must represent total bytes of the rest of array. + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code + * + * The format of an array of \a tlv argument is: + * tlv[0]: Type. One of SND_CTL_TLVT_XXX. + * tlv[1]: Length. The length of value in units of byte. + * tlv[2..]: Value. Depending on the type. + * + * Details are described in . + */ +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[SNDRV_CTL_TLVO_LEN] + 2 * sizeof(unsigned int)); +} + +/** + * \brief Process structured data from given buffer for an element set. + * \param ctl A handle of backend module for control interface. + * \param id ID of an element. + * \param tlv An array with members of unsigned int type. The second member + * must represent total bytes of the rest of array. + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code + * + * The format of an array of \a tlv argument is: + * tlv[0]: Type. One of SND_CTL_TLVT_XXX. + * tlv[1]: Length. The length of value in units of byte. + * tlv[2..]: Value. Depending on the type. + * + * Details are described in . + */ +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[SNDRV_CTL_TLVO_LEN] + 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); + 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) { + 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) +{ + snd_config_t *top; + int err; + + assert(ctlp && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_ctl_open_noupdate(ctlp, top, name, mode); + snd_config_unref(top); + return err; +} + +/** + * \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); +} + +/** + * \brief Opens a fallback CTL + * \param ctlp Returned CTL handle + * \param root Configuration root + * \param name ASCII identifier of the CTL handle used as fallback + * \param orig_name The original ASCII name + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int snd_ctl_open_fallback(snd_ctl_t **ctlp, snd_config_t *root, + const char *name, const char *orig_name, int mode) +{ + int err; + assert(ctlp && name && root); + err = snd_ctl_open_noupdate(ctlp, root, name, mode); + if (err >= 0) { + free((*ctlp)->name); + (*ctlp)->name = orig_name ? strdup(orig_name) : NULL; + } + return err; +} + +#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); + snd_strlcpy((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 + * + * \deprecated Since 1.1.5 + * #snd_ctl_elem_info_get_dimensions is deprecated without any replacement. + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 + * + * \deprecated Since 1.1.5 + * #snd_ctl_elem_info_get_dimension is deprecated without any replacement. + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 Set width to a specified dimension level of given element information. + * \param info Information of an element. + * \param dimension Dimension width for each level by member unit. + * \return Zero on success, otherwise a negative error code. + * + * \par Errors: + *
+ *
-EINVAL + *
Invalid arguments are given as parameters. + *
+ * + * \par Compatibility: + * This function is added in version 1.1.2. + * + * \deprecated Since 1.1.5 + * #snd_ctl_elem_info_set_dimension is deprecated without any replacement. + */ +int snd_ctl_elem_info_set_dimension(snd_ctl_elem_info_t *info, + const int dimension[4]) +{ + unsigned int i; + + if (info == NULL) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(info->dimen.d); i++) { + if (dimension[i] < 0) + return -EINVAL; + + info->dimen.d[i] = dimension[i]; + } + + return 0; +} + +/** + * \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); + snd_strlcpy((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 data structure for an element. + * \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(3). + * \param ptr Returned pointer for data of an element. + * \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 data of an element. + * \param obj Data of an element. + */ +void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj) +{ + free(obj); +} + +/** + * \brief Clear given data of an element. + * \param obj Data of an element. + */ +void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj) +{ + memset(obj, 0, sizeof(snd_ctl_elem_value_t)); +} + +/** + * \brief Copy two data of elements. + * \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 data of an element to the other. + * \param left Pointer to first data. + * \param right Pointer to second data. + * \return 0 on match, less than or greater than otherwise, see memcmp(3). + */ +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 element identifier from given data of an element. + * \param obj Data of an element. + * \param ptr Pointer for 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 from given data of an element. + * \param obj Data of an element. + * \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 element identifier from given data of an + * element. + * \param obj Data of an element. + * \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 element identifier from given data of an element. + * \param obj Data of an element. + * \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 element identifier from given data of an + * element. + * \param obj Data of an element. + * \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 element identifier from given data of an element. + * \param obj Data of an element. + * \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 element identifier from given data of an element. + * \param obj Data of an element. + * \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 element identifier to given data of an element. + * \param obj Data of an element. + * \param ptr Pointer to an 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 numeric identifier to given data of an element. + * \param obj Data of an element. + * \param val Value for 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 element identifier to given data of an element. + * \param obj Data of an element. + * \param val Value for 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 element identifier to given data of an element. + * \param obj Data of an element. + * \param val Value for 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 element identifier to given data of an element. + * \param obj Data of an element. + * \param val Value for 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 element identifier to given data of an element. + * \param obj Data of an element. + * \param val Value for name part of element identifier, + */ +void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val) +{ + assert(obj); + snd_strlcpy((char *)obj->id.name, val, sizeof(obj->id.name)); +} + +/** + * \brief Set index part of element identifier to given data of an element. + * \param obj Data of an element. + * \param val Value for 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 of a specified member from given data as an element of + * boolean type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \return Value for the member. + */ +int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.integer.value)); + return obj->value.integer.value[idx]; +} + +/** + * \brief Get value of a specified member from given data as an element of + * integer type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \return Value for the member. + */ +long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.integer.value)); + return obj->value.integer.value[idx]; +} + +/** + * \brief Get value of a specified member from given data as an element of + * integer64 type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \return Value for the member. + */ +long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.integer64.value)); + return obj->value.integer64.value[idx]; +} + +/** + * \brief Get value of a specified member from given data as an element of + * enumerated type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \return Value for the member. This is an index of name set in the element. + */ +unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.enumerated.item)); + return obj->value.enumerated.item[idx]; +} + +/** + * \brief Get value of a specified member from given data as an element of + * bytes type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \return Value for the member. + */ +unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.bytes.data)); + return obj->value.bytes.data[idx]; +} + +/** + * \brief Set value of a specified member to given data as an element of + * boolean type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \param val Value for the member. + */ +void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.integer.value)); + obj->value.integer.value[idx] = val; +} + +/** + * \brief Set value of a specified member to given data as an element of + * integer type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \param val Value for the member. + */ +void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.integer.value)); + obj->value.integer.value[idx] = val; +} + +/** + * \brief Set value of a specified member to given data as an element of + * integer64 type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \param val Value for the member. + */ +void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.integer64.value)); + obj->value.integer64.value[idx] = val; +} + +/** + * \brief Set value of a specified member to given data as an element of + * enumerated type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \param val Value for the member. + */ +void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.enumerated.item)); + obj->value.enumerated.item[idx] = val; +} + +/** + * \brief Set value for a specified member to given data as an element of byte + * type. + * \param obj Data of an element. + * \param idx Index of member in the element. + * \param val Value for the member. + */ +void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val) +{ + assert(obj); + assert(idx < ARRAY_SIZE(obj->value.bytes.data)); + obj->value.bytes.data[idx] = val; +} + +/** + * \brief Set values to given data as an element of bytes type. + * \param obj Data of an element. + * \param data Pointer for byte array. + * \param size The number of bytes included in the memory block. + */ +void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) +{ + assert(obj); + assert(size <= ARRAY_SIZE(obj->value.bytes.data)); + memcpy(obj->value.bytes.data, data, size); +} + +/** + * \brief Get memory block from given data as an element of bytes type. + * \param obj Data of an element. + * \return Pointer for byte array. + */ +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 from given data to given pointer as an element of IEC958 + * type. + * \param obj Data of an element. + * \param ptr Pointer to IEC958 data. + */ +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 from given pointer to given data as an element of IEC958 + * type. + * \param obj Data of an element. + * \param ptr Pointer to IEC958 data. + */ +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..515f788 --- /dev/null +++ b/src/control/control_ext.c @@ -0,0 +1,742 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_elem_tlv(snd_ctl_t *handle, int op_flag, + unsigned int numid, + unsigned int *tlv, unsigned int tlv_size) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + unsigned int access, count, len; + snd_ctl_elem_id_t id; + + /* we don't support TLV on protocol ver 1.0.0 or earlier */ + if (ext->version <= SNDRV_PROTOCOL_VERSION(1, 0, 0)) + return -ENXIO; + + snd_ctl_elem_id_clear(&id); + if (numid > 0) { + ext->callback->elem_list(ext, numid - 1, &id); + id.numid = numid; + } else + id.numid = 0; + key = ext->callback->find_elem(ext, &id); + + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &access, &count); + if (ret < 0) + return ret; + + if ((op_flag == 0 && (access & SND_CTL_EXT_ACCESS_TLV_READ) == 0) || + (op_flag > 0 && (access & SND_CTL_EXT_ACCESS_TLV_WRITE) == 0) || + (op_flag < 0 && (access & SND_CTL_EXT_ACCESS_TLV_COMMAND) == 0)) + return -ENXIO; + if (access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + return ext->tlv.c(ext, key, op_flag, numid, tlv, tlv_size); + } else { + if (op_flag) + return -ENXIO; + len = ext->tlv.p[1] + 2 * sizeof(unsigned int); + if (tlv_size < len) + return -ENOMEM; + memcpy(tlv, ext->tlv.p, len); + return 0; + } +} + +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; + + if (ext->callback->read_event) { + memset(event, 0, sizeof(*event)); + return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); + } + + return -EINVAL; +} + +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, + .element_tlv = snd_ctl_ext_elem_tlv, + .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_ext_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 < SNDRV_PROTOCOL_VERSION(1, 0, 0) || + 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..b54d65f --- /dev/null +++ b/src/control/control_hw.c @@ -0,0 +1,471 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && + hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 7)) + return -ENXIO; + + 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 (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && + hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 7)) + return -ENXIO; + + 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) +{ + unsigned int inum; + snd_ctl_hw_t *hw = handle->private_data; + struct snd_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 snd_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) { + unsigned int size; + size = xtlv->tlv[SNDRV_CTL_TLVO_LEN] + 2 * sizeof(unsigned int); + if (size > tlv_size) { + free(xtlv); + return -EFAULT; + } + memcpy(tlv, xtlv->tlv, size); + } + 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 >= SND_MAX_CARDS)) { + 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); + return err; + } + 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 (_snd_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; + } + 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..9568968 --- /dev/null +++ b/src/control/control_local.h @@ -0,0 +1,108 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "local.h" +#include + +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); + +#define CTLINABORT(x) ((x)->nonblock == 2) + +#ifdef INTERNAL +int INTERNAL(snd_ctl_elem_info_get_dimensions)(const snd_ctl_elem_info_t *obj); +int INTERNAL(snd_ctl_elem_info_get_dimension)(const snd_ctl_elem_info_t *obj, unsigned int idx); +#endif /* INTERNAL */ diff --git a/src/control/control_shm.c b/src/control/control_shm.c new file mode 100644 index 0000000..40d4264 --- /dev/null +++ b/src/control/control_shm.c @@ -0,0 +1,621 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + ctrl->u.pcm_prefer_subdevice = subdev; + ctrl->cmd = SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE; + return snd_ctl_shm_action(ctl); +} + +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; + ctrl->u.rawmidi_prefer_subdevice = subdev; + ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE; + return snd_ctl_shm_action(ctl); +} + +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; + ctrl->u.power_state = state; + ctrl->cmd = SNDRV_CTL_IOCTL_POWER; + return snd_ctl_shm_action(ctl); +} + +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) { + close(sock); + return -errno; + } + return sock; +} + +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 *sockname = NULL; + long port = -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 (_snd_conf_generic_id(id)) + 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 (_snd_conf_generic_id(id)) + continue; + if (strcmp(id, "host") == 0) + 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 (!sockname) { + SNDERR("socket is not defined"); + 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..a2431e6 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/ctlparse.c b/src/control/ctlparse.c new file mode 100644 index 0000000..b0bb5ee --- /dev/null +++ b/src/control/ctlparse.c @@ -0,0 +1,392 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include "control_local.h" + +/* Function to convert from percentage to volume. val = percentage */ + +#ifdef HAVE_SOFT_FLOAT +static inline long int convert_prange1(long val, long min, long max) +{ + long temp = val * (max - min); + return temp / 100 + min + ((temp % 100) == 0 ? 0 : 1); +} +#else + +#define convert_prange1(val, min, max) \ + ceil((val) * ((max) - (min)) * 0.01 + (min)) +#endif + +#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, 0); + if (*p == '.') { + p++; + (void)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, 0); + if (*p == '.') { + p++; + (void)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=%u", index); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + if (device) { + snprintf(buf1, sizeof(buf1), ",device=%u", device); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + if (subdevice) { + snprintf(buf1, sizeof(buf1), ",subdevice=%u", subdevice); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + return strdup(buf); +} + +#ifndef DOC_HIDDEN +/* used by UCM parser, too */ +int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str, + const char **ret_ptr) +{ + int c, size, numid; + int err = -EINVAL; + char *ptr; + + while (isspace(*str)) + str++; + if (!(*str)) + goto out; + 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); + goto out; + } + 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 { + goto out; + } + } 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 { + /* when ret_ptr is given, allow to terminate gracefully + * at the next space letter + */ + if (ret_ptr && isspace(*str)) + break; + if (*str) + goto out; + } + } + err = 0; + + out: + if (ret_ptr) + *ret_ptr = str; + return err; +} +#endif + +/** + * \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) +{ + return __snd_ctl_ascii_elem_id_parse(dst, str, NULL); +} + +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; + char end; + + 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); + end = *ptr; + if (end == '\'' || end == '"') + ptr++; + else + end = '\0'; + len = strlen(name); + if (strncmp(name, ptr, len) == 0) { + if (ptr[len] == end || ptr[len] == ',' || ptr[len] == '\n') { + ptr += len; + *ptrp = ptr; + return i; + } + } + } + return -1; +} + +/** + * \brief parse ASCII string as CTL element value + * \param handle CTL handle + * \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 + * + * Note: For toggle command, the dst must contain previous (current) + * state (do the #snd_ctl_elem_read call to obtain it). + */ +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 = {0}; + snd_ctl_elem_type_t type; + unsigned int idx, count; + long tmp; + long long tmp64; + + 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++) { + if (*ptr == ',') + goto skip; + 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; + } + skip: + 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..0cac895 --- /dev/null +++ b/src/control/hcontrol.c @@ -0,0 +1,1013 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 && !CTLINABORT(hctl->ctl)) + 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); + 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); + 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[SNDRV_CTL_TLVO_LEN] >= 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[SNDRV_CTL_TLVO_LEN] >= 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..808df6b --- /dev/null +++ b/src/control/namehint.c @@ -0,0 +1,706 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "local.h" + +#ifndef DOC_HIDDEN +#define DEV_SKIP 9999 /* some non-existing device number */ +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 + 1 >= list->allocated) { + char **n = realloc(list->list, (list->allocated + 10) * sizeof(char *)); + if (n == NULL) + return -ENOMEM; + memset(n + list->allocated, 0, 10 * sizeof(*n)); + 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, + va_list arg ATTRIBUTE_UNUSED) +{ +} + +static int get_dev_name1(struct hint_list *list, char **res, int device, + int stream) +{ + *res = NULL; + if (device < 0 || device == DEV_SKIP) + return 0; + switch (list->iface) { +#ifdef BUILD_HWDEP + case SND_CTL_ELEM_IFACE_HWDEP: + { + snd_hwdep_info_t info = {0}; + 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 = {0}; + 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 = {0}; + 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(snd_config_t *config, + struct hint_list *list, + const char *base, + const char *name) +{ + snd_local_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(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_set_local(&zero_handler); + err = snd_config_search_definition(config, base, buf, &res); + snd_lib_error_set_local(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) { + 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; + } + /* skip the counterpart if only a single direction is defined */ + if (list->device_output < 0) + list->device_output = DEV_SKIP; + } + 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; + } + /* skip the counterpart if only a single direction is defined */ + if (list->device_input < 0) + list->device_input = DEV_SKIP; + } + } 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_set_local(&zero_handler); + err = snd_config_search_alias_hooks(config, base, buf, &res); + snd_lib_error_set_local(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(snd_config_t *config, snd_config_t *rw_config, 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 = {0}; + int device, max_device = 0; + + list->info = &info; + err = snd_config_search(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(rw_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(rw_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(snd_config_t *config, snd_config_t *rw_config, + struct hint_list *list) +{ + int err; + snd_config_t *conf, *n; + snd_config_iterator_t i, next; + const char *str; + + err = snd_config_search(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(rw_config, list, list->siface, str); + if (err == -ENOMEM) + return -ENOMEM; + } + return 0; +} + +/** + * \brief Get a set of 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 device name hints + * \result zero if success, otherwise a negative error code + * + * hints will receive a NULL-terminated array of device name hints, + * which can be passed to #snd_device_name_get_hint to extract usable + * values. When no longer needed, hints should be passed to + * #snd_device_name_free_hint to release resources. + * + * 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"
+ * } + *
+ * + * Note: The device description is separated with '|' char. + * + * 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, *local_config = NULL, *local_config_rw = NULL; + snd_config_update_t *local_config_update = NULL; + snd_config_iterator_t i, next; + int err; + + if (hints == NULL) + return -EINVAL; + err = snd_config_update_r(&local_config, &local_config_update, NULL); + if (err < 0) + return err; + err = snd_config_copy(&local_config_rw, local_config); + if (err < 0) + return err; + list.list = NULL; + list.count = list.allocated = 0; + list.siface = iface; + list.show_all = 0; + list.cardname = NULL; + 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 { + err = -EINVAL; + goto __error; + } + + if (snd_config_search(local_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(local_config, local_config_rw, &list, card); + } else { + add_software_devices(local_config, local_config_rw, &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(local_config, local_config_rw, &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(local_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: + /* add an empty entry if nothing has been added yet; the caller + * expects non-NULL return + */ + if (!err && !list.list) + err = hint_list_add(&list, NULL, NULL); + if (err < 0) + snd_device_name_free_hint((void **)list.list); + else + *hints = (void **)list.list; + free(list.cardname); + if (local_config_rw) + snd_config_delete(local_config_rw); + if (local_config) + snd_config_delete(local_config); + if (local_config_update) + snd_config_update_free(local_config_update); + return err; +} + +/** + * \brief Free a list of device name hints. + * \param hints 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 Extract a value from a hint + * \param hint A pointer to hint + * \param id Hint value to extract ("NAME", "DESC", or "IOID", see below) + * \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"), NULL means both + * + * The return value should be freed when no longer needed. + */ +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..ab84bbe --- /dev/null +++ b/src/control/setup.c @@ -0,0 +1,648 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 = {0}; + snd_ctl_elem_type_t type; + unsigned int count; + long v; + long idx; + 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, int *quit) +{ + snd_config_t *conf; + 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 lock = 0; + int preserve = 0; + int optional = 0; + int skip_rest = 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) { + err = snd_config_get_bool(n); + if (err < 0) + goto _err; + lock = err; + continue; + } + if (strcmp(id, "preserve") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + goto _err; + preserve = err; + continue; + } + if (strcmp(id, "value") == 0) { + value = n; + continue; + } + if (strcmp(id, "mask") == 0) { + mask = n; + continue; + } + if (strcmp(id, "optional") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + goto _err; + optional = err; + continue; + } + if (strcmp(id, "skip_rest") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + goto _err; + skip_rest = err; + 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; + } else { + if (skip_rest) + *quit = 1; + } + 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, quit = 0; + + 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, &quit); + if (err < 0) { + free_elems(h); + return err; + } + if (quit) + break; + } + *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..d6944b5 --- /dev/null +++ b/src/control/tlv.c @@ -0,0 +1,503 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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[SNDRV_CTL_TLVO_TYPE]; + size = tlv[SNDRV_CTL_TLVO_LEN]; + 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[SNDRV_CTL_TLVO_LEN]) + 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[SNDRV_CTL_TLVO_TYPE]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[SNDRV_CTL_TLVO_LEN]); + 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[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & 0x10000) + *min = SND_CTL_TLV_DB_GAIN_MUTE; + else + *min = (int)tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN]; + step = (tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & 0xffff); + *max = (int)tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] + + step * (rangemax - rangemin); + return 0; + } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_LINEAR: + *min = (int)tlv[SNDRV_CTL_TLVO_DB_LINEAR_MIN]; + *max = (int)tlv[SNDRV_CTL_TLVO_DB_LINEAR_MAX]; + return 0; + case SND_CTL_TLVT_DB_MINMAX_MUTE: + *min = SND_CTL_TLV_DB_GAIN_MUTE; + *max = (int)tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX]; + 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) +{ + unsigned int type = tlv[SNDRV_CTL_TLVO_TYPE]; + + switch (type) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[SNDRV_CTL_TLVO_LEN]); + 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[SNDRV_CTL_TLVO_DB_SCALE_MIN]; + step = (tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & 0xffff); + mute = (tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] >> 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[SNDRV_CTL_TLVO_DB_MINMAX_MIN]; + maxdb = tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX]; + if (volume <= rangemin || rangemax <= rangemin) { + if (type == 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[SNDRV_CTL_TLVO_DB_LINEAR_MIN]; + int maxdb = tlv[SNDRV_CTL_TLVO_DB_LINEAR_MAX]; + 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) +{ + unsigned int type = tlv[SNDRV_CTL_TLVO_TYPE]; + + switch (type) { + case SND_CTL_TLVT_DB_RANGE: { + long dbmin, dbmax, prev_submax; + unsigned int pos, len; + len = int_index(tlv[SNDRV_CTL_TLVO_LEN]); + if (len < 6 || len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + prev_submax = 0; + while (pos + 4 <= len) { + long submin, submax; + submin = (int)tlv[pos]; + submax = (int)tlv[pos + 1]; + if (rangemax < submax) + submax = rangemax; + if (!snd_tlv_get_dB_range(tlv + pos + 2, + submin, submax, + &dbmin, &dbmax) && + db_gain >= dbmin && db_gain <= dbmax) + return snd_tlv_convert_from_dB(tlv + pos + 2, + submin, submax, + db_gain, value, xdir); + else if (db_gain < dbmin) { + *value = xdir > 0 || pos == 2 ? submin : prev_submax; + return 0; + } + prev_submax = submax; + if (rangemax == submax) + break; + pos += int_index(tlv[pos + 3]) + 4; + } + *value = prev_submax; + return 0; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, max, mute; + min = tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN]; + step = tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & 0xffff; + mute = tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & 0x10000; + max = min + (int)(step * (rangemax - rangemin)); + if (db_gain <= min) + if (db_gain > SND_CTL_TLV_DB_GAIN_MUTE && xdir > 0 && + 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; + } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: { + int min, max; + min = tlv[SNDRV_CTL_TLVO_DB_MINMAX_MIN]; + max = tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX]; + if (db_gain <= min) + if (db_gain > SND_CTL_TLV_DB_GAIN_MUTE && xdir > 0 && + type == 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[SNDRV_CTL_TLVO_DB_LINEAR_MIN]; + max = tlv[SNDRV_CTL_TLVO_DB_LINEAR_MAX]; + 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 = {0}; + int err; + + 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..8c8f3ff --- /dev/null +++ b/src/dlmisc.c @@ -0,0 +1,391 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + * \param errbuf a string buffer for the error message \c dlerror. + * \param errbuflen a length of the string buffer for the error message. + * \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. + */ +#ifndef DOXYGEN +EXPORT_SYMBOL void *INTERNAL(snd_dlopen)(const char *name, int mode, char *errbuf, size_t errbuflen) +#else +void *snd_dlopen(const char *name, int mode, char *errbuf, size_t errbuflen) +#endif +{ +#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 + /* + * Handle the plugin dir not being on the default dlopen search + * path, without resorting to polluting the entire system namespace + * via ld.so.conf. + */ + void *handle = NULL; + char *filename = NULL; + + if (name && name[0] != '/') { + filename = alloca(sizeof(ALSA_PLUGIN_DIR) + 1 + strlen(name) + 1); + if (filename) { + strcpy(filename, ALSA_PLUGIN_DIR); + strcat(filename, "/"); + strcat(filename, name); + handle = dlopen(filename, mode); + if (!handle) { + /* if the filename exists and cannot be opened */ + /* return immediately */ + if (access(filename, X_OK) == 0) + goto errpath; + } + } + } + if (!handle) { + handle = dlopen(name, mode); + if (!handle) + goto errpath; + } + return handle; +errpath: + if (errbuf) + snprintf(errbuf, errbuflen, "%s: %s", filename, dlerror()); +#endif + return NULL; +} + +#ifndef DOXYGEN +void *INTERNAL(snd_dlopen_old)(const char *name, int mode) +{ + return INTERNAL(snd_dlopen)(name, mode, NULL, 0); +} +#endif + +use_symbol_version(__snd_dlopen_old, snd_dlopen, ALSA_0.9); +use_default_symbol_version(__snd_dlopen, snd_dlopen, ALSA_1.1.6); + +/** + * \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 +#ifdef VERSIONED_SYMBOLS + if (version) { + err = snd_dlsym_verify(handle, name, version); + if (err < 0) + return NULL; + } +#endif + 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); + +static struct dlobj_cache * +snd_dlobj_cache_get0(const char *lib, const char *name, + const char *version, int verbose) +{ + struct list_head *p; + struct dlobj_cache *c; + void *func, *dlobj; + char errbuf[256]; + + 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; + if (strcmp(c->name, name) == 0) { + c->refcnt++; + return c; + } + } + + errbuf[0] = '\0'; + dlobj = INTERNAL(snd_dlopen)(lib, RTLD_NOW, + verbose ? errbuf : 0, + verbose ? sizeof(errbuf) : 0); + if (dlobj == NULL) { + if (verbose) + SNDERR("Cannot open shared library %s (%s)", + lib ? lib : "[builtin]", + errbuf); + return NULL; + } + + 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: + snd_dlclose(dlobj); + snd_dlobj_unlock(); + return NULL; + } + c->dlobj = dlobj; + c->func = func; + list_add_tail(&c->list, &pcm_dlobj_list); + return c; +} + +void *snd_dlobj_cache_get(const char *lib, const char *name, + const char *version, int verbose) +{ + struct dlobj_cache *c; + void *func = NULL; + + snd_dlobj_lock(); + c = snd_dlobj_cache_get0(lib, name, version, verbose); + if (c) + func = c->func; + snd_dlobj_unlock(); + return func; +} + +void *snd_dlobj_cache_get2(const char *lib, const char *name, + const char *version, int verbose) +{ + struct dlobj_cache *c; + void *func = NULL; + + snd_dlobj_lock(); + c = snd_dlobj_cache_get0(lib, name, version, verbose); + if (c) { + func = c->func; + /* double reference */ + c->refcnt++; + } + snd_dlobj_unlock(); + return func; +} + +int snd_dlobj_cache_put(void *func) +{ + struct list_head *p; + struct dlobj_cache *c; + unsigned int refcnt; + + if (!func) + return -ENOENT; + + 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) + continue; + 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..2e617f8 --- /dev/null +++ b/src/error.c @@ -0,0 +1,201 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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]; +} + +#ifndef DOC_HIDDEN +#ifdef HAVE___THREAD +#define TLS_PFX __thread +#else +#define TLS_PFX /* NOP */ +#endif +#endif + +static TLS_PFX snd_local_error_handler_t local_error = NULL; + +/** + * \brief Install local error handler + * \param func The local error handler function + * \retval Previous local error handler function + */ +snd_local_error_handler_t snd_lib_error_set_local(snd_local_error_handler_t func) +{ + snd_local_error_handler_t old = local_error; + local_error = func; + return old; +} + +/** + * \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. + * + * If a local error function has been installed for the current thread by + * \ref snd_lib_error_set_local, it is called. Otherwise, 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); + if (local_error) { + local_error(file, line, function, err, fmt, arg); + va_end(arg); + return; + } + 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 + +/** + * \brief Copy a C-string into a sized buffer + * \param dst Where to copy the string to + * \param src Where to copy the string from + * \param size Size of destination buffer + * \retval The source string length + * + * The result is always a valid NUL-terminated string that fits + * in the buffer (unless, of course, the buffer size is zero). + * It does not pad out the result like strncpy() does. + */ +size_t snd_strlcpy(char *dst, const char *src, size_t size) +{ + size_t ret = strlen(src); + if (size) { + size_t len = ret >= size ? size - 1 : ret; + memcpy(dst, src, len); + dst[len] = '\0'; + } + return ret; +} diff --git a/src/hwdep/Makefile.am b/src/hwdep/Makefile.am new file mode 100644 index 0000000..b543e58 --- /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 + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/hwdep/Makefile.in b/src/hwdep/Makefile.in new file mode 100644 index 0000000..20ac6cd --- /dev/null +++ b/src/hwdep/Makefile.in @@ -0,0 +1,607 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/hwdep.Plo ./$(DEPDIR)/hwdep_hw.Plo \ + ./$(DEPDIR)/hwdep_symbols.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libhwdep_la_SOURCES) +DIST_SOURCES = $(libhwdep_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libhwdep.la: $(libhwdep_la_OBJECTS) $(libhwdep_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwdep_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwdep_symbols.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/hwdep.Plo + -rm -f ./$(DEPDIR)/hwdep_hw.Plo + -rm -f ./$(DEPDIR)/hwdep_symbols.Plo + -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 -f ./$(DEPDIR)/hwdep.Plo + -rm -f ./$(DEPDIR)/hwdep_hw.Plo + -rm -f ./$(DEPDIR)/hwdep_symbols.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +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..c5b3513 --- /dev/null +++ b/src/hwdep/hwdep.c @@ -0,0 +1,765 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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], errbuf[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); + 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_hwdep_%s_open", str); + } +#ifndef PIC + snd_hwdep_open_symbols(); +#endif + h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", lib, errbuf); + 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) +{ + snd_config_t *top; + int err; + + assert(hwdep && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_hwdep_open_noupdate(hwdep, top, name, mode); + snd_config_unref(top); + return err; +} + +/** + * \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..d303719 --- /dev/null +++ b/src/hwdep/hwdep_hw.c @@ -0,0 +1,188 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 >= SND_MAX_CARDS) + 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 (_snd_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; + } + 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..6cc95b0 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..d6f74fa --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..35324f1 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..6eeff8a --- /dev/null +++ b/src/mixer/Makefile.am @@ -0,0 +1,14 @@ +EXTRA_LTLIBRARIES=libmixer.la + +libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c + +if BUILD_MODULES +libmixer_la_SOURCES += simple_abst.c +endif + +noinst_HEADERS = mixer_local.h mixer_simple.h + +all: libmixer.la + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/mixer/Makefile.in b/src/mixer/Makefile.in new file mode 100644 index 0000000..cdf4a0c --- /dev/null +++ b/src/mixer/Makefile.in @@ -0,0 +1,621 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 = simple_abst.c +subdir = src/mixer +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +libmixer_la_LIBADD = +am__libmixer_la_SOURCES_DIST = bag.c mixer.c simple.c simple_none.c \ + simple_abst.c +@BUILD_MODULES_TRUE@am__objects_1 = simple_abst.lo +am_libmixer_la_OBJECTS = bag.lo mixer.lo simple.lo simple_none.lo \ + $(am__objects_1) +libmixer_la_OBJECTS = $(am_libmixer_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/bag.Plo ./$(DEPDIR)/mixer.Plo \ + ./$(DEPDIR)/simple.Plo ./$(DEPDIR)/simple_abst.Plo \ + ./$(DEPDIR)/simple_none.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libmixer_la_SOURCES) +DIST_SOURCES = $(am__libmixer_la_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 \ + $(am__append_1) +noinst_HEADERS = mixer_local.h mixer_simple.h +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libmixer.la: $(libmixer_la_OBJECTS) $(libmixer_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mixer.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_abst.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simple_none.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/bag.Plo + -rm -f ./$(DEPDIR)/mixer.Plo + -rm -f ./$(DEPDIR)/simple.Plo + -rm -f ./$(DEPDIR)/simple_abst.Plo + -rm -f ./$(DEPDIR)/simple_none.Plo + -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 -f ./$(DEPDIR)/bag.Plo + -rm -f ./$(DEPDIR)/mixer.Plo + -rm -f ./$(DEPDIR)/simple.Plo + -rm -f ./$(DEPDIR)/simple_abst.Plo + -rm -f ./$(DEPDIR)/simple_none.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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..18a8fbe --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..8205647 --- /dev/null +++ b/src/mixer/mixer.c @@ -0,0 +1,1085 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) + 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 + * + * Upon error, this function closes the given hctl handle automatically. + */ +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) { + snd_hctl_close(hctl); + 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++, pfds++) + 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 *)) +{ + 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..667242b --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..4d556c8 --- /dev/null +++ b/src/mixer/mixer_simple.h @@ -0,0 +1,41 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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); + +#ifdef HAVE_LIBDL +int snd_mixer_simple_basic_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp); +#else +static inline int snd_mixer_simple_basic_register(snd_mixer_t *mixer ATTRIBUTE_UNUSED, + struct snd_mixer_selem_regopt *options ATTRIBUTE_UNUSED, + snd_mixer_class_t **classp ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} +#endif diff --git a/src/mixer/simple.c b/src/mixer/simple.c new file mode 100644 index 0000000..2861d97 --- /dev/null +++ b/src/mixer/simple.c @@ -0,0 +1,1107 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#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 rounding mode - rounds up if dir > 0, otherwise rounds down + * \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 rounding mode - rounds up if dir > 0, otherwise rounds down + * \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 rounding mode - rounds up if dir > 0, otherwise rounds down + * \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 rounding mode - rounds up if dir > 0, otherwise rounds down + * \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 rounding mode - rounds up if dir > 0, otherwise rounds down + * \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 rounding mode - rounds up if dir > 0, otherwise rounds down + * \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); + 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); + 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; +} + +/** + * \brief Parse ASCII simple mixer element identifier + * \param dst Parsed simple mixer element identifier + * \param str Mixer simple element ASCII representation + */ +int snd_mixer_selem_id_parse(snd_mixer_selem_id_t *dst, const char *str) +{ + int c, size; + char buf[128]; + char *ptr = buf; + + memset(dst, 0, sizeof(*dst)); + while (*str == ' ' || *str == '\t') + str++; + if (!(*str)) + return -EINVAL; + size = 1; /* for '\0' */ + if (*str != '"' && *str != '\'') { + while (*str && *str != ',') { + if (size < (int)sizeof(buf)) { + *ptr++ = *str; + size++; + } + str++; + } + } else { + c = *str++; + while (*str && *str != c) { + if (size < (int)sizeof(buf)) { + *ptr++ = *str; + size++; + } + str++; + } + if (*str == c) + str++; + } + if (*str == '\0') { + *ptr = 0; + goto _set; + } + if (*str != ',') + return -EINVAL; + *ptr = 0; /* terminate the string */ + str++; + if (str[0] < '0' || str[1] > '9') + return -EINVAL; + dst->index = atoi(str); + _set: + snd_strlcpy(dst->name, buf, sizeof(dst->name)); + return 0; +} diff --git a/src/mixer/simple_abst.c b/src/mixer/simple_abst.c new file mode 100644 index 0000000..9c61cb5 --- /dev/null +++ b/src/mixer/simple_abst.c @@ -0,0 +1,425 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mixer_local.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, errbuf[256]; + void *h; + int err = 0; + + if (!lib) + return -ENXIO; + 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 = INTERNAL(snd_dlopen)(xlib, RTLD_NOW, errbuf, sizeof(errbuf)); + if (h == NULL) { + SNDERR("Unable to open library '%s' (%s)", xlib, errbuf); + 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, errbuf[256]; + 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 = INTERNAL(snd_dlopen)(xlib, RTLD_NOW|RTLD_GLOBAL, errbuf, sizeof(errbuf)); + 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) { + const char *topdir = snd_config_topdir(); + char *s = alloca(strlen(topdir) + strlen("smixer.conf") + 2); + sprintf(s, "%s/smixer.conf", topdir); + file = s; + } + 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..e9dc173 --- /dev/null +++ b/src/mixer/simple_none.c @@ -0,0 +1,1734 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "local.h" +#include "config.h" +#include "mixer_simple.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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + 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]; + 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 = {0}; + selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; + 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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + unsigned int idx; + int err; + selem_ctl_t *c = &s->ctls[type]; + 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 = {0}; + 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]; + 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 = {0}; + selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; + 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; + + 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); + 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); + } + if (strstr(name, "3D Control")) { + if (strstr(name, "Depth")) { + *type = CTL_PLAYBACK_VOLUME; + 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 = {0}; + 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; + + 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 = {0}; + 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_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 = {0}; + 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); + 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 = {0}; + 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; + } + 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 = {0}; + selem_none_t *simple; + const char *name1; + snd_ctl_elem_type_t ctype; + unsigned long values; + + 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 = {0}; + unsigned int k, items; + int err; + 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..d909a11 --- /dev/null +++ b/src/names.c @@ -0,0 +1,56 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include "local.h" + +/** + * \brief This function is unimplemented. + * \deprecated Since 1.0.14 + */ +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 This function is unimplemented. + * \deprecated Since 1.0.14 + */ +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..7e3a91b --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..8edbd0b --- /dev/null +++ b/src/pcm/Makefile.am @@ -0,0 +1,117 @@ +SUBDIRS = +DIST_SUBDIRS = scopes + +EXTRA_LTLIBRARIES = libpcm.la + +libpcm_la_SOURCES = 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 + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/pcm/Makefile.in b/src/pcm/Makefile.in new file mode 100644 index 0000000..cafb286 --- /dev/null +++ b/src/pcm/Makefile.in @@ -0,0 +1,954 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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 = 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 = 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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/interval.Plo ./$(DEPDIR)/mask.Plo \ + ./$(DEPDIR)/pcm.Plo ./$(DEPDIR)/pcm_adpcm.Plo \ + ./$(DEPDIR)/pcm_alaw.Plo ./$(DEPDIR)/pcm_asym.Plo \ + ./$(DEPDIR)/pcm_copy.Plo ./$(DEPDIR)/pcm_direct.Plo \ + ./$(DEPDIR)/pcm_dmix.Plo ./$(DEPDIR)/pcm_dshare.Plo \ + ./$(DEPDIR)/pcm_dsnoop.Plo ./$(DEPDIR)/pcm_empty.Plo \ + ./$(DEPDIR)/pcm_extplug.Plo ./$(DEPDIR)/pcm_file.Plo \ + ./$(DEPDIR)/pcm_generic.Plo ./$(DEPDIR)/pcm_hooks.Plo \ + ./$(DEPDIR)/pcm_hw.Plo ./$(DEPDIR)/pcm_iec958.Plo \ + ./$(DEPDIR)/pcm_ioplug.Plo ./$(DEPDIR)/pcm_ladspa.Plo \ + ./$(DEPDIR)/pcm_lfloat.Plo ./$(DEPDIR)/pcm_linear.Plo \ + ./$(DEPDIR)/pcm_meter.Plo ./$(DEPDIR)/pcm_misc.Plo \ + ./$(DEPDIR)/pcm_mmap.Plo ./$(DEPDIR)/pcm_mmap_emul.Plo \ + ./$(DEPDIR)/pcm_mulaw.Plo ./$(DEPDIR)/pcm_multi.Plo \ + ./$(DEPDIR)/pcm_null.Plo ./$(DEPDIR)/pcm_params.Plo \ + ./$(DEPDIR)/pcm_plug.Plo ./$(DEPDIR)/pcm_plugin.Plo \ + ./$(DEPDIR)/pcm_rate.Plo ./$(DEPDIR)/pcm_rate_linear.Plo \ + ./$(DEPDIR)/pcm_route.Plo ./$(DEPDIR)/pcm_share.Plo \ + ./$(DEPDIR)/pcm_shm.Plo ./$(DEPDIR)/pcm_simple.Plo \ + ./$(DEPDIR)/pcm_softvol.Plo ./$(DEPDIR)/pcm_symbols.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libpcm_la_SOURCES) +DIST_SOURCES = $(am__libpcm_la_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 = 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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libpcm.la: $(libpcm_la_OBJECTS) $(libpcm_la_DEPENDENCIES) $(EXTRA_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)/interval.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mask.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_adpcm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_alaw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_asym.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_copy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_direct.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_dmix.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_dshare.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_dsnoop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_empty.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_extplug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_file.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_generic.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_hooks.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_iec958.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_ioplug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_ladspa.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_lfloat.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_linear.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_meter.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_misc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_mmap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_mmap_emul.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_mulaw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_multi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_null.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_params.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_plug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_plugin.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_rate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_rate_linear.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_route.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_share.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_shm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_simple.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_softvol.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_symbols.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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 + +# 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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/interval.Plo + -rm -f ./$(DEPDIR)/mask.Plo + -rm -f ./$(DEPDIR)/pcm.Plo + -rm -f ./$(DEPDIR)/pcm_adpcm.Plo + -rm -f ./$(DEPDIR)/pcm_alaw.Plo + -rm -f ./$(DEPDIR)/pcm_asym.Plo + -rm -f ./$(DEPDIR)/pcm_copy.Plo + -rm -f ./$(DEPDIR)/pcm_direct.Plo + -rm -f ./$(DEPDIR)/pcm_dmix.Plo + -rm -f ./$(DEPDIR)/pcm_dshare.Plo + -rm -f ./$(DEPDIR)/pcm_dsnoop.Plo + -rm -f ./$(DEPDIR)/pcm_empty.Plo + -rm -f ./$(DEPDIR)/pcm_extplug.Plo + -rm -f ./$(DEPDIR)/pcm_file.Plo + -rm -f ./$(DEPDIR)/pcm_generic.Plo + -rm -f ./$(DEPDIR)/pcm_hooks.Plo + -rm -f ./$(DEPDIR)/pcm_hw.Plo + -rm -f ./$(DEPDIR)/pcm_iec958.Plo + -rm -f ./$(DEPDIR)/pcm_ioplug.Plo + -rm -f ./$(DEPDIR)/pcm_ladspa.Plo + -rm -f ./$(DEPDIR)/pcm_lfloat.Plo + -rm -f ./$(DEPDIR)/pcm_linear.Plo + -rm -f ./$(DEPDIR)/pcm_meter.Plo + -rm -f ./$(DEPDIR)/pcm_misc.Plo + -rm -f ./$(DEPDIR)/pcm_mmap.Plo + -rm -f ./$(DEPDIR)/pcm_mmap_emul.Plo + -rm -f ./$(DEPDIR)/pcm_mulaw.Plo + -rm -f ./$(DEPDIR)/pcm_multi.Plo + -rm -f ./$(DEPDIR)/pcm_null.Plo + -rm -f ./$(DEPDIR)/pcm_params.Plo + -rm -f ./$(DEPDIR)/pcm_plug.Plo + -rm -f ./$(DEPDIR)/pcm_plugin.Plo + -rm -f ./$(DEPDIR)/pcm_rate.Plo + -rm -f ./$(DEPDIR)/pcm_rate_linear.Plo + -rm -f ./$(DEPDIR)/pcm_route.Plo + -rm -f ./$(DEPDIR)/pcm_share.Plo + -rm -f ./$(DEPDIR)/pcm_shm.Plo + -rm -f ./$(DEPDIR)/pcm_simple.Plo + -rm -f ./$(DEPDIR)/pcm_softvol.Plo + -rm -f ./$(DEPDIR)/pcm_symbols.Plo + -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 -f ./$(DEPDIR)/interval.Plo + -rm -f ./$(DEPDIR)/mask.Plo + -rm -f ./$(DEPDIR)/pcm.Plo + -rm -f ./$(DEPDIR)/pcm_adpcm.Plo + -rm -f ./$(DEPDIR)/pcm_alaw.Plo + -rm -f ./$(DEPDIR)/pcm_asym.Plo + -rm -f ./$(DEPDIR)/pcm_copy.Plo + -rm -f ./$(DEPDIR)/pcm_direct.Plo + -rm -f ./$(DEPDIR)/pcm_dmix.Plo + -rm -f ./$(DEPDIR)/pcm_dshare.Plo + -rm -f ./$(DEPDIR)/pcm_dsnoop.Plo + -rm -f ./$(DEPDIR)/pcm_empty.Plo + -rm -f ./$(DEPDIR)/pcm_extplug.Plo + -rm -f ./$(DEPDIR)/pcm_file.Plo + -rm -f ./$(DEPDIR)/pcm_generic.Plo + -rm -f ./$(DEPDIR)/pcm_hooks.Plo + -rm -f ./$(DEPDIR)/pcm_hw.Plo + -rm -f ./$(DEPDIR)/pcm_iec958.Plo + -rm -f ./$(DEPDIR)/pcm_ioplug.Plo + -rm -f ./$(DEPDIR)/pcm_ladspa.Plo + -rm -f ./$(DEPDIR)/pcm_lfloat.Plo + -rm -f ./$(DEPDIR)/pcm_linear.Plo + -rm -f ./$(DEPDIR)/pcm_meter.Plo + -rm -f ./$(DEPDIR)/pcm_misc.Plo + -rm -f ./$(DEPDIR)/pcm_mmap.Plo + -rm -f ./$(DEPDIR)/pcm_mmap_emul.Plo + -rm -f ./$(DEPDIR)/pcm_mulaw.Plo + -rm -f ./$(DEPDIR)/pcm_multi.Plo + -rm -f ./$(DEPDIR)/pcm_null.Plo + -rm -f ./$(DEPDIR)/pcm_params.Plo + -rm -f ./$(DEPDIR)/pcm_plug.Plo + -rm -f ./$(DEPDIR)/pcm_plugin.Plo + -rm -f ./$(DEPDIR)/pcm_rate.Plo + -rm -f ./$(DEPDIR)/pcm_rate_linear.Plo + -rm -f ./$(DEPDIR)/pcm_route.Plo + -rm -f ./$(DEPDIR)/pcm_share.Plo + -rm -f ./$(DEPDIR)/pcm_shm.Plo + -rm -f ./$(DEPDIR)/pcm_simple.Plo + -rm -f ./$(DEPDIR)/pcm_softvol.Plo + -rm -f ./$(DEPDIR)/pcm_symbols.Plo + -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: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags ctags-am 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-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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/interval.c b/src/pcm/interval.c new file mode 100644 index 0000000..ef4c2ed --- /dev/null +++ b/src/pcm/interval.c @@ -0,0 +1,447 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define SND_INTERVAL_C +#define SND_INTERVAL_INLINE + +#include +#include +#include "pcm_local.h" + +static inline void div64_32(uint64_t *n, uint32_t d, uint32_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) +{ + uint64_t n = (uint64_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) +{ + const unsigned int last_max = i->max; + + if (snd_interval_empty(i)) + return -ENOENT; + if (snd_interval_single(i)) + return 0; + i->max = i->min; + if (i->openmin) + i->max++; + /* only exclude max value if also excluded before refine */ + i->openmax = (i->openmax && i->max >= last_max); + return 1; +} + +int snd_interval_refine_last(snd_interval_t *i) +{ + const unsigned int last_min = i->min; + + if (snd_interval_empty(i)) + return -ENOENT; + if (snd_interval_single(i)) + return 0; + i->min = i->max; + if (i->openmax) + i->min--; + /* only exclude min value if also excluded before refine */ + i->openmin = (i->openmin && i->min <= last_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..04996c9 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..d9a30b2 --- /dev/null +++ b/src/pcm/interval_inline.h @@ -0,0 +1,159 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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->openmin || i->openmax))); +} + +INTERVAL_INLINE int snd_interval_value(const snd_interval_t *i) +{ + assert(snd_interval_single(i)); + if (i->openmin && !i->openmax) + return i->max; + 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..f85357c --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..7f30587 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..75ad359 --- /dev/null +++ b/src/pcm/mask_inline.h @@ -0,0 +1,300 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#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(uint32_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(uint32_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(uint32_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..1064044 --- /dev/null +++ b/src/pcm/pcm.c @@ -0,0 +1,8766 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 different +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_PREPARED +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 use 32-bit physical space, but the sample is +stored in the lower three bytes. 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 this 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_mmap_writei(), #snd_pcm_mmap_readn() +and #snd_pcm_mmap_writen() functions. These functions use +#snd_pcm_areas_copy() internally. + +\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 PREPARED 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_thread_safety Thread-safety + +When the library is configured with the proper option, some PCM functions +(e.g. #snd_pcm_avail_update()) are thread-safe and can be called concurrently +from multiple threads. Meanwhile, some functions (e.g. #snd_pcm_hw_params()) +aren't thread-safe, and application needs to call them carefully when they +are called from multiple threads. In general, all the functions that are +often called during streaming are covered as thread-safe. + +This thread-safe behavior can be disabled also by passing 0 to the environment +variable LIBASOUND_THREAD_SAFE, e.g. +\code +LIBASOUND_THREAD_SAFE=0 aplay foo.wav +\endcode +for making the debugging easier. + +\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" + +#ifndef DOC_HIDDEN +/* return specific error codes for known bad PCM states */ +static int pcm_state_to_error(snd_pcm_state_t state) +{ + switch (state) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return 0; + } +} + +#define P_STATE(x) (1U << SND_PCM_STATE_ ## x) +#define P_STATE_RUNNABLE (P_STATE(PREPARED) | \ + P_STATE(RUNNING) | \ + P_STATE(XRUN) | \ + P_STATE(PAUSED) | \ + P_STATE(DRAINING)) + +/* check whether the PCM is in the unexpected state */ +static int bad_pcm_state(snd_pcm_t *pcm, unsigned int supported_states) +{ + snd_pcm_state_t state; + int err; + + if (pcm->own_state_check) + return 0; /* don't care, the plugin checks by itself */ + state = snd_pcm_state(pcm); + if (supported_states & (1U << state)) + return 0; /* OK */ + err = pcm_state_to_error(state); + if (err < 0) + return err; + return -EBADFD; +} +#endif + +/** + * \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); + } + if (pcm->ops->close) + err = pcm->ops->close(pcm->op_arg); + else + err = -ENOSYS; + 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, 2 = abort + * \return 0 on success otherwise a negative error code + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) +{ + int err = 0; + + assert(pcm); + /* FIXME: __snd_pcm_lock() call below is commented out because of the + * the possible deadlock in signal handler calling snd_pcm_abort() + */ + /* __snd_pcm_lock(pcm->op_arg); */ /* forced lock due to pcm field change */ + if (pcm->ops->nonblock) + err = pcm->ops->nonblock(pcm->op_arg, nonblock); + else + err = -ENOSYS; + if (err < 0) + goto unlock; + if (nonblock == 2) { + pcm->mode |= SND_PCM_ABORT; + goto unlock; + } + if (nonblock) + pcm->mode |= SND_PCM_NONBLOCK; + else { + if (pcm->hw_flags & SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP) + err = -EINVAL; + else + pcm->mode &= ~SND_PCM_NONBLOCK; + } + unlock: + /* __snd_pcm_unlock(pcm->op_arg); */ /* FIXME: see above */ + return err; +} + +#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) +{ + int err = 0; + + assert(pcm); + if (sig == 0) + sig = SIGIO; + if (pid == 0) + pid = getpid(); + +#ifdef THREAD_SAFE_API + /* async handler may lead to a deadlock; suppose no multi thread */ + pcm->lock_enabled = 0; +#endif + if (pcm->ops->async) + err = pcm->ops->async(pcm->op_arg, sig, pid); + else + err = -ENOSYS; + return err; +} +#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) +{ + int err = 0; + + assert(pcm && info); + if (pcm->ops->info) + err = pcm->ops->info(pcm->op_arg, info); + else + err = -ENOSYS; + return err; +} + +/** \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. If no mutually + * compatible set of parameters can be chosen, a negative error code + * will be returned. + * + * 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. + * + * The configuration space will be updated to reflect the chosen + * parameters. + */ +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_internal(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); + if (pcm->ops->hw_free) + err = pcm->ops->hw_free(pcm->op_arg); + else + err = -ENOSYS; + 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). + * + * The function is thread-safe when built with the proper option. + */ +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 + __snd_pcm_lock(pcm->op_arg); /* forced lock due to pcm field change */ + if (pcm->ops->sw_params) + err = pcm->ops->sw_params(pcm->op_arg, params); + else + err = -ENOSYS; + if (err < 0) { + __snd_pcm_unlock(pcm->op_arg); + return err; + } + pcm->tstamp_mode = params->tstamp_mode; + pcm->tstamp_type = params->tstamp_type; + pcm->period_step = params->period_step; + pcm->avail_min = params->avail_min; + pcm->period_event = sw_get_period_event(params); + 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; + __snd_pcm_unlock(pcm->op_arg); + 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 + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status) +{ + int err; + + assert(pcm && status); + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->status) + err = pcm->fast_ops->status(pcm->fast_op_arg, status); + else + err = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm) +{ + snd_pcm_state_t state; + + assert(pcm); + snd_pcm_lock(pcm->fast_op_arg); + state = __snd_pcm_state(pcm); + snd_pcm_unlock(pcm->fast_op_arg); + return state; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + * + * This function is deprecated. Use #snd_pcm_avail_update() instead. + */ +int snd_pcm_hwsync(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_hwsync(pcm); + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_delay(pcm, delayp); + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_resume(snd_pcm_t *pcm) +{ + int err = 0; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + /* lock handled in the callback */ + if (pcm->fast_ops->resume) + err = pcm->fast_ops->resume(pcm->fast_op_arg); + else + err = -ENOSYS; + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, snd_htimestamp_t *tstamp) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->htimestamp) + err = pcm->fast_ops->htimestamp(pcm->fast_op_arg, avail, tstamp); + else + err = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \brief Prepare PCM for use + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_prepare(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, ~P_STATE(DISCONNECTED)); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->prepare) + err = pcm->fast_ops->prepare(pcm->fast_op_arg); + else + err = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \brief Reset PCM position + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * Reduce PCM delay to 0. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_reset(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->reset) + err = pcm->fast_ops->reset(pcm->fast_op_arg); + else + err = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \brief Start a PCM + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_start(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, P_STATE(PREPARED)); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_start(pcm); + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_drop(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE | P_STATE(SETUP) | + P_STATE(SUSPENDED)); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->drop) + err = pcm->fast_ops->drop(pcm->fast_op_arg); + else + err = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_drain(snd_pcm_t *pcm) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + /* lock handled in the callback */ + if (pcm->fast_ops->drain) + err = pcm->fast_ops->drain(pcm->fast_op_arg); + else + err = -ENOSYS; + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_pause(snd_pcm_t *pcm, int enable) +{ + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->pause) + err = pcm->fast_ops->pause(pcm->fast_op_arg, enable); + else + err = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t result; + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->rewindable) + result = pcm->fast_ops->rewindable(pcm->fast_op_arg); + else + result = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} + +/** + * \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 + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + snd_pcm_sframes_t result; + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (frames == 0) + return 0; + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->rewind) + result = pcm->fast_ops->rewind(pcm->fast_op_arg, frames); + else + result = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_forwardable(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t result; + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->forwardable) + result = pcm->fast_ops->forwardable(pcm->fast_op_arg); + else + result = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} + +/** + * \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 + * + * The function is thread-safe when built with the proper option. + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +{ + snd_pcm_sframes_t result; + int err; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (frames == 0) + return 0; + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + if (pcm->fast_ops->forward) + result = pcm->fast_ops->forward(pcm->fast_op_arg, frames); + else + result = -ENOSYS; + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} +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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) +{ + int err; + + 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; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + 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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + int err; + + 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; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + 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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) +{ + int err; + + 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; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + 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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) +{ + int err; + + 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; + } + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + 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) +{ + int err = 0; + + assert(pcm1); + assert(pcm2); + if (pcm1->fast_ops->link) + err = pcm1->fast_ops->link(pcm1, pcm2); + else + err = -ENOSYS; + return err; +} + +/** + * \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) +{ + int err = 0; + + assert(pcm); + if (pcm->fast_ops->unlink) + err = pcm->fast_ops->unlink(pcm); + else + err = -ENOSYS; + return err; +} + +/* locked version */ +static int __snd_pcm_poll_descriptors_count(snd_pcm_t *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 count of poll descriptors for PCM handle + * \param pcm PCM handle + * \return count of poll descriptors + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm) +{ + int count; + + assert(pcm); + snd_pcm_lock(pcm->fast_op_arg); + count = __snd_pcm_poll_descriptors_count(pcm); + snd_pcm_unlock(pcm->fast_op_arg); + return count; +} + +/* locked version */ +static int __snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, + unsigned int space) +{ + 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 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 . + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + int err; + + assert(pcm && pfds); + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_poll_descriptors(pcm, pfds, space); + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +static int __snd_pcm_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, + unsigned int nfds, unsigned short *revents); + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + int err; + + assert(pcm && pfds && revents); + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_poll_revents(pcm, pfds, nfds, revents); + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +static int __snd_pcm_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, + unsigned int nfds, unsigned short *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 TSTAMP_TYPE(v) [SND_PCM_TSTAMP_TYPE_##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(S20_LE), + FORMAT(S20_BE), + FORMAT(U20_LE), + FORMAT(U20_BE), + 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), + FORMAT(G723_24), + FORMAT(G723_24_1B), + FORMAT(G723_40), + FORMAT(G723_40_1B), + FORMAT(DSD_U8), + FORMAT(DSD_U16_LE), + FORMAT(DSD_U32_LE), + FORMAT(DSD_U16_BE), + FORMAT(DSD_U32_BE), +}; + +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), + FORMAT(S20), + FORMAT(U20), +}; + +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(S20_LE, "Signed 20 bit Little Endian in 4 bytes, LSB justified"), + FORMATD(S20_BE, "Signed 20 bit Big Endian in 4 bytes, LSB justified"), + FORMATD(U20_LE, "Unsigned 20 bit Little Endian in 4 bytes, LSB justified"), + FORMATD(U20_BE, "Unsigned 20 bit Big Endian in 4 bytes, LSB justified"), + 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"), + FORMATD(G723_24, "G.723 (ADPCM) 24 kbit/s, 8 samples in 3 bytes"), + FORMATD(G723_24_1B, "G.723 (ADPCM) 24 kbit/s, 1 sample in 1 byte"), + FORMATD(G723_40, "G.723 (ADPCM) 40 kbit/s, 8 samples in 3 bytes"), + FORMATD(G723_40_1B, "G.723 (ADPCM) 40 kbit/s, 1 sample in 1 byte"), + FORMATD(DSD_U8, "Direct Stream Digital, 1-byte (x8), oldest bit in MSB"), + FORMATD(DSD_U16_LE, "Direct Stream Digital, 2-byte (x16), little endian, oldest bits in MSB"), + FORMATD(DSD_U32_LE, "Direct Stream Digital, 4-byte (x32), little endian, oldest bits in MSB"), + FORMATD(DSD_U16_BE, "Direct Stream Digital, 2-byte (x16), big endian, oldest bits in MSB"), + FORMATD(DSD_U32_BE, "Direct Stream Digital, 4-byte (x32), big endian, oldest bits in MSB"), +}; + +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), +}; + +static const char *const snd_pcm_tstamp_type_names[] = { + TSTAMP_TYPE(GETTIMEOFDAY), + TSTAMP_TYPE(MONOTONIC), + TSTAMP_TYPE(MONOTONIC_RAW), +}; +#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(const 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(const 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(const 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(const 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(const 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(const 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(const 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 tstamp type setting + * \param mode PCM tstamp type + * \return ascii name of PCM tstamp type setting + */ +const char *snd_pcm_tstamp_type_name(snd_pcm_tstamp_type_t type) +{ + if (type > SND_PCM_TSTAMP_TYPE_LAST) + return NULL; + return snd_pcm_tstamp_type_names[type]; +} + +/** + * \brief get name of PCM state + * \param state PCM state + * \return ascii name of PCM state + */ +const char *snd_pcm_state_name(const 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 +EXPORT_SYMBOL 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, " tstamp_type : %s\n", snd_pcm_tstamp_type_name(pcm->tstamp_type)); + 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 / 1000); + snd_output_printf(out, " tstamp : %ld.%06ld\n", + status->tstamp.tv_sec, status->tstamp.tv_nsec / 1000); + 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) +{ + int err = 0; + + assert(pcm); + assert(out); + if (pcm->ops->dump) + pcm->ops->dump(pcm->op_arg, out); + else + err = -ENOSYS; + return err; +} + +/** + * \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); + 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) { + 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) { + if ((*pcmp)->open_func) { + /* only init plugin (like empty, asym) */ + snd_dlobj_cache_put(open_func); + } else { + (*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) +{ + snd_config_t *top; + int err; + + assert(pcmp && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_pcm_open_noupdate(pcmp, top, name, stream, mode, 0); + snd_config_unref(top); + return err; +} + +/** + * \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); +} + +/** + * \brief Opens a fallback PCM + * \param pcmp Returned PCM handle + * \param root Configuration root + * \param name ASCII identifier of the PCM handle + * \param orig_name The original ASCII name + * \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_fallback(snd_pcm_t **pcmp, snd_config_t *root, + const char *name, const char *orig_name, + snd_pcm_stream_t stream, int mode) +{ + int err; + assert(pcmp && name && root); + err = snd_pcm_open_noupdate(pcmp, root, name, stream, mode, 0); + if (err >= 0) { + free((*pcmp)->name); + (*pcmp)->name = orig_name ? strdup(orig_name) : NULL; + } + return err; +} + +#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; +#ifdef THREAD_SAFE_API + pthread_mutexattr_t attr; +#endif + + 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); +#ifdef THREAD_SAFE_API + pthread_mutexattr_init(&attr); +#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif + pthread_mutex_init(&pcm->lock, &attr); + /* use locking as default; + * each plugin may suppress this in its open call + */ + pcm->need_lock = 1; + if (mode & SND_PCM_ASYNC) { + /* async handler may lead to a deadlock; suppose no MT */ + pcm->lock_enabled = 0; + } else { + /* set lock_enabled field depending on $LIBASOUND_THREAD_SAFE */ + static int do_lock_enable = -1; /* uninitialized */ + + /* evaluate env var only once at the first open for consistency */ + if (do_lock_enable == -1) { + char *p = getenv("LIBASOUND_THREAD_SAFE"); + do_lock_enable = !p || *p != '0'; + } + pcm->lock_enabled = do_lock_enable; + } +#endif + *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); +#ifdef THREAD_SAFE_API + pthread_mutex_destroy(&pcm->lock); +#endif + 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 + * + * The function is thread-safe when built with the proper option. + */ +int snd_pcm_wait(snd_pcm_t *pcm, int timeout) +{ + int err; + + __snd_pcm_lock(pcm->fast_op_arg); /* forced lock */ + err = __snd_pcm_wait_in_lock(pcm, timeout); + __snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +#ifndef DOC_HIDDEN +/* locked version */ +int __snd_pcm_wait_in_lock(snd_pcm_t *pcm, int timeout) +{ + int err; + + /* NOTE: avail_min check can be skipped during draining */ + if (__snd_pcm_state(pcm) != SND_PCM_STATE_DRAINING && + !snd_pcm_may_wait_for_avail_min(pcm, snd_pcm_mmap_avail(pcm))) { + /* check more precisely */ + err = pcm_state_to_error(__snd_pcm_state(pcm)); + return err < 0 ? err : 1; + } + return snd_pcm_wait_nocheck(pcm, timeout); +} + +/* + * like snd_pcm_wait() but doesn't check mmap_avail before calling poll() + * + * used in drain code in some plugins + * + * This function is called inside pcm lock. + */ +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 { + __snd_pcm_unlock(pcm->fast_op_arg); + err_poll = poll(pfd, npfds, timeout); + __snd_pcm_lock(pcm->fast_op_arg); + if (err_poll < 0) { + if (errno == EINTR && !PCMINABORT(pcm)) + continue; + return -errno; + } + if (! err_poll) + break; + err = __snd_pcm_poll_revents(pcm, pfd, npfds, &revents); + if (err < 0) + return err; + if (revents & (POLLERR | POLLNVAL)) { + /* check more precisely */ + err = pcm_state_to_error(__snd_pcm_state(pcm)); + return err < 0 ? err : -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). + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t result; + + snd_pcm_lock(pcm->fast_op_arg); + result = __snd_pcm_avail_update(pcm); + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm) +{ + int err; + snd_pcm_sframes_t result; + + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_hwsync(pcm); + if (err < 0) + result = err; + else + result = __snd_pcm_avail_update(pcm); + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +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; + } + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_hwsync(pcm); + if (err < 0) + goto unlock; + sf = __snd_pcm_avail_update(pcm); + if (sf < 0) { + err = (int)sf; + goto unlock; + } + err = __snd_pcm_delay(pcm, delayp); + if (err < 0) + goto unlock; + *availp = sf; + err = 0; + unlock: + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +/** + * \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; + uint64_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); + /* + * Iterate copying silent sample for sample data aligned to 64 bit. + * This is a fast path. + */ + if (dst_area->step == (unsigned int) width && + width != 24 && + ((intptr_t)dst & 7) == 0) { + unsigned int dwords = samples * width / 64; + uint64_t *dstp = (uint64_t *)dst; + samples -= dwords * 64 / width; + while (dwords-- > 0) + *dstp++ = silence; + if (samples == 0) + return 0; + dst = (char *)dstp; + } + dst_step = dst_area->step / 8; + switch (width) { + case 4: { + uint8_t s0 = silence & 0xf0; + uint8_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: { + uint8_t sil = silence; + while (samples-- > 0) { + *dst = sil; + dst += dst_step; + } + break; + } + case 16: { + uint16_t sil = silence; + while (samples-- > 0) { + *(uint16_t*)dst = sil; + dst += dst_step; + } + break; + } + case 24: { + while (samples-- > 0) { +#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 + dst += dst_step; + } + } + break; + case 32: { + uint32_t sil = silence; + while (samples-- > 0) { + *(uint32_t*)dst = sil; + dst += dst_step; + } + break; + } + case 64: { + while (samples-- > 0) { + *(uint64_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; + assert(src < dst || src >= dst + bytes); + assert(dst < src || dst >= src + bytes); + 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) { + *(uint16_t*)dst = *(const uint16_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) { + *(uint32_t*)dst = *(const uint32_t*)src; + src += src_step; + dst += dst_step; + } + break; + } + case 64: { + while (samples-- > 0) { + *(uint64_t*)dst = *(const uint64_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) { + if (src_offset != dst_offset || + src_start->addr != dst_start->addr || + src_start->first != dst_start->first) { + /* 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; +} + +/** + * \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 dst_size size in frames of the destination buffer + * \param src_areas source areas specification (one for each channel) + * \param src_offset offset in frames inside source area + * \param dst_size size in frames of the source buffer + * \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_wrap(const snd_pcm_channel_area_t *dst_channels, + snd_pcm_uframes_t dst_offset, + const snd_pcm_uframes_t dst_size, + const snd_pcm_channel_area_t *src_channels, + snd_pcm_uframes_t src_offset, + const snd_pcm_uframes_t src_size, + const unsigned int channels, + snd_pcm_uframes_t frames, + const snd_pcm_format_t format) +{ + while (frames > 0) { + int err; + snd_pcm_uframes_t xfer = frames; + /* do not write above the destination buffer */ + if ((dst_offset + xfer) > dst_size) + xfer = dst_size - dst_offset; + /* do not read from above the source buffer */ + if ((src_offset + xfer) > src_size) + xfer = src_size - src_offset; + err = snd_pcm_areas_copy(dst_channels, dst_offset, src_channels, + src_offset, channels, xfer, format); + if (err < 0) + return err; + + dst_offset += xfer; + if (dst_offset >= dst_size) + dst_offset = 0; + src_offset += xfer; + if (src_offset >= src_size) + src_offset = 0; + frames -= xfer; + } + + 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 + * \retval 0 Hardware doesn't support sample-resolution mmap + * \retval 1 Hardware supports sample-resolution mmap + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't do double buffering for start/stop + * \retval 1 Hardware does double buffering for start/stop + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't do double buffering for data transfers + * \retval 1 Hardware does double buffering for data transfers + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't block transfers + * \retval 1 Hardware does block transfers + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Device doesn't do monotomic timestamps + * \retval 1 Device does monotonic timestamps + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't support overrange detection + * \retval 1 Hardware supports overrange detection + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't support pause + * \retval 1 Hardware supports pause + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't support resume + * \retval 1 Hardware supports resume + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't do half-duplex + * \retval 1 Hardware does half-duplex + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't do joint-duplex + * \retval 1 Hardware does joint-duplex + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \retval 0 Hardware doesn't support synchronized start + * \retval 1 Hardware supports synchronized start + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * \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 Check if hardware supports audio wallclock timestamps + * \param params Configuration space + * \retval 0 Hardware doesn't support audio wallclock timestamps + * \retval 1 Hardware supports audio wallclock timestamps + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single configuration from the configuration space. + */ +int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params) +{ + /* deprecated */ + return snd_pcm_hw_params_supports_audio_ts_type(params, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT); +} + +/** + * \brief Check if hardware supports type of audio timestamps + * \param params Configuration space + * \param type Audio timestamp type + * \retval 0 Hardware doesn't support type of audio timestamps + * \retval 1 Hardware supports type of audio timestamps + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single configuration from the configuration space. + */ +int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + switch (type) { + case SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT: + return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK); /* deprecated */ + case SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT: + return 1; /* always supported, based on hw_ptr */ + case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK: + return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ATIME); + case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE: + return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME); + case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED: + return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME); + case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED: + return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME); + default: + return 0; + } +} + +/** + * \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 + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 hardware 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 + * + * This function should only be called when the configuration space + * contains a single configuration. Call #snd_pcm_hw_params to choose + * a single 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 + * + * The configuration space will be filled with all possible ranges + * for the PCM device. + */ +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 the configuration space does not contain a single value + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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; + params->rmask = ~0; + 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 to be 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; + params->rmask = ~0; + 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; + params->rmask = ~0; + + 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 the configuration space does not contain a single value + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +#ifndef DOXYGEN +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 the configuration space does not contain a single value + */ +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 + * + * The function is thread-safe when built with the proper option. + */ +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; + } + __snd_pcm_lock(pcm); /* forced lock due to pcm field changes */ + params->proto = SNDRV_PCM_VERSION; + params->tstamp_mode = pcm->tstamp_mode; + params->tstamp_type = pcm->tstamp_type; + params->period_step = pcm->period_step; + params->sleep_min = 0; + params->avail_min = pcm->avail_min; + sw_set_period_event(params, 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; + __snd_pcm_unlock(pcm); + 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, "tstamp_type: %s\n", snd_pcm_tstamp_type_name(params->tstamp_type)); + 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 +EXPORT_SYMBOL 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 Set timestamp type inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Timestamp type + * \return 0 otherwise a negative error code + */ +int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val) +{ + assert(pcm && params); + if (CHECK_SANITY(val > SND_PCM_TSTAMP_TYPE_LAST)) { + SNDMSG("invalid tstamp_type value %d", val); + return -EINVAL; + } + params->tstamp_type = val; + return 0; +} + +/** + * \brief Get timestamp type from a software configuration container + * \param params Software configuration container + * \param val Returned timestamp type + * \return 0 otherwise a negative error code + */ +int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val) +{ + assert(params && val); + *val = params->tstamp_type; + 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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); + sw_set_period_event(params, 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 = sw_get_period_event(params); + 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 "now" hi-res audio timestamp from a PCM status container + * \param obj pointer to #snd_pcm_status_t + * \param ptr Pointer to returned timestamp + */ +void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr) +{ + assert(obj && ptr); + *ptr = obj->audio_tstamp; +} + +/** + * \brief Get "now" hi-res driver timestamp from a PCM status container. Defines when the status + * was generated by driver, may differ from normal timestamp. + * \param obj pointer to #snd_pcm_status_t + * \param ptr Pointer to returned timestamp + */ +void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr) +{ + assert(obj && ptr); + *ptr = obj->driver_tstamp; +} + +/** + * \brief Get audio_tstamp_report from a PCM status container + * \param obj pointer to #snd_pcm_status_t + * \param ptr Pointer to returned report (valid fields are accuracy and type) + */ +void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj, + snd_pcm_audio_tstamp_report_t *audio_tstamp_report) +{ + assert(obj && audio_tstamp_report); + snd_pcm_unpack_audio_tstamp_report(obj->audio_tstamp_data, + obj->audio_tstamp_accuracy, + audio_tstamp_report); +} + +/** + * \brief set audio_tstamp_config from a PCM status container + * \param obj pointer to #snd_pcm_status_t + * \param ptr Pointer to config (valid fields are type and report_analog_delay) + */ +void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj, + snd_pcm_audio_tstamp_config_t *audio_tstamp_config) +{ + assert(obj && audio_tstamp_config); + snd_pcm_pack_audio_tstamp_config(&obj->audio_tstamp_data, audio_tstamp_config); +} + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +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) +{ + int err; + + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + err = __snd_pcm_mmap_begin(pcm, areas, offset, frames); + snd_pcm_unlock(pcm->fast_op_arg); + return err; +} + +#ifndef DOC_HIDDEN +/* locked version */ +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); + + if (pcm->fast_ops->mmap_begin) + return pcm->fast_ops->mmap_begin(pcm->fast_op_arg, areas, offset, frames); + + /* fallback for plugins that do not specify new callback */ + 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; +} +#endif + +/** + * \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. + * + * The function is thread-safe when built with the proper option. + */ +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 result; + int err; + + err = bad_pcm_state(pcm, P_STATE_RUNNABLE); + if (err < 0) + return err; + snd_pcm_lock(pcm->fast_op_arg); + result = __snd_pcm_mmap_commit(pcm, offset, frames); + snd_pcm_unlock(pcm->fast_op_arg); + return result; +} + +#ifndef DOC_HIDDEN +/* locked version*/ +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; + } + if (pcm->fast_ops->mmap_commit) + return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames); + else + return -ENOSYS; +} + +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; + + snd_pcm_lock(pcm); + channels = pcm->channels; + for (channel = 0; channel < channels; ++channel, ++areas) { + areas->addr = buf; + areas->first = channel * pcm->sample_bits; + areas->step = pcm->frame_bits; + } + snd_pcm_unlock(pcm); +} + +void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, + void **bufs) +{ + unsigned int channel; + unsigned int channels; + + snd_pcm_lock(pcm); + channels = pcm->channels; + for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) { + areas->addr = *bufs; + areas->first = 0; + areas->step = pcm->sample_bits; + } + snd_pcm_unlock(pcm); +} + +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; + + __snd_pcm_lock(pcm->fast_op_arg); /* forced lock */ + 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; + default: + err = pcm_state_to_error(state); + if (!err) + 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_in_lock(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: + __snd_pcm_unlock(pcm->fast_op_arg); + 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; + + __snd_pcm_lock(pcm->fast_op_arg); /* forced lock */ + 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; + default: + err = pcm_state_to_error(state); + if (!err) + err = -EBADFD; + goto _end; + } + avail = __snd_pcm_avail_update(pcm); + if (avail < 0) { + err = avail; + goto _end; + } + if (state == SND_PCM_STATE_RUNNING && + size > (snd_pcm_uframes_t)avail) { + if (snd_pcm_may_wait_for_avail_min(pcm, avail)) { + if (pcm->mode & SND_PCM_NONBLOCK) { + err = -EAGAIN; + goto _end; + } + + err = snd_pcm_wait_nocheck(pcm, -1); + if (err < 0) + break; + goto _again; + } + /* the snd_pcm_may_wait_for_avail_min may check against the + * updated hw.ptr (slaves), get the avail again here + */ + avail = __snd_pcm_avail_update(pcm); + if (avail < 0) { + err = avail; + goto _end; + } + } + 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: + __snd_pcm_unlock(pcm->fast_op_arg); + 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; +} + +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 */ + +static int chmap_equal(const snd_pcm_chmap_t *a, const snd_pcm_chmap_t *b) +{ + if (a->channels != b->channels) + return 0; + return !memcmp(a->pos, b->pos, a->channels * sizeof(a->pos[0])); +} + +/** + * \!brief Query the available channel maps + * \param pcm PCM handle to query + * \return the NULL-terminated array of integer pointers, each of + * which contains the channel map. A channel map is represented by an + * integer array, beginning with the channel map type, followed by the + * number of channels, and the position of each channel. Return NULL + * in case of an error. + * + * Note: the caller is requested to release the returned value via + * snd_pcm_free_chmaps(). + */ +snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm) +{ + if (!pcm->ops->query_chmaps) + return NULL; + return pcm->ops->query_chmaps(pcm); +} + +/** + * \!brief Release the channel map array allocated via #snd_pcm_query_chmaps + * \param maps the array pointer to release + */ +void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps) +{ + snd_pcm_chmap_query_t **p; + if (!maps) + return; + for (p = maps; *p; p++) + free(*p); + free(maps); +} + +/** + * \!brief Get the current channel map + * \param pcm PCM instance + * \return the current channel map, or NULL if error + * + * Note: the caller is requested to release the returned value via free() + */ +snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm) +{ + if (!pcm->ops->get_chmap) + return NULL; + return pcm->ops->get_chmap(pcm); +} + +/** + * \!brief Configure the current channel map + * \param pcm PCM instance + * \param map the channel map to write + * \return zero if succeeded, or a negative error code + */ +int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + const snd_pcm_chmap_t *oldmap; + int nochange; + + oldmap = snd_pcm_get_chmap(pcm); + nochange = (oldmap && chmap_equal(oldmap, map)); + free((void *)oldmap); + if (nochange) + return 0; + + if (!pcm->ops->set_chmap) + return -ENXIO; + return pcm->ops->set_chmap(pcm, map); +} + +/* + */ +#ifndef DOC_HIDDEN +#define _NAME(n) [SND_CHMAP_TYPE_##n] = #n +static const char *chmap_type_names[SND_CHMAP_TYPE_LAST + 1] = { + _NAME(NONE), _NAME(FIXED), _NAME(VAR), _NAME(PAIRED), +}; +#undef _NAME +#endif + +/** + * \!brief Get a name string for a channel map type as query results + * \param val Channel position + * \return The string corresponding to the given type, or NULL + */ +const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val) +{ + if (val <= SND_CHMAP_TYPE_LAST) + return chmap_type_names[val]; + else + return NULL; +} + +#ifndef DOC_HIDDEN +#define _NAME(n) [SND_CHMAP_##n] = #n +static const char *chmap_names[SND_CHMAP_LAST + 1] = { + _NAME(UNKNOWN), _NAME(NA), _NAME(MONO), + _NAME(FL), _NAME(FR), + _NAME(RL), _NAME(RR), + _NAME(FC), _NAME(LFE), + _NAME(SL), _NAME(SR), + _NAME(RC), _NAME(FLC), _NAME(FRC), _NAME(RLC), _NAME(RRC), + _NAME(FLW), _NAME(FRW), + _NAME(FLH), _NAME(FCH), _NAME(FRH), _NAME(TC), + _NAME(TFL), _NAME(TFR), _NAME(TFC), + _NAME(TRL), _NAME(TRR), _NAME(TRC), + _NAME(TFLC), _NAME(TFRC), _NAME(TSL), _NAME(TSR), + _NAME(LLFE), _NAME(RLFE), + _NAME(BC), _NAME(BLC), _NAME(BRC), +}; +#undef _NAME +#endif + +/** + * \!brief Get a name string for a standard channel map position + * \param val Channel position + * \return The string corresponding to the given position, or NULL + */ +const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val) +{ + if (val <= SND_CHMAP_LAST) + return chmap_names[val]; + else + return NULL; +} + +static const char *chmap_long_names[SND_CHMAP_LAST + 1] = { + [SND_CHMAP_UNKNOWN] = "Unknown", + [SND_CHMAP_NA] = "Unused", + [SND_CHMAP_MONO] = "Mono", + [SND_CHMAP_FL] = "Front Left", + [SND_CHMAP_FR] = "Front Right", + [SND_CHMAP_RL] = "Rear Left", + [SND_CHMAP_RR] = "Rear Right", + [SND_CHMAP_FC] = "Front Center", + [SND_CHMAP_LFE] = "LFE", + [SND_CHMAP_SL] = "Side Left", + [SND_CHMAP_SR] = "Side Right", + [SND_CHMAP_RC] = "Rear Center", + [SND_CHMAP_FLC] = "Front Left Center", + [SND_CHMAP_FRC] = "Front Right Center", + [SND_CHMAP_RLC] = "Rear Left Center", + [SND_CHMAP_RRC] = "Rear Right Center", + [SND_CHMAP_FLW] = "Front Left Wide", + [SND_CHMAP_FRW] = "Front Right Wide", + [SND_CHMAP_FLH] = "Front Left High", + [SND_CHMAP_FCH] = "Front Center High", + [SND_CHMAP_FRH] = "Front Right High", + [SND_CHMAP_TC] = "Top Center", + [SND_CHMAP_TFL] = "Top Front Left", + [SND_CHMAP_TFR] = "Top Front Right", + [SND_CHMAP_TFC] = "Top Front Center", + [SND_CHMAP_TRL] = "Top Rear Left", + [SND_CHMAP_TRR] = "Top Rear Right", + [SND_CHMAP_TRC] = "Top Rear Center", + [SND_CHMAP_TFLC] = "Top Front Left Center", + [SND_CHMAP_TFRC] = "Top Front Right Center", + [SND_CHMAP_TSL] = "Top Side Left", + [SND_CHMAP_TSR] = "Top Side Right", + [SND_CHMAP_LLFE] = "Left LFE", + [SND_CHMAP_RLFE] = "Right LFE", + [SND_CHMAP_BC] = "Bottom Center", + [SND_CHMAP_BLC] = "Bottom Left Center", + [SND_CHMAP_BRC] = "Bottom Right Center", +}; + +/** + * \!brief Get a longer name string for a standard channel map position + * \param val Channel position + * \return The string corresponding to the given position, or NULL + */ +const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val) +{ + if (val <= SND_CHMAP_LAST) + return chmap_long_names[val]; + else + return NULL; +} + +/** + * \!brief Print the channels in chmap on the buffer + * \param map The channel map to print + * \param maxlen The maximal length to write (including NUL letter) + * \param buf The buffer to write + * \return The actual string length or a negative error code + */ +int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf) +{ + unsigned int i, len = 0; + + for (i = 0; i < map->channels; i++) { + unsigned int p = map->pos[i] & SND_CHMAP_POSITION_MASK; + if (i > 0) { + len += snprintf(buf + len, maxlen - len, " "); + if (len >= maxlen) + return -ENOMEM; + } + if (map->pos[i] & SND_CHMAP_DRIVER_SPEC) + len += snprintf(buf + len, maxlen - len, "%d", p); + else { + const char *name = chmap_names[p]; + if (name) + len += snprintf(buf + len, maxlen - len, + "%s", name); + else + len += snprintf(buf + len, maxlen - len, + "Ch%d", p); + } + if (len >= maxlen) + return -ENOMEM; + if (map->pos[i] & SND_CHMAP_PHASE_INVERSE) { + len += snprintf(buf + len, maxlen - len, "[INV]"); + if (len >= maxlen) + return -ENOMEM; + } + } + return len; +} + +static int str_to_chmap(const char *str, int len) +{ + int val; + unsigned long v; + char *p; + + if (isdigit(*str)) { + v = strtoul(str, &p, 0); + if (v == ULONG_MAX) + return -1; + val = v; + val |= SND_CHMAP_DRIVER_SPEC; + str = p; + } else if (!strncasecmp(str, "ch", 2)) { + v = strtoul(str + 2, &p, 0); + if (v == ULONG_MAX) + return -1; + val = v; + str = p; + } else { + for (val = 0; val <= SND_CHMAP_LAST; val++) { + int slen; + assert(chmap_names[val]); + slen = strlen(chmap_names[val]); + if (slen > len) + continue; + if (!strncasecmp(str, chmap_names[val], slen) && + !isalpha(str[slen])) { + str += slen; + break; + } + } + if (val > SND_CHMAP_LAST) + return -1; + } + if (str && !strncasecmp(str, "[INV]", 5)) + val |= SND_CHMAP_PHASE_INVERSE; + return val; +} + +/** + * \!brief Convert from string to channel position + * \param str The string to parse + * \return The channel position value or -1 as an error + */ +unsigned int snd_pcm_chmap_from_string(const char *str) +{ + return str_to_chmap(str, strlen(str)); +} + +/** + * \!brief Convert from string to channel map + * \param str The string to parse + * \return The channel map + * + * Note: the caller is requested to release the returned value via free() + */ +snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str) +{ + int i, ch = 0; + int tmp_map[64]; + snd_pcm_chmap_t *map; + + for (;;) { + const char *p; + int len, val; + + if (ch >= (int)(sizeof(tmp_map) / sizeof(tmp_map[0]))) + return NULL; + for (p = str; *p && isalnum(*p); p++) + ; + len = p - str; + if (!len) + return NULL; + val = str_to_chmap(str, len); + if (val < 0) + return NULL; + str += len; + if (*str == '[') { + if (!strncmp(str, "[INV]", 5)) { + val |= SND_CHMAP_PHASE_INVERSE; + str += 5; + } + } + tmp_map[ch] = val; + ch++; + for (; *str && !isalnum(*str); str++) + ; + if (!*str) + break; + } + map = malloc(sizeof(*map) + ch * sizeof(int)); + if (!map) + return NULL; + map->channels = ch; + for (i = 0; i < ch; i++) + map->pos[i] = tmp_map[i]; + return map; +} + +/* copy a single channel map with the fixed type to chmap_query pointer */ +static int _copy_to_fixed_query_map(snd_pcm_chmap_query_t **dst, + const snd_pcm_chmap_t *src) +{ + *dst = malloc((src->channels + 2) * sizeof(int)); + if (!*dst) + return -ENOMEM; + (*dst)->type = SND_CHMAP_TYPE_FIXED; + memcpy(&(*dst)->map, src, (src->channels + 1) * sizeof(int)); + return 0; +} + +#ifndef DOC_HIDDEN +/* make a chmap_query array from a single channel map */ +snd_pcm_chmap_query_t ** +_snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t *src) +{ + snd_pcm_chmap_query_t **maps; + + maps = calloc(2, sizeof(*maps)); + if (!maps) + return NULL; + if (_copy_to_fixed_query_map(maps, src)) { + free(maps); + return NULL; + } + return maps; +} + +/* make a copy of chmap */ +snd_pcm_chmap_t *_snd_pcm_copy_chmap(const snd_pcm_chmap_t *src) +{ + snd_pcm_chmap_t *map; + + map = malloc((src->channels + 1) * sizeof(int)); + if (!map) + return NULL; + memcpy(map, src, (src->channels + 1) * sizeof(int)); + return map; +} + +/* make a copy of channel maps */ +snd_pcm_chmap_query_t ** +_snd_pcm_copy_chmap_query(snd_pcm_chmap_query_t * const *src) +{ + snd_pcm_chmap_query_t * const *p; + snd_pcm_chmap_query_t **maps; + int i, nums; + + for (nums = 0, p = src; *p; p++) + nums++; + + maps = calloc(nums + 1, sizeof(*maps)); + if (!maps) + return NULL; + for (i = 0; i < nums; i++) { + maps[i] = malloc((src[i]->map.channels + 2) * sizeof(int)); + if (!maps[i]) { + snd_pcm_free_chmaps(maps); + return NULL; + } + memcpy(maps[i], src[i], (src[i]->map.channels + 2) * sizeof(int)); + } + return maps; +} + +/* select the channel map with the current PCM channels and make a copy */ +snd_pcm_chmap_t * +_snd_pcm_choose_fixed_chmap(snd_pcm_t *pcm, snd_pcm_chmap_query_t * const *maps) +{ + snd_pcm_chmap_query_t * const *p; + + for (p = maps; *p; p++) { + if ((*p)->map.channels == pcm->channels) + return _snd_pcm_copy_chmap(&(*p)->map); + } + return NULL; +} + +/* make chmap_query array from the config tree; + * conf must be a compound (array) + */ +snd_pcm_chmap_query_t ** +_snd_pcm_parse_config_chmaps(snd_config_t *conf) +{ + snd_pcm_chmap_t *chmap; + snd_pcm_chmap_query_t **maps; + snd_config_iterator_t i, next; + const char *str; + int nums, err; + + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) + return NULL; + + nums = 0; + snd_config_for_each(i, next, conf) { + nums++; + } + + maps = calloc(nums + 1, sizeof(*maps)); + if (!maps) + return NULL; + + nums = 0; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + err = snd_config_get_string(n, &str); + if (err < 0) + goto error; + chmap = snd_pcm_chmap_parse_string(str); + if (!chmap) + goto error; + if (_copy_to_fixed_query_map(maps + nums, chmap)) { + free(chmap); + goto error; + } + free(chmap); + nums++; + } + return maps; + + error: + snd_pcm_free_chmaps(maps); + return NULL; +} +#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_saved, params = {0}; + snd_pcm_sw_params_t swparams = {0}; + 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; + + assert(pcm); + /* choose all parameters */ + err = snd_pcm_hw_params_any(pcm, ¶ms); + 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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, 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, ¶ms, &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, rrate); + return -EINVAL; + } + /* set the buffer time */ + params_saved = params; + err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, ¶ms, + &latency, NULL); + if (err < 0) { + /* error path -> set period size as first */ + params = params_saved; + /* set the period time */ + period_time = latency / 4; + err = INTERNAL(snd_pcm_hw_params_set_period_time_near)(pcm, + ¶ms, &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)(¶ms, + &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, + ¶ms, &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)(¶ms, + &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)(¶ms, + &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)(¶ms, + &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, + ¶ms, &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)(¶ms, + &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, ¶ms); + 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 params = {0}; + int err; + + assert(pcm); + err = snd_pcm_hw_params_current(pcm, ¶ms); + if (err < 0) + return err; + err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(¶ms, buffer_size); + if (err < 0) + return err; + return INTERNAL(snd_pcm_hw_params_get_period_size)(¶ms, period_size, + NULL); +} diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c new file mode 100644 index 0000000..ed06531 --- /dev/null +++ b/src/pcm/pcm_adpcm.c @@ -0,0 +1,682 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "bswap.h" +#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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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..540ba25 --- /dev/null +++ b/src/pcm/pcm_alaw.c @@ -0,0 +1,556 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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..4c099ac --- /dev/null +++ b/src/pcm/pcm_copy.c @@ -0,0 +1,302 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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..54d9900 --- /dev/null +++ b/src/pcm/pcm_direct.c @@ -0,0 +1,2060 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, first_instance = 0; + +retryget: + dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t), + dmix->ipc_perm); + if (dmix->shmid < 0 && errno == ENOENT) { + if ((dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t), + IPC_CREAT | IPC_EXCL | dmix->ipc_perm)) != -1) + first_instance = 1; + else if (errno == EEXIST) + goto retryget; + } + 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 (first_instance) { /* 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 */ +int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) +{ + int changed = 0; + if (dmix->timer_need_poll) { + while (poll(&dmix->timer_fd, 1, 0) > 0) { + changed++; + /* 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 + && (++changed) && + len != sizeof(rbuf[0])) + ; + } else { + snd_timer_read_t rbuf; + while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0) + changed++; + } + } + return changed; +} + +int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) +{ + snd_timer_stop(dmix->timer); + return 0; +} + +/* + * Recover slave on XRUN. + * Even if direct plugins disable xrun detection, there might be an xrun + * raised directly by some drivers. + * The first client recovers slave pcm. + * Each client needs to execute sw xrun handling afterwards + */ +int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct) +{ + int ret; + int semerr; + + semerr = snd_pcm_direct_semaphore_down(direct, + DIRECT_IPC_SEM_CLIENT); + if (semerr < 0) { + SNDERR("SEMDOWN FAILED with err %d", semerr); + return semerr; + } + + if (snd_pcm_state(direct->spcm) != SND_PCM_STATE_XRUN) { + /* ignore... someone else already did recovery */ + semerr = snd_pcm_direct_semaphore_up(direct, + DIRECT_IPC_SEM_CLIENT); + if (semerr < 0) { + SNDERR("SEMUP FAILED with err %d", semerr); + return semerr; + } + return 0; + } + + ret = snd_pcm_prepare(direct->spcm); + if (ret < 0) { + SNDERR("recover: unable to prepare slave"); + semerr = snd_pcm_direct_semaphore_up(direct, + DIRECT_IPC_SEM_CLIENT); + if (semerr < 0) { + SNDERR("SEMUP FAILED with err %d", semerr); + return semerr; + } + return ret; + } + + if (direct->type == SND_PCM_TYPE_DSHARE) { + const snd_pcm_channel_area_t *dst_areas; + dst_areas = snd_pcm_mmap_areas(direct->spcm); + snd_pcm_areas_silence(dst_areas, 0, direct->spcm->channels, + direct->spcm->buffer_size, + direct->spcm->format); + } + + ret = snd_pcm_start(direct->spcm); + if (ret < 0) { + SNDERR("recover: unable to start slave"); + semerr = snd_pcm_direct_semaphore_up(direct, + DIRECT_IPC_SEM_CLIENT); + if (semerr < 0) { + SNDERR("SEMUP FAILED with err %d", semerr); + return semerr; + } + return ret; + } + direct->shmptr->s.recoveries++; + semerr = snd_pcm_direct_semaphore_up(direct, + DIRECT_IPC_SEM_CLIENT); + if (semerr < 0) { + SNDERR("SEMUP FAILED with err %d", semerr); + return semerr; + } + return 0; +} + +/* + * enter xrun state, if slave xrun occurred + * @return: 0 - no xrun >0: xrun happened + */ +int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm) +{ + if (direct->shmptr->s.recoveries != direct->recoveries) { + /* no matter how many xruns we missed - + * so don't increment but just update to actual counter + */ + direct->recoveries = direct->shmptr->s.recoveries; + pcm->fast_ops->drop(pcm); + /* trigger_tstamp update is missing in drop callbacks */ + gettimestamp(&direct->trigger_tstamp, pcm->tstamp_type); + /* no timer clear: + * if slave already entered xrun again the event is lost. + * snd_pcm_direct_clear_timer_queue(direct); + */ + direct->state = SND_PCM_STATE_XRUN; + return 1; + } + return 0; +} + +/* + * This is the only operation guaranteed to be called before entering poll(). + * Direct plugins use fd of snd_timer to poll on, these timers do NOT check + * state of substream in kernel by intention. + * Only the enter to xrun might be notified once (SND_TIMER_EVENT_MSTOP). + * If xrun event was not correctly handled or was ignored it will never be + * evaluated again afterwards. + * This will result in snd_pcm_wait() always returning timeout. + * In contrast poll() on pcm hardware checks ALSA state and will immediately + * return POLLERR on XRUN. + * + * To prevent timeout and applications endlessly spinning without xrun + * detected we add a state check here which may trigger the xrun sequence. + * + * return count of filled descriptors or negative error code + */ +int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, + unsigned int 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; + } + + /* this will also evaluate slave state and enter xrun if necessary */ + /* using __snd_pcm_state() since this function is called inside lock */ + switch (__snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: + break; + } + return 1; +} + +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); + +timer_changed: + 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: + /* recover slave and update client state to xrun + * before returning POLLERR + */ + snd_pcm_direct_slave_recover(dmix); + snd_pcm_direct_client_chk_xrun(dmix, pcm); + /* fallthrough */ + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_SETUP: + events |= POLLERR; + break; + default: + if (empty) { + /* here we have a race condition: + * if period event arrived after the avail_update call + * above we might clear this event with the following + * clear_timer_queue. + * There is no way to do this in atomic manner, so we + * need to recheck avail_update if we successfully + * cleared a poll event. + */ + if (snd_pcm_direct_clear_timer_queue(dmix)) + goto timer_changed; + 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) { + snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id)); + snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name)); + snd_strlcpy((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<min - min) % step; + if (n != 0 || i->openmin) { + i->min += step - n; + changed = 1; + } + n = (i->max - min) % step; + if (n != 0 || i->openmax) { + i->max -= n; + changed = 1; + } + if (snd_interval_checkempty(i)) { + i->empty = 1; + return -EINVAL; + } + return changed; +} + +#undef REFINE_DEBUG + +int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + snd_pcm_direct_t *dshare = pcm->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; + + if (dshare->max_periods < 0) { + 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; + 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<shmptr->hw.period_size; + snd_interval_t period_time = dshare->shmptr->hw.period_time; + int changed; + unsigned int max_periods = dshare->max_periods; + if (max_periods < 2) + max_periods = dshare->slave_buffer_size / dshare->slave_period_size; + + /* make sure buffer size does not exceed slave buffer size */ + err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + 2 * dshare->slave_period_size, dshare->slave_buffer_size); + if (err < 0) + return err; + if (dshare->var_periodsize) { + /* more tolerant settings... */ + if (dshare->shmptr->hw.buffer_size.max / 2 > period_size.max) + period_size.max = dshare->shmptr->hw.buffer_size.max / 2; + if (dshare->shmptr->hw.buffer_time.max / 2 > period_time.max) + period_time.max = dshare->shmptr->hw.buffer_time.max / 2; + } + + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, + &period_size); + if (err < 0) + return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, + &period_time); + if (err < 0) + return err; + 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; + err = snd_interval_step(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE), + 0, dshare->slave_period_size); + if (err < 0) + return err; + changed |= err; + if (err) + params->rmask |= (1 << SND_PCM_HW_PARAM_PERIOD_SIZE); + } while (changed); + } + dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max / dshare->slave_period_size; + 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; +} + +snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + return snd_pcm_query_chmaps(dmix->spcm); +} + +snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + return snd_pcm_get_chmap(dmix->spcm); +} + +int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + return snd_pcm_set_chmap(dmix->spcm, map); +} + +int snd_pcm_direct_prepare(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + int err; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SETUP: + case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_SUSPENDED: + err = snd_pcm_prepare(dmix->spcm); + if (err < 0) + return err; + snd_pcm_start(dmix->spcm); + break; + case SND_PCM_STATE_OPEN: + case SND_PCM_STATE_DISCONNECTED: + return -EBADFD; + default: + break; + } + 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); +} + +int snd_pcm_direct_resume(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_t *spcm = dmix->spcm; + + snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + /* some buggy drivers require the device resumed before prepared; + * when a device has RESUME flag and is in SUSPENDED state, resume + * here but immediately drop to bring it to a sane active state. + */ + if ((spcm->info & SND_PCM_INFO_RESUME) && + snd_pcm_state(spcm) == SND_PCM_STATE_SUSPENDED) { + snd_pcm_resume(spcm); + snd_pcm_drop(spcm); + snd_pcm_direct_timer_stop(dmix); + snd_pcm_direct_clear_timer_queue(dmix); + snd_pcm_areas_silence(snd_pcm_mmap_areas(spcm), 0, + spcm->channels, spcm->buffer_size, + spcm->format); + snd_pcm_prepare(spcm); + snd_pcm_start(spcm); + } + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + return -ENOSYS; +} + +#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(tstamp_type); + 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); + + dmix->shmptr->s.info &= ~SND_PCM_INFO_RESUME; +} + +#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 = {0}; + snd_pcm_sw_params_t sw_params = {0}; + int ret, buffer_is_not_initialized; + snd_pcm_uframes_t boundary; + struct pollfd fd; + int loops = 10; + + __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 < ARRAY_SIZE(dmix_formats); ++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 && + dmix->type != SND_PCM_TYPE_DSHARE) + 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 = {0}; + char name[128]; + int capture = dmix->type == SND_PCM_TYPE_DSNOOP ? 1 : 0; + + dmix->tread = 1; + dmix->timer_need_poll = 0; + dmix->timer_ticks = 1; + 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(tstamp_type); + 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); + 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; + dmix->recoveries = dmix->shmptr->s.recoveries; + + 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 = {0}; + unsigned int filter; + int ret; + + snd_timer_params_set_auto_start(¶ms, 1); + if (dmix->type != SND_PCM_TYPE_DSNOOP) + snd_timer_params_set_early_event(¶ms, 1); + snd_timer_params_set_ticks(¶ms, dmix->timer_ticks); + if (dmix->tread) { + filter = (1<timer_events; + INTERNAL(snd_timer_params_set_filter)(¶ms, filter); + } + ret = snd_timer_params(dmix->timer, ¶ms); + 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, *pcm_conf2; + 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) { + if (snd_config_search(pcm_conf, "pcm", &pcm_conf) >= 0) { + return _snd_pcm_direct_get_slave_ipc_offset(root, + pcm_conf, + direction, + hop + 1); + } else { + if (snd_config_get_string(pcm_conf, &str) >= 0 && + snd_config_search_definition(root, "pcm_slave", + str, &pcm_conf) >= 0) { + if (snd_config_search(pcm_conf, "pcm", + &pcm_conf2) >= 0) { + err = + _snd_pcm_direct_get_slave_ipc_offset( + root, pcm_conf2, direction, hop + 1); + snd_config_delete(pcm_conf); + return err; + } + snd_config_delete(pcm_conf); + } + } + } + + 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; + rec->var_periodsize = 0; + rec->direct_memory_access = 1; + rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_AUTO; + + /* 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, "hw_ptr_alignment") == 0) { + const char *str; + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + if (strcmp(str, "no") == 0) + rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_NO; + else if (strcmp(str, "roundup") == 0) + rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP; + else if (strcmp(str, "rounddown") == 0) + rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_ROUNDDOWN; + else if (strcmp(str, "auto") == 0) + rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_AUTO; + else { + SNDERR("The field hw_ptr_alignment is invalid : %s", str); + return -EINVAL; + } + + 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) { + long clen = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t len = (clen == -1) ? 1024 : (size_t)clen; + struct group grp, *pgrp; + char *buffer = (char *)malloc(len); + if (buffer == NULL) + return -ENOMEM; + int st = getgrnam_r(group, &grp, buffer, len, &pgrp); + if (st != 0 || !pgrp) { + SNDERR("The field ipc_gid must be a valid group (create group %s)", group); + free(buffer); + return -EINVAL; + } + rec->ipc_gid = pgrp->gr_gid; + free(buffer); + } 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; + } + if (strcmp(id, "var_periodsize") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return err; + rec->var_periodsize = err; + continue; + } + if (strcmp(id, "direct_memory_access") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return err; + rec->direct_memory_access = err; + 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; +} + +void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix) +{ + + if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP || + (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO && + pcm->buffer_size <= pcm->period_size * 2)) + dmix->slave_appl_ptr = + ((dmix->slave_appl_ptr + dmix->slave_period_size - 1) / + dmix->slave_period_size) * dmix->slave_period_size; + else if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDDOWN || + (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO && + (dmix->slave_period_size * SEC_TO_MS) / + pcm->rate < LOW_LATENCY_PERIOD_TIME)) + dmix->slave_appl_ptr = dmix->slave_hw_ptr = + ((dmix->slave_hw_ptr / dmix->slave_period_size) * + dmix->slave_period_size); +} diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h new file mode 100644 index 0000000..221edbe --- /dev/null +++ b/src/pcm/pcm_direct.h @@ -0,0 +1,364 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "pcm_local.h" +#include "../timer/timer_local.h" + +#define DIRECT_IPC_SEMS 1 +#define DIRECT_IPC_SEM_CLIENT 0 +/* Seconds representing in Milli seconds */ +#define SEC_TO_MS 1000 +/* slave_period time for low latency requirements in ms */ +#define LOW_LATENCY_PERIOD_TIME 10 + + +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); + +typedef enum snd_pcm_direct_hw_ptr_alignment { + SND_PCM_HW_PTR_ALIGNMENT_NO = 0, /* use the hw_ptr as is and do no rounding */ + SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP = 1, /* round the slave_appl_ptr up to slave_period */ + SND_PCM_HW_PTR_ALIGNMENT_ROUNDDOWN = 2, /* round slave_hw_ptr and slave_appl_ptr down to slave_period */ + SND_PCM_HW_PTR_ALIGNMENT_AUTO = 3 /* automatic selection */ +} snd_pcm_direct_hw_ptr_alignment_t; + +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; + snd_pcm_tstamp_t tstamp_mode; + snd_pcm_tstamp_type_t tstamp_type; + 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 recoveries; /* no of executed recoveries on slave*/ + 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 locked[DIRECT_IPC_SEMS]; /* local lock counter */ + 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; + unsigned int timer_ticks; + 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) */ + int var_periodsize; /* allow variable period size if max_periods is != -1*/ + unsigned int channels; /* client's channels */ + unsigned int *bindings; + unsigned int recoveries; /* mirror of executed recoveries on slave */ + int direct_memory_access; /* use arch-optimized buffer RW */ + snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment; + 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 { + 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_prepare \ + snd1_pcm_direct_prepare +#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 +#define snd_pcm_direct_query_chmaps \ + snd1_pcm_direct_query_chmaps +#define snd_pcm_direct_get_chmap \ + snd1_pcm_direct_get_chmap +#define snd_pcm_direct_set_chmap \ + snd1_pcm_direct_set_chmap +#define snd_pcm_direct_reset_slave_ptr \ + snd1_pcm_direct_reset_slave_ptr + +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 } }; + int err = semop(dmix->semid, op, 2); + if (err == 0) + dmix->locked[sem_num]++; + else if (err == -1) + err = -errno; + return err; +} + +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 }; + int err = semop(dmix->semid, &op, 1); + if (err == 0) + dmix->locked[sem_num]--; + else if (err == -1) + err = -errno; + return err; +} + +static inline int snd_pcm_direct_semaphore_final(snd_pcm_direct_t *dmix, int sem_num) +{ + if (dmix->locked[sem_num] != 1) { + SNDMSG("invalid semaphore count to finalize %d: %d", sem_num, dmix->locked[sem_num]); + return -EBUSY; + } + return snd_pcm_direct_semaphore_up(dmix, sem_num); +} + +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_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, + unsigned int space); +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_prepare(snd_pcm_t *pcm); +int snd_pcm_direct_resume(snd_pcm_t *pcm); +int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); +int 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); + +snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm); +snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm); +int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); +int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct); +int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm); +int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); +struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); +void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix); + +struct snd_pcm_direct_open_conf { + key_t ipc_key; + mode_t ipc_perm; + int ipc_gid; + int slowptr; + int max_periods; + int var_periodsize; + int direct_memory_access; + snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment; + 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..d533f40 --- /dev/null +++ b/src/pcm/pcm_dmix.c @@ -0,0 +1,1432 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + + old_slave_hw_ptr = dmix->slave_hw_ptr; + dmix->slave_hw_ptr = slave_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->tstamp_type); + 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; +} + +static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + int err; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dmix->state = SND_PCM_STATE_DISCONNECTED; + return -ENODEV; + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) + return err; + break; + default: + break; + } + if (snd_pcm_direct_client_chk_xrun(dmix, pcm)) + return -EPIPE; + if (dmix->slowptr) + snd_pcm_hwsync(dmix->spcm); + + return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr); +} + +/* + * plugin implementation + */ + +static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dmix = pcm->private_data; + int err; + snd_pcm_state_t state; + state = snd_pcm_state(dmix->spcm); + switch (state) { + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_DISCONNECTED: + dmix->state = state; + return state; + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) + return err; + break; + default: + break; + } + snd_pcm_direct_client_chk_xrun(dmix, pcm); + 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; + + memset(status, 0, sizeof(*status)); + snd_pcm_status(dmix->spcm, status); + + switch (dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + snd_pcm_dmix_sync_ptr0(pcm, status->hw_ptr); + status->delay += snd_pcm_mmap_playback_delay(pcm) + + status->avail - dmix->spcm->buffer_size; + break; + default: + break; + } + + status->state = snd_pcm_dmix_state(pcm); + status->trigger_tstamp = dmix->trigger_tstamp; + 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_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; + dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + snd_pcm_direct_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); + dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + snd_pcm_direct_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->tstamp_type); + 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; +} + +/* locked version */ +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 = 0; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + + if (dmix->state == SND_PCM_STATE_OPEN) + return -EBADFD; + 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); + goto done; + } + if (dmix->state == SND_PCM_STATE_DRAINING) { + snd_pcm_dmix_sync_area(pcm); + if ((pcm->mode & SND_PCM_NONBLOCK) == 0) { + snd_pcm_wait_nocheck(pcm, -1); + snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ + } + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto done; + default: + break; + } + } + if (pcm->mode & SND_PCM_NONBLOCK) { + if (dmix->state == SND_PCM_STATE_DRAINING) { + err = -EAGAIN; + goto done; + } + } + } while (dmix->state == SND_PCM_STATE_DRAINING); +done: + pcm->stop_threshold = stop_threshold; + return err; +} + +static int snd_pcm_dmix_drain(snd_pcm_t *pcm) +{ + int err; + + snd_pcm_lock(pcm); + err = __snd_pcm_dmix_drain(pcm); + snd_pcm_unlock(pcm); + return err; +} + +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_playback_hw_rewindable(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, frames_to_remix; + int err; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) { + err = snd_pcm_dmix_hwsync(pcm); + if (err < 0) + return err; + } + + /* (appl_ptr - last_appl_ptr) indicates the frames which are not + * already mixed + * (last_appl_ptr - hw_ptr) indicates the frames which are already + * mixed but not played yet. + * So they can be remixed. + */ + + 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; + + /* Always at this point last_appl_ptr == appl_ptr + * So (appl_ptr - hw_ptr) indicates the frames which can be remixed + */ + 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 which should be remixed will be saved + * to also backward the appl pointer on success + */ + frames_to_remix = 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_up_sem(dmix); + + snd_pcm_mmap_appl_backward(pcm, frames_to_remix); + result += frames_to_remix; + /* At this point last_appl_ptr and appl_ptr has to indicate the + * position of the first not mixed frame + */ + + return result; +} + +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_dmix_forwardable(pcm); + 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_final(dmix, DIRECT_IPC_SEM_CLIENT); + } else + snd_pcm_direct_semaphore_final(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: + if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) + return err; + break; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (snd_pcm_direct_client_chk_xrun(dmix, pcm)) + return -EPIPE; + 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) { + if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) + return err; + } + 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; + int err; + + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) { + if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) + return err; + } + if (dmix->state == SND_PCM_STATE_XRUN) + return -EPIPE; + + 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); + ok = 1; + } + 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, + .query_chmaps = snd_pcm_direct_query_chmaps, + .get_chmap = snd_pcm_direct_get_chmap, + .set_chmap = snd_pcm_direct_set_chmap, +}; + +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_direct_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 = snd_pcm_direct_poll_descriptors, + .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->var_periodsize = opts->var_periodsize; + dmix->hw_ptr_alignment = opts->hw_ptr_alignment; + dmix->sync_ptr = snd_pcm_dmix_sync_ptr; + dmix->direct_memory_access = opts->direct_memory_access; + + retry: + 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) { + /* all other streams have been closed; + * retry as the first instance + */ + if (ret == -EBADFD) { + first_instance = 1; + goto retry; + } + 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->tstamp_type = spcm->tstamp_type; + 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)) + snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT); + } else + 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) + hw_ptr_alignment STR # Slave application and hw pointer alignment type + # STR can be one of the below strings : + # no + # roundup + # rounddown + # auto (default) + 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 frames + buffer_time INT # in usec + # or + buffer_size INT # in frames + 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. + +hw_ptr_alignment specifies slave application and hw +pointer alignment type. By default hw_ptr_alignment is auto. Below are +the possible configurations: +- no: minimal latency with minimal frames dropped at startup. But + wakeup of application (return from snd_pcm_wait() or poll()) can + take up to 2 * period. +- roundup: It is guaranteed that all frames will be played at + startup. But the latency will increase upto period-1 frames. +- rounddown: It is guaranteed that a wakeup will happen for each + period and frames can be written from application. But on startup + upto period-1 frames will be dropped. +- auto: Selects the best approach depending on the used period and + buffer size. + If the application buffer size is < 2 * application period, + "roundup" will be selected to avoid under runs. If the slave_period + is < 10ms we could expect that there are low latency + requirements. Therefore "rounddown" will be chosen to avoid long + wakeup times. Such wakeup delay could otherwise end up with Xruns in + case of a dependency to another sound device (e.g. forwarding of + microphone to speaker). Else "no" will be chosen. + +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..40c0874 --- /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 "bswap.h" + +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..1ab983a --- /dev/null +++ b/src/pcm/pcm_dmix_i386.c @@ -0,0 +1,138 @@ +/* + * 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 (!dmix->direct_memory_access) { + generic_mix_select_callbacks(dmix); + return; + } + + 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..2778cb1 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..34c40d4 --- /dev/null +++ b/src/pcm/pcm_dmix_x86_64.c @@ -0,0 +1,105 @@ +/* + * 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 (!dmix->direct_memory_access) { + generic_mix_select_callbacks(dmix); + return; + } + + 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..1ef608a --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..59448cf --- /dev/null +++ b/src/pcm/pcm_dshare.c @@ -0,0 +1,1049 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + if (dchn != UINT_MAX) + 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; + if (dchn != UINT_MAX) + 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 (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_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_uframes_t old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + + old_slave_hw_ptr = dshare->slave_hw_ptr; + dshare->slave_hw_ptr = slave_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); + do_silence(pcm); + gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); + 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; +} + +static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + int err; + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dshare->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) + return err; + break; + default: + break; + } + if (snd_pcm_direct_client_chk_xrun(dshare, pcm)) + return -EPIPE; + if (dshare->slowptr) + snd_pcm_hwsync(dshare->spcm); + + return snd_pcm_dshare_sync_ptr0(pcm, *dshare->spcm->hw.ptr); +} + +/* + * plugin implementation + */ + +static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm); + +static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) +{ + snd_pcm_direct_t *dshare = pcm->private_data; + + memset(status, 0, sizeof(*status)); + snd_pcm_status(dshare->spcm, status); + + switch (dshare->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + snd_pcm_dshare_sync_ptr0(pcm, status->hw_ptr); + status->delay += snd_pcm_mmap_playback_delay(pcm) + + status->avail - dshare->spcm->buffer_size; + break; + default: + break; + } + status->state = snd_pcm_dshare_state(pcm); + status->trigger_tstamp = dshare->trigger_tstamp; + 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; + int err; + snd_pcm_state_t state; + state = snd_pcm_state(dshare->spcm); + switch (state) { + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_DISCONNECTED: + dshare->state = state; + return state; + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) + return err; + break; + default: + break; + } + snd_pcm_direct_client_chk_xrun(dshare, pcm); + 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_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; + snd_pcm_direct_reset_slave_ptr(pcm, dshare); + return 0; +} + +static int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare) +{ + int err; + + snd_pcm_hwsync(dshare->spcm); + dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr; + snd_pcm_direct_reset_slave_ptr(pcm, dshare); + 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 { + err = snd_pcm_dshare_start_timer(pcm, dshare); + if (err < 0) + return err; + snd_pcm_dshare_sync_area(pcm); + } + gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); + 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; +} + +/* locked version */ +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; + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + + 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 */ + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + } + } while (dshare->state == SND_PCM_STATE_DRAINING); + pcm->stop_threshold = stop_threshold; + return 0; +} + +static int snd_pcm_dshare_drain(snd_pcm_t *pcm) +{ + int err; + + snd_pcm_lock(pcm); + err = __snd_pcm_dshare_drain(pcm); + snd_pcm_unlock(pcm); + return err; +} + +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_rewindable(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_dshare_rewindable(pcm); + 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_dshare_forwardable(pcm); + 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); + if (dshare->bindings) + 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)) { + if (snd_pcm_direct_semaphore_discard(dshare)) + snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT); + } else + snd_pcm_direct_semaphore_final(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: + if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) + return err; + break; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (snd_pcm_direct_client_chk_xrun(dshare, pcm)) + return -EPIPE; + if (! size) + return 0; + snd_pcm_mmap_appl_forward(pcm, size); + if (dshare->state == STATE_RUN_PENDING) { + err = snd_pcm_dshare_start_timer(pcm, dshare); + if (err < 0) + return err; + } else if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) { + if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) + return err; + } + 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; + int err; + + if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) { + if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) + return err; + } + if (dshare->state == SND_PCM_STATE_XRUN) + return -EPIPE; + + 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); + ok = 1; + } + 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_dummy_ops = { + .close = snd_pcm_dshare_close, +}; + +static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_dummy_ops; + +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, + .get_chmap = snd_pcm_direct_get_chmap, + .set_chmap = snd_pcm_direct_set_chmap, +}; + +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_direct_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 = snd_pcm_direct_poll_descriptors, + .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; + + 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; + } + + if (!dshare->bindings) { + pcm->ops = &snd_pcm_dshare_dummy_ops; + pcm->fast_ops = &snd_pcm_dshare_fast_dummy_ops; + } else { + 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->var_periodsize = opts->var_periodsize; + dshare->hw_ptr_alignment = opts->hw_ptr_alignment; + dshare->sync_ptr = snd_pcm_dshare_sync_ptr; + + retry: + 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) { + /* all other streams have been closed; + * retry as the first instance + */ + if (ret == -EBADFD) { + first_instance = 1; + goto retry; + } + 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; dshare->bindings && (chn < dshare->channels); chn++) { + unsigned int dchn = dshare->bindings ? dshare->bindings[chn] : chn; + if (dchn != UINT_MAX) + dshare->u.dshare.chn_mask |= (1ULL << dchn); + } + 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->tstamp_type = spcm->tstamp_type; + 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)) + snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT); + } else + 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) + hw_ptr_alignment STR # Slave application and hw pointer alignment type + # STR can be one of the below strings : + # no + # roundup + # rounddown + # auto (default) + 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 frames + buffer_time INT # in usec + # or + buffer_size INT # in frames + 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 + +hw_ptr_alignment specifies slave application and hw +pointer alignment type. By default hw_ptr_alignment is auto. Below are +the possible configurations: +- no: minimal latency with minimal frames dropped at startup. But + wakeup of application (return from snd_pcm_wait() or poll()) can + take up to 2 * period. +- roundup: It is guaranteed that all frames will be played at + startup. But the latency will increase upto period-1 frames. +- rounddown: It is guaranteed that a wakeup will happen for each + period and frames can be written from application. But on startup + upto period-1 frames will be dropped. +- auto: Selects the best approach depending on the used period and + buffer size. + If the application buffer size is < 2 * application period, + "roundup" will be selected to avoid under runs. If the slave_period + is < 10ms we could expect that there are low latency + requirements. Therefore "rounddown" will be chosen to avoid long + wakeup times. Such wakeup delay could otherwise end up with Xruns in + case of a dependency to another sound device (e.g. forwarding of + microphone to speaker). Else "no" will be chosen. + +\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..24f472c --- /dev/null +++ b/src/pcm/pcm_dsnoop.c @@ -0,0 +1,898 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + int err; + + switch (snd_pcm_state(dsnoop->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) + return err; + break; + default: + break; + } + if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm)) + return -EPIPE; + 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->tstamp_type); + 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)); + snd_pcm_status(dsnoop->spcm, status); + state = snd_pcm_state(dsnoop->spcm); + status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state; + status->trigger_tstamp = dsnoop->trigger_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; + status->delay = snd_pcm_mmap_capture_delay(pcm); + return 0; +} + +static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm) +{ + snd_pcm_direct_t *dsnoop = pcm->private_data; + int err; + snd_pcm_state_t state; + state = snd_pcm_state(dsnoop->spcm); + switch (state) { + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_DISCONNECTED: + dsnoop->state = state; + return state; + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) + return err; + break; + default: + break; + } + snd_pcm_direct_client_chk_xrun(dsnoop, pcm); + 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; + /* Fall through */ + 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_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; + snd_pcm_direct_reset_slave_ptr(pcm, dsnoop); + 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; + snd_pcm_direct_reset_slave_ptr(pcm, dsnoop); + 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; +} + +/* locked version */ +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_in_lock(pcm, -1); + } + pcm->stop_threshold = stop_threshold; + return snd_pcm_dsnoop_drop(pcm); +} + +static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm) +{ + int err; + + snd_pcm_lock(pcm); + err = __snd_pcm_dsnoop_drain(pcm); + snd_pcm_unlock(pcm); + return err; +} + +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_hw_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_dsnoop_rewindable(pcm); + 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_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_dsnoop_forwardable(pcm); + 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)) { + if (snd_pcm_direct_semaphore_discard(dsnoop)) + snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT); + } else + snd_pcm_direct_semaphore_final(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: + if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) + return err; + break; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm)) + return -EPIPE; + 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; + } + if (dsnoop->state == SND_PCM_STATE_XRUN) + return -EPIPE; + + 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); + ok = 1; + } + 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, + .query_chmaps = snd_pcm_direct_query_chmaps, + .get_chmap = snd_pcm_direct_get_chmap, + .set_chmap = snd_pcm_direct_set_chmap, +}; + +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_direct_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 = snd_pcm_direct_poll_descriptors, + .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->var_periodsize = opts->var_periodsize; + dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; + dsnoop->hw_ptr_alignment = opts->hw_ptr_alignment; + + retry: + 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) { + /* all other streams have been closed; + * retry as the first instance + */ + if (ret == -EBADFD) { + first_instance = 1; + goto retry; + } + 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->tstamp_type = spcm->tstamp_type; + 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)) + snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT); + } else + 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) + hw_ptr_alignment STR # Slave application and hw pointer alignment type + # STR can be one of the below strings : + # no + # roundup + # rounddown + # auto (default) + 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 frames + buffer_time INT # in usec + # or + buffer_size INT # in frames + 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 + +hw_ptr_alignment specifies slave application and hw +pointer alignment type. By default hw_ptr_alignment is auto. Below are +the possible configurations: +- no: minimal latency with minimal frames dropped at startup. But + wakeup of application (return from snd_pcm_wait() or poll()) can + take up to 2 * period. +- roundup: It is guaranteed that all frames will be played at + startup. But the latency will increase upto period-1 frames. +- rounddown: It is guaranteed that a wakeup will happen for each + period and frames can be written from application. But on startup + upto period-1 frames will be dropped. +- auto: Selects the best approach depending on the used period and + buffer size. + If the application buffer size is < 2 * application period, + "roundup" will be selected to avoid over runs. If the slave_period + is < 10ms we could expect that there are low latency + requirements. Therefore "rounddown" will be chosen to avoid long + wakeup times. Else "no" will be chosen. + +\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..869577b --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..7b99bef --- /dev/null +++ b/src/pcm/pcm_ext_parm.h @@ -0,0 +1,42 @@ +/* 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; + unsigned int keep_link: 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..94002dc --- /dev/null +++ b/src/pcm/pcm_extplug.c @@ -0,0 +1,885 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + if (!parm->active) + return 0; + 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 && !params[i].keep_link) + 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 snd_pcm_chmap_query_t **snd_pcm_extplug_query_chmaps(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + + if (ext->data->version >= 0x010002 && + ext->data->callback->query_chmaps) + return ext->data->callback->query_chmaps(ext->data); + return snd_pcm_generic_query_chmaps(pcm); +} + +static snd_pcm_chmap_t *snd_pcm_extplug_get_chmap(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + + if (ext->data->version >= 0x010002 && + ext->data->callback->get_chmap) + return ext->data->callback->get_chmap(ext->data); + return snd_pcm_generic_get_chmap(pcm); +} + +static int snd_pcm_extplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + extplug_priv_t *ext = pcm->private_data; + + if (ext->data->version >= 0x010002 && + ext->data->callback->set_chmap) + return ext->data->callback->set_chmap(ext->data, map); + return snd_pcm_generic_set_chmap(pcm, map); +} + +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, + .query_chmaps = snd_pcm_extplug_query_chmaps, + .get_chmap = snd_pcm_extplug_get_chmap, + .set_chmap = snd_pcm_extplug_set_chmap, +}; + +#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. + +When using snd_pcm_extplug_set_param_*() or snd_pcm_extplug_set_slave_param_*() +for any parameter. This parameter is no longer linked between the client and +slave PCM. Therefore it could differ and the extplug has to support conversion +between all valid parameter configurations. To keep the client and slave +parameter linked #snd_pcm_extplug_set_param_link() can be used for the +corresponding parameter. For example if the extplug does not support channel nor +format conversion the supported client parameters can be limited with +snd_pcm_extplug_set_param_*() and afterwards +#snd_pcm_extplug_set_param_link(ext, SND_PCM_EXTPLUG_HW_FORMAT, 1) and +#snd_pcm_extplug_set_param_link(ext, SND_PCM_EXTPLUG_HW_CHANNELS, 1) should be +called to keep the client and slave parameters the same. +*/ + +/** + * \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); + + /* We support 1.0.0 to current */ + if (extplug->version < 0x010000 || + extplug->version > SND_PCM_EXTPLUG_VERSION) { + SNDERR("extplug: Plugin version mismatch: 0x%x\n", + extplug->version); + 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->version >= 0x010001 && 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); +} + +/** + * @brief Keep the client and slave format/channels the same if requested. This + * is for example useful if this extplug does not support any channel + * conversion. + * @param extplug the extplug handle + * @param type parameter type + * @param keep_link if 1 the parameter identified by type will be kept the same + * for the client and slave PCM of this extplug + * @return 0 if successful, or a negative error code + */ +int snd_pcm_extplug_set_param_link(snd_pcm_extplug_t *extplug, int type, + int keep_link) +{ + 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; + } + ext->params[type].keep_link = keep_link ? 1 : 0; + ext->sparams[type].keep_link = keep_link ? 1 : 0; + return 0; +} diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c new file mode 100644 index 0000000..a02b2dc --- /dev/null +++ b/src/pcm/pcm_file.c @@ -0,0 +1,1130 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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; + FILE *pipe; + 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; + snd_pcm_uframes_t rbuf_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; + char ifmmap_overwritten; +} 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); + file->pipe = pipe; + } else { + file->pipe = NULL; + 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; +} + +/* fill areas with data from input file, return bytes red */ +static int snd_pcm_file_areas_read_infile(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; + snd_pcm_channel_area_t areas_if[pcm->channels]; + ssize_t bytes; + + if (file->ifd < 0) + return -EBADF; + + if (file->rbuf == NULL) + return -ENOMEM; + + if (file->rbuf_size < frames) { + SYSERR("requested more frames than pcm buffer"); + return -ENOMEM; + } + + bytes = snd_pcm_frames_to_bytes(pcm, frames); + if (bytes < 0) + return bytes; + bytes = read(file->ifd, file->rbuf, bytes); + if (bytes < 0) { + SYSERR("read from file failed, error: %d", bytes); + return bytes; + } + + snd_pcm_areas_from_buf(pcm, areas_if, file->rbuf); + snd_pcm_areas_copy(areas, offset, areas_if, 0, pcm->channels, snd_pcm_bytes_to_frames(pcm, bytes), pcm->format); + + return bytes; +} + +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; + ssize_t res; + + 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); + + res = write(file->fd, header, sizeof(header)); + if (res != sizeof(header)) + goto write_error; + + res = write(file->fd, &file->wav_header, sizeof(file->wav_header)); + if (res != sizeof(file->wav_header)) + goto write_error; + + res = write(file->fd, header2, sizeof(header2)); + if (res != sizeof(header2)) + goto write_error; + + return 0; + +write_error: + /* + * print real errno if available and return EIO, reason for this is + * to block possible EPIPE in case file->fd is a pipe. EPIPE from + * file->fd conflicts with EPIPE from playback stream which should + * be used to signal XRUN on playback device + */ + if (res < 0) + SYSERR("%s write header failed, file data may be corrupt", file->fname); + else + SNDERR("%s write header incomplete, file data may be corrupt", file->fname); + + memset(&file->wav_header, 0, sizeof(struct wav_fmt)); + + return -EIO; +} + +/* 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 */ + + + +/* return error code in case write failed */ +static int snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes) +{ + snd_pcm_file_t *file = pcm->private_data; + snd_pcm_sframes_t err = 0; + assert(bytes <= file->wbuf_used_bytes); + + if (file->format == SND_PCM_FILE_FORMAT_WAV && + !file->wav_header.fmt) { + err = write_wav_header(pcm); + if (err < 0) { + file->wbuf_used_bytes = 0; + file->file_ptr_bytes = 0; + return err; + } + } + + while (bytes > 0) { + 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) { + err = -errno; + file->wbuf_used_bytes = 0; + file->file_ptr_bytes = 0; + SYSERR("%s write failed, file data may be corrupt", file->fname); + return err; + } + 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; + } + return 0; +} + +static int 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) { + int err = 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) { + err = snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes - file->buffer_bytes); + if (err < 0) + return err; + } + assert(file->wbuf_used_bytes < file->wbuf_size_bytes); + } + return 0; +} + +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); + if (file->pipe) { + pclose(file->pipe); + } else if (file->fd >= 0) { + 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; +} + +/* locking */ +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_lock(pcm); + snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes); + assert(file->wbuf_used_bytes == 0); + __snd_pcm_unlock(pcm); + } + 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(file->gen.slave); + 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(file->gen.slave); + 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; +} + +/* locking */ +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_lock(pcm); + if (snd_pcm_file_add_frames(pcm, areas, 0, n) < 0) { + __snd_pcm_unlock(pcm); + return -EIO; + } + __snd_pcm_unlock(pcm); + } + return n; +} + +/* locking */ +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_lock(pcm); + if (snd_pcm_file_add_frames(pcm, areas, 0, n) < 0) { + __snd_pcm_unlock(pcm); + return -EIO; + } + __snd_pcm_unlock(pcm); + } + return n; +} + +/* locking */ +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 frames; + + frames = _snd_pcm_readi(file->gen.slave, buffer, size); + if (frames <= 0) + return frames; + + snd_pcm_areas_from_buf(pcm, areas, buffer); + snd_pcm_file_areas_read_infile(pcm, areas, 0, frames); + __snd_pcm_lock(pcm); + if (snd_pcm_file_add_frames(pcm, areas, 0, frames) < 0) { + __snd_pcm_unlock(pcm); + return -EIO; + } + + __snd_pcm_unlock(pcm); + + return frames; +} + +/* locking */ +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 frames; + + frames = _snd_pcm_readn(file->gen.slave, bufs, size); + if (frames <= 0) + return frames; + + snd_pcm_areas_from_bufs(pcm, areas, bufs); + snd_pcm_file_areas_read_infile(pcm, areas, 0, frames); + __snd_pcm_lock(pcm); + if (snd_pcm_file_add_frames(pcm, areas, 0, frames) < 0) { + __snd_pcm_unlock(pcm); + return -EIO; + } + + __snd_pcm_unlock(pcm); + + return frames; +} + +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; + + file->ifmmap_overwritten = 0; + + result = snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); + if (result >= 0) { + assert(ofs == offset && siz == size); + result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); + if (result > 0) { + if (snd_pcm_file_add_frames(pcm, areas, ofs, result) < 0) + return -EIO; + } + } + return result; +} + +static int snd_pcm_file_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_file_t *file = pcm->private_data; + int result; + + result = snd_pcm_mmap_begin(file->gen.slave, areas, offset, frames); + if (result < 0) + return result; + + if (pcm->stream != SND_PCM_STREAM_CAPTURE) + return result; + + /* user may run mmap_begin without mmap_commit multiple times in row */ + if (file->ifmmap_overwritten) + return result; + file->ifmmap_overwritten = 1; + + snd_pcm_file_areas_read_infile(pcm, *areas, *offset, *frames); + + 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); + free(file->final_fname); + free(file->rbuf); + file->wbuf = NULL; + file->wbuf_areas = NULL; + file->final_fname = NULL; + file->rbuf = 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_internal(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; + file->ifmmap_overwritten = 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; + } + assert(!file->rbuf); + file->rbuf_size = slave->buffer_size; + file->rbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->rbuf_size); + file->rbuf_used_bytes = 0; + file->rbuf = malloc(file->rbuf_size_bytes); + if (file->rbuf == 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; + } + } + + /* pointer may have changed - e.g if plug is used. */ + snd_pcm_unlink_hw_ptr(pcm, file->gen.slave); + snd_pcm_unlink_appl_ptr(pcm, file->gen.slave); + + snd_pcm_link_hw_ptr(pcm, file->gen.slave); + snd_pcm_link_appl_ptr(pcm, file->gen.slave); + + 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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +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, + .htimestamp = snd_pcm_generic_htimestamp, + .mmap_begin = snd_pcm_file_mmap_begin, +}; + +/** + * \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 + * \param stream the direction of PCM stream + * \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_stream_t stream) +{ + 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 && (stream == SND_PCM_STREAM_CAPTURE)) { + ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */ + if (ifd < 0) { + SYSERR("open %s for reading failed", ifname); + free(file->fname); + 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->ifname); + 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; + pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) + pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; +#endif + pcm->stream = stream; + 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) { + 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, stream); + 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..4a10c6b --- /dev/null +++ b/src/pcm/pcm_generic.c @@ -0,0 +1,349 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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 err; +} + +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_internal(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->tstamp_type); + 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; +} + +snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_query_chmaps(generic->slave); +} + +snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_get_chmap(generic->slave); +} + +int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_set_chmap(generic->slave, map); +} + +int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail ATTRIBUTE_UNUSED) +{ + snd_pcm_generic_t *generic = pcm->private_data; + return snd_pcm_may_wait_for_avail_min(generic->slave, snd_pcm_mmap_avail(generic->slave)); +} + +#endif /* DOC_HIDDEN */ diff --git a/src/pcm/pcm_generic.h b/src/pcm/pcm_generic.h new file mode 100644 index 0000000..dfbe21a --- /dev/null +++ b/src/pcm/pcm_generic.h @@ -0,0 +1,164 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 +#define snd_pcm_generic_query_chmaps \ + snd1_pcm_generic_query_chmaps +#define snd_pcm_generic_get_chmap \ + snd1_pcm_generic_get_chmap +#define snd_pcm_generic_set_chmap \ + snd1_pcm_generic_set_chmap +#define snd_pcm_generic_may_wait_for_avail_min \ + snd1_pcm_generic_may_wait_for_avail_min + +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); +snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm); +snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm); +int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); +int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail); + diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c new file mode 100644 index 0000000..4416d36 --- /dev/null +++ b/src/pcm/pcm_hooks.c @@ -0,0 +1,728 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +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, + .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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], errbuf[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); + err = -EINVAL; + 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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", + lib ? lib : "[builtin]", errbuf); + 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) { + if(h) + 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 = {0}; + 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); + + 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..2028790 --- /dev/null +++ b/src/pcm/pcm_hw.c @@ -0,0 +1,2017 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 snd_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; + + volatile struct snd_pcm_mmap_status * mmap_status; + struct snd_pcm_mmap_control *mmap_control; + bool mmap_status_fallbacked; + bool mmap_control_fallbacked; + struct snd_pcm_sync_ptr *sync_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; + /* for chmap */ + unsigned int chmap_caps; + snd_pcm_chmap_query_t **chmap_override; +} 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) \ + ((snd_pcm_state_t) (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; + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); + return err; + } + return 0; +} + +static int issue_avail_min(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) + return 0; + + /* Avoid unexpected change of applptr in kernel space. */ + return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_APPL); +} + +static int issue_applptr(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) + return 0; + + /* Avoid unexpected change of avail_min in kernel space. */ + return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + +static int request_hwsync(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_status_fallbacked) + return 0; + + /* + * Query both of control/status data to avoid unexpected change of + * control data in kernel space. + */ + return sync_ptr1(hw, + SNDRV_PCM_SYNC_PTR_HWSYNC | + SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + +static int query_status_and_control_data(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) + return 0; + + /* + * Query both of control/status data to avoid unexpected change of + * control data in kernel space. + */ + return sync_ptr1(hw, + SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + +static int query_status_data(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_status_fallbacked) + return 0; + + /* + * Query both of control/status data to avoid unexpected change of + * control data in kernel space. + */ + return sync_ptr1(hw, + SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); +} + +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; + if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) + params->info |= SND_PCM_INFO_MONOTONIC; + } + + 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; + if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) + params->info |= SND_PCM_INFO_MONOTONIC; + return query_status_data(hw); +} + +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 = {0}; + unsigned int suspend, resume; + int err; + + if (enable) { + 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, ¶ms); + 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 = 0; + int old_period_event = sw_get_period_event(params); + sw_set_period_event(params, 0); + if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode && + (snd_pcm_tstamp_type_t) params->tstamp_type == pcm->tstamp_type && + 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; + err = issue_avail_min(hw); + goto out; + } + if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW && + hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { + SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW"); + err = -EINVAL; + goto out; + } + if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC && + hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 5)) { + SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC"); + err = -EINVAL; + goto out; + } + if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); + goto out; + } + if ((snd_pcm_tstamp_type_t) params->tstamp_type != pcm->tstamp_type) { + if (hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { + int on = (snd_pcm_tstamp_type_t) params->tstamp_type == + SND_PCM_TSTAMP_TYPE_MONOTONIC; + if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) { + err = -errno; + SNDMSG("TSTAMP failed\n"); + goto out; + } + } + pcm->tstamp_type = params->tstamp_type; + } + 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) + goto out; + hw->period_event = old_period_event; + } + out: + sw_set_period_event(params, old_period_event); + return err; +} + +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 snd_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 (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) { + if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err); + return err; + } + } else { + if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT 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 = query_status_data(hw); + 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->mmap_status_fallbacked) { + err = request_hwsync(hw); + 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 query_status_and_control_data(hw); +} + +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 query_status_and_control_data(hw); +} + +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 + issue_applptr(hw); + 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_rewindable(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 = query_status_and_control_data(hw); + 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 = query_status_and_control_data(hw); + if (err < 0) + return err; + return frames; + } else { + snd_pcm_sframes_t avail; + + 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); + 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 snd_xferi xferi; + xferi.buf = (char*) buffer; + xferi.frames = size; + xferi.result = 0; /* make valgrind happy */ + if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); +#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 snd_xfern xfern; + memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ + xfern.bufs = bufs; + xfern.frames = size; + if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); +#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 snd_xferi xferi; + xferi.buf = buffer; + xferi.frames = size; + xferi.result = 0; /* make valgrind happy */ + if (ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); +#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 snd_xfern xfern; + memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ + xfern.bufs = bufs; + xfern.frames = size; + if (ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern) < 0) + err = -errno; + else + err = query_status_and_control_data(hw); +#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 bool map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr, + bool force_fallback) +{ + struct snd_pcm_mmap_status *mmap_status; + bool fallbacked; + + mmap_status = MAP_FAILED; + if (!force_fallback) { + mmap_status = mmap(NULL, page_align(sizeof(*mmap_status)), + PROT_READ, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + } + + if (mmap_status == MAP_FAILED || mmap_status == NULL) { + mmap_status = &sync_ptr->s.status; + fallbacked = true; + } else { + fallbacked = false; + } + + hw->mmap_status = mmap_status; + + return fallbacked; +} + +static bool map_control_data(snd_pcm_hw_t *hw, + struct snd_pcm_sync_ptr *sync_ptr, + bool force_fallback) +{ + struct snd_pcm_mmap_control *mmap_control; + bool fallbacked; + + mmap_control = MAP_FAILED; + if (!force_fallback) { + mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), + PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + } + + if (mmap_control == MAP_FAILED || mmap_control == NULL) { + mmap_control = &sync_ptr->c.control; + fallbacked = true; + } else { + fallbacked = false; + } + + hw->mmap_control = mmap_control; + + return fallbacked; +} + +static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) +{ + snd_pcm_hw_t *hw = pcm->private_data; + struct snd_pcm_sync_ptr *sync_ptr; + int err; + + /* Preparation for fallback to failure of mmap(2). */ + sync_ptr = malloc(sizeof(*sync_ptr)); + if (sync_ptr == NULL) + return -ENOMEM; + memset(sync_ptr, 0, sizeof(*sync_ptr)); + + hw->mmap_status_fallbacked = + map_status_data(hw, sync_ptr, force_fallback); + hw->mmap_control_fallbacked = + map_control_data(hw, sync_ptr, force_fallback); + + /* Any fallback mode needs to keep the buffer. */ + if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) { + hw->sync_ptr = sync_ptr; + } else { + free(sync_ptr); + hw->sync_ptr = NULL; + } + + /* do not initialize in case of append and keep the values from the + * kernel + */ + if (!(pcm->mode & SND_PCM_APPEND)) { + /* Initialize the data. */ + hw->mmap_control->appl_ptr = 0; + hw->mmap_control->avail_min = 1; + } + snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_STATUS + + offsetof(struct snd_pcm_mmap_status, hw_ptr)); + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (hw->mmap_control_fallbacked) { + unsigned int flags = 0; + /* read appl_ptr and avail_min from kernel when device opened + * with SND_PCM_APPEND flag + */ + if (pcm->mode & SND_PCM_APPEND) + flags = SNDRV_PCM_SYNC_PTR_APPL | + SNDRV_PCM_SYNC_PTR_AVAIL_MIN; + err = sync_ptr1(hw, flags); + if (err < 0) + return err; + } + + return 0; +} + +static void unmap_status_data(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_status_fallbacked) { + if (munmap((void *)hw->mmap_status, + page_align(sizeof(*hw->mmap_status))) < 0) + SYSMSG("status munmap failed (%u)", errno); + } +} + +static void unmap_control_data(snd_pcm_hw_t *hw) +{ + if (!hw->mmap_control_fallbacked) { + if (munmap((void *)hw->mmap_control, + page_align(sizeof(*hw->mmap_control))) < 0) + SYSMSG("control munmap failed (%u)", errno); + } +} + +static void unmap_status_and_control_data(snd_pcm_hw_t *hw) +{ + unmap_status_data(hw); + unmap_control_data(hw); + + if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) + free(hw->sync_ptr); + + hw->mmap_status = NULL; + hw->mmap_control = NULL; + hw->mmap_status_fallbacked = false; + hw->mmap_control_fallbacked = false; + hw->sync_ptr = NULL; +} + +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); + } + + unmap_status_and_control_data(hw); + + 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); + issue_applptr(hw); +#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; + + query_status_data(hw); + 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 __fill_chmap_ctl_id(snd_ctl_elem_id_t *id, int dev, int subdev, + int stream) +{ + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); + if (stream == SND_PCM_STREAM_PLAYBACK) + snd_ctl_elem_id_set_name(id, "Playback Channel Map"); + else + snd_ctl_elem_id_set_name(id, "Capture Channel Map"); + snd_ctl_elem_id_set_device(id, dev); + snd_ctl_elem_id_set_index(id, subdev); +} + +static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id) +{ + snd_pcm_hw_t *hw = pcm->private_data; + __fill_chmap_ctl_id(id, hw->device, hw->subdevice, pcm->stream); +} + +static int is_chmap_type(int type) +{ + return (type >= SND_CTL_TLVT_CHMAP_FIXED && + type <= SND_CTL_TLVT_CHMAP_PAIRED); +} + +/** + * \!brief Query the available channel maps + * \param card the card number + * \param dev the PCM device number + * \param subdev the PCM substream index + * \param stream the direction of PCM stream + * \return the NULL-terminated array of integer pointers, or NULL at error. + * + * This function works like snd_pcm_query_chmaps() but it takes the card, + * device, substream and stream numbers instead of the already opened + * snd_pcm_t instance, so that you can query available channel maps of + * a PCM before actually opening it. + * + * As the parameters stand, the query is performed only to the hw PCM + * devices, not the abstracted PCM object in alsa-lib. + */ +snd_pcm_chmap_query_t ** +snd_pcm_query_chmaps_from_hw(int card, int dev, int subdev, + snd_pcm_stream_t stream) +{ + snd_ctl_t *ctl; + snd_ctl_elem_id_t id = {0}; + unsigned int tlv[2048], *start; + unsigned int type; + snd_pcm_chmap_query_t **map; + int i, ret, nums; + + ret = snd_ctl_hw_open(&ctl, NULL, card, 0); + if (ret < 0) { + SYSMSG("Cannot open the associated CTL\n"); + return NULL; + } + + __fill_chmap_ctl_id(&id, dev, subdev, stream); + ret = snd_ctl_elem_tlv_read(ctl, &id, tlv, sizeof(tlv)); + snd_ctl_close(ctl); + if (ret < 0) { + SYSMSG("Cannot read Channel Map TLV\n"); + return NULL; + } + +#if 0 + for (i = 0; i < 32; i++) + fprintf(stderr, "%02x: %08x\n", i, tlv[i]); +#endif + /* FIXME: the parser below assumes that the TLV only contains + * chmap-related blocks + */ + type = tlv[SNDRV_CTL_TLVO_TYPE]; + if (type != SND_CTL_TLVT_CONTAINER) { + if (!is_chmap_type(type)) { + SYSMSG("Invalid TLV type %d\n", type); + return NULL; + } + start = tlv; + nums = 1; + } else { + unsigned int *p; + int size; + start = tlv + 2; + size = tlv[SNDRV_CTL_TLVO_LEN]; + nums = 0; + for (p = start; size > 0; ) { + if (!is_chmap_type(p[0])) { + SYSMSG("Invalid TLV type %d\n", p[0]); + return NULL; + } + nums++; + size -= p[1] + 8; + p += p[1] / 4 + 2; + } + } + map = calloc(nums + 1, sizeof(int *)); + if (!map) + return NULL; + for (i = 0; i < nums; i++) { + map[i] = malloc(start[1] + 8); + if (!map[i]) { + snd_pcm_free_chmaps(map); + return NULL; + } + map[i]->type = start[0] - 0x100; + map[i]->map.channels = start[1] / 4; + memcpy(map[i]->map.pos, start + 2, start[1]); + start += start[1] / 4 + 2; + } + return map; +} + +enum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET }; + +static int chmap_caps(snd_pcm_hw_t *hw, int type) +{ + if (hw->chmap_caps & (1 << type)) + return 1; + if (hw->chmap_caps & (1 << (type + 8))) + return 0; + return 1; +} + +static void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type) +{ + hw->chmap_caps |= (1 << type); +} + +static void chmap_caps_set_error(snd_pcm_hw_t *hw, int type) +{ + hw->chmap_caps |= (1 << (type + 8)); +} + +static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + snd_pcm_chmap_query_t **map; + + if (hw->chmap_override) + return _snd_pcm_copy_chmap_query(hw->chmap_override); + + if (!chmap_caps(hw, CHMAP_CTL_QUERY)) + return NULL; + + map = snd_pcm_query_chmaps_from_hw(hw->card, hw->device, + hw->subdevice, pcm->stream); + if (map) + chmap_caps_set_ok(hw, CHMAP_CTL_QUERY); + else + chmap_caps_set_error(hw, CHMAP_CTL_QUERY); + return map; +} + +static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm) +{ + snd_pcm_hw_t *hw = pcm->private_data; + snd_pcm_chmap_t *map; + snd_ctl_t *ctl; + snd_ctl_elem_id_t id = {0}; + snd_ctl_elem_value_t val = {0}; + unsigned int i; + int ret; + + if (hw->chmap_override) + return _snd_pcm_choose_fixed_chmap(pcm, hw->chmap_override); + + if (!chmap_caps(hw, CHMAP_CTL_GET)) + return NULL; + + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_XRUN: + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_PAUSED: + case SNDRV_PCM_STATE_SUSPENDED: + break; + default: + SYSMSG("Invalid PCM state for chmap_get: %s\n", + snd_pcm_state_name(FAST_PCM_STATE(hw))); + return NULL; + } + map = malloc(pcm->channels * sizeof(map->pos[0]) + sizeof(*map)); + if (!map) + return NULL; + map->channels = pcm->channels; + ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); + if (ret < 0) { + free(map); + SYSMSG("Cannot open the associated CTL\n"); + chmap_caps_set_error(hw, CHMAP_CTL_GET); + return NULL; + } + fill_chmap_ctl_id(pcm, &id); + snd_ctl_elem_value_set_id(&val, &id); + ret = snd_ctl_elem_read(ctl, &val); + snd_ctl_close(ctl); + if (ret < 0) { + free(map); + SYSMSG("Cannot read Channel Map ctl\n"); + chmap_caps_set_error(hw, CHMAP_CTL_GET); + return NULL; + } + for (i = 0; i < pcm->channels; i++) + map->pos[i] = snd_ctl_elem_value_get_integer(&val, i); + chmap_caps_set_ok(hw, CHMAP_CTL_GET); + return map; +} + +static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + snd_pcm_hw_t *hw = pcm->private_data; + snd_ctl_t *ctl; + snd_ctl_elem_id_t id = {0}; + snd_ctl_elem_value_t val = {0}; + unsigned int i; + int ret; + + if (hw->chmap_override) + return -ENXIO; + + if (!chmap_caps(hw, CHMAP_CTL_SET)) + return -ENXIO; + + if (map->channels > 128) { + SYSMSG("Invalid number of channels %d\n", map->channels); + return -EINVAL; + } + if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) { + SYSMSG("Invalid PCM state for chmap_set: %s\n", + snd_pcm_state_name(FAST_PCM_STATE(hw))); + return -EBADFD; + } + ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0); + if (ret < 0) { + SYSMSG("Cannot open the associated CTL\n"); + chmap_caps_set_error(hw, CHMAP_CTL_SET); + return ret; + } + + fill_chmap_ctl_id(pcm, &id); + snd_ctl_elem_value_set_id(&val, &id); + for (i = 0; i < map->channels; i++) + snd_ctl_elem_value_set_integer(&val, i, map->pos[i]); + ret = snd_ctl_elem_write(ctl, &val); + snd_ctl_close(ctl); + if (ret >= 0) + chmap_caps_set_ok(hw, CHMAP_CTL_SET); + else if (ret == -ENOENT || ret == -EPERM || ret == -ENXIO) { + chmap_caps_set_error(hw, CHMAP_CTL_SET); + ret = -ENXIO; + } + if (ret < 0) + SYSMSG("Cannot write Channel Map ctl\n"); + return ret; +} + +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, + .query_chmaps = snd_pcm_hw_query_chmaps, + .get_chmap = snd_pcm_hw_get_chmap, + .set_chmap = snd_pcm_hw_set_chmap, +}; + +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 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 sync_ptr_ioctl) +{ + int ver, mode; + snd_pcm_tstamp_type_t tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + 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 (fmode & O_APPEND) + mode |= SND_PCM_APPEND; + + 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 (SNDRV_PROTOCOL_VERSION(2, 0, 14) <= ver) { + /* inform the protocol version we're supporting */ + unsigned int user_ver = SNDRV_PCM_VERSION; + if (ioctl(fd, SNDRV_PCM_IOCTL_USER_PVERSION, &user_ver) < 0) { + ret = -errno; + SNDMSG("USER_PVERSION failed\n"); + return ret; + } + } + +#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; + } + tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; + } + } 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; + /* 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->tstamp_type = tstamp_type; +#ifdef THREAD_SAFE_API + pcm->need_lock = 0; /* hw plugin is thread-safe */ +#endif + pcm->own_state_check = 1; /* skip the common state check */ + + ret = map_status_and_control_data(pcm, !!sync_ptr_ioctl); + 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); + fd = -1; + goto __again; + } + } + snd_ctl_close(ctl); + return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl); + _err: + if (fd >= 0) + close(fd); + 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 + [chmap MAP] # Override channel maps; MAP is a string array +} +\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_chmap_query_t **chmap = NULL; + 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); + err = -EINVAL; + goto fail; + } + card = snd_card_get_index(str); + if (card < 0) { + SNDERR("Invalid value for %s", id); + err = card; + goto fail; + } + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto fail; + } + continue; + } + if (strcmp(id, "subdevice") == 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) { + SNDERR("Invalid type for %s", id); + goto fail; + } + 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); + goto fail; + } + rate = val; + continue; + } + if (strcmp(id, "format") == 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("invalid type for %s", id); + goto fail; + } + 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); + goto fail; + } + channels = val; + continue; + } + if (strcmp(id, "chmap") == 0) { + snd_pcm_free_chmaps(chmap); + chmap = _snd_pcm_parse_config_chmaps(n); + if (!chmap) { + SNDERR("Invalid channel map for %s", id); + err = -EINVAL; + goto fail; + } + continue; + } + SNDERR("Unknown field %s", id); + err = -EINVAL; + goto fail; + } + if (card < 0) { + SNDERR("card is not defined"); + err = -EINVAL; + goto fail; + } + err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream, + mode | (nonblock ? SND_PCM_NONBLOCK : 0), + 0, sync_ptr_ioctl); + if (err < 0) + goto fail; + 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; + if (chmap) + hw->chmap_override = chmap; + + return 0; + +fail: + snd_pcm_free_chmaps(chmap); + return err; +} + +#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..76d3ca7 --- /dev/null +++ b/src/pcm/pcm_iec958.c @@ -0,0 +1,717 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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 */ + snd_pcm_fast_ops_t fops; +}; + +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 uint32_t iec958_subframe(snd_pcm_iec958_t *iec, uint32_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, uint32_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 uint32_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(uint32_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; + uint32_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(uint32_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 snd_pcm_sframes_t snd_pcm_iec958_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +{ + unsigned int counter_decrement; + snd_pcm_iec958_t *iec = pcm->private_data; + snd_pcm_sframes_t result = snd_pcm_plugin_rewind(pcm, frames); + if (result <= 0) + return result; + + counter_decrement = result % 192; + iec->counter += 192 - counter_decrement; + iec->counter %= 192; + return result; +} + +static snd_pcm_sframes_t snd_pcm_iec958_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) + +{ + unsigned int counter_increment; + snd_pcm_iec958_t *iec = pcm->private_data; + snd_pcm_sframes_t result = snd_pcm_plugin_rewind(pcm, frames); + if (result <= 0) + return result; + + counter_increment = result % 192; + iec->counter += counter_increment; + iec->counter %= 192; + return result; +} + +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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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; + + iec->fops = snd_pcm_plugin_fast_ops; + iec->fops.rewind = snd_pcm_iec958_rewind; + iec->fops.forward = snd_pcm_iec958_forward; + pcm->fast_ops = &iec->fops; + + pcm->private_data = iec; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->tstamp_type = slave->tstamp_type; + 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..a437ca3 --- /dev/null +++ b/src/pcm/pcm_ioplug.c @@ -0,0 +1,1272 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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]; + snd_pcm_uframes_t last_hw; + snd_pcm_uframes_t avail_max; + snd_htimestamp_t trigger_tstamp; +} ioplug_priv_t; + +static int snd_pcm_ioplug_drop(snd_pcm_t *pcm); +static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm); +static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); +static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); + +/* update the hw pointer */ +/* called in lock */ +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) { + snd_pcm_uframes_t delta; + snd_pcm_uframes_t avail; + + if ((snd_pcm_uframes_t)hw >= io->last_hw) + delta = hw - io->last_hw; + else { + const snd_pcm_uframes_t wrap_point = + (io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ? + pcm->boundary : pcm->buffer_size; + delta = wrap_point + hw - io->last_hw; + } + snd_pcm_mmap_hw_forward(io->data->pcm, delta); + /* stop the stream if all samples are drained */ + if (io->data->state == SND_PCM_STATE_DRAINING) { + avail = snd_pcm_mmap_avail(pcm); + if (avail >= pcm->buffer_size) + snd_pcm_ioplug_drop(pcm); + } + io->last_hw = (snd_pcm_uframes_t)hw; + } else { + if (io->data->state == SND_PCM_STATE_DRAINING) + snd_pcm_ioplug_drop(pcm); + 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) { + snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id)); + snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name)); + snd_strlcpy((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; + int err = 0; + + snd_pcm_ioplug_reset(pcm); + if (io->data->callback->prepare) { + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = io->data->callback->prepare(io->data); + snd_pcm_lock(pcm); + } + if (err < 0) + return err; + + io->data->state = SND_PCM_STATE_PREPARED; + return err; +} + +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; + int err; + + if (!io->data->callback->sw_params) + return 0; + + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = io->data->callback->sw_params(io->data, params); + snd_pcm_lock(pcm); + + return err; +} + + +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->tstamp_type); + 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->tstamp_type); + io->data->state = SND_PCM_STATE_SETUP; + + return 0; +} + +static int ioplug_drain_via_poll(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + while (io->data->state == SND_PCM_STATE_DRAINING) { + snd_pcm_ioplug_hw_ptr_update(pcm); + if (io->data->state != SND_PCM_STATE_DRAINING) + break; + /* in non-blocking mode, let application to poll() by itself */ + if (io->data->nonblock) + return -EAGAIN; + if (snd_pcm_wait_nocheck(pcm, -1) < 0) + break; + } + + return 0; /* force to drop at error */ +} + +/* need own locking */ +static int snd_pcm_ioplug_drain(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + int err = 0; + + snd_pcm_lock(pcm); + switch (io->data->state) { + case SND_PCM_STATE_OPEN: + case SND_PCM_STATE_DISCONNECTED: + case SND_PCM_STATE_SUSPENDED: + snd_pcm_unlock(pcm); + return -EBADFD; + case SND_PCM_STATE_PREPARED: + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + if (!io->data->callback->drain) { + err = snd_pcm_ioplug_start(pcm); + if (err < 0) + goto unlock; + } + io->data->state = SND_PCM_STATE_DRAINING; + } + break; + case SND_PCM_STATE_RUNNING: + io->data->state = SND_PCM_STATE_DRAINING; + break; + default: + break; + } + + if (io->data->state == SND_PCM_STATE_DRAINING) { + if (io->data->callback->drain) { + snd_pcm_unlock(pcm); /* let plugin own locking */ + err = io->data->callback->drain(io->data); + snd_pcm_lock(pcm); + } else { + err = ioplug_drain_via_poll(pcm); + } + } + + unlock: + if (!err && io->data->state != SND_PCM_STATE_SETUP) + snd_pcm_ioplug_drop(pcm); + snd_pcm_unlock(pcm); + return err; +} + +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_rewindable(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; +} + +/* need own locking */ +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; +} + +/* called in lock */ +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 == SND_PCM_STATE_XRUN) + return -EPIPE; + + avail = snd_pcm_mmap_avail(pcm); + 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; + + /* If the available data doesn't fit in the + contiguous area at the end of the mmap we + must transfer the remaining data to the + beginning of the mmap. */ + if (size < avail) { + result = io->data->callback->transfer(io->data, areas, + 0, avail - size); + if (result < 0) + return result; + } + } + } + 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; + int err = 1; + + if (io->data->callback->poll_descriptors_count) { + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = io->data->callback->poll_descriptors_count(io->data); + snd_pcm_lock(pcm); + } + return err; +} + +static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) +{ + ioplug_priv_t *io = pcm->private_data; + int err; + + if (io->data->callback->poll_descriptors) { + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = io->data->callback->poll_descriptors(io->data, pfds, space); + snd_pcm_lock(pcm); + return err; + } + 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; + int err; + + if (io->data->callback->poll_revents) { + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = io->data->callback->poll_revents(io->data, pfds, nfds, revents); + snd_pcm_lock(pcm); + } else { + *revents = pfds->revents; + err = 0; + } + return err; +} + +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 snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->version >= 0x010002 && + io->data->callback->query_chmaps) + return io->data->callback->query_chmaps(io->data); + return NULL; +} + +static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->version >= 0x010002 && + io->data->callback->get_chmap) + return io->data->callback->get_chmap(io->data); + return NULL; +} + +static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->version >= 0x010002 && + io->data->callback->set_chmap) + return io->data->callback->set_chmap(io->data, map); + return -ENXIO; +} + +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, + .query_chmaps = snd_pcm_ioplug_query_chmaps, + .get_chmap = snd_pcm_ioplug_get_chmap, + .set_chmap = snd_pcm_ioplug_set_chmap, +}; + +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. + +Note that some callbacks (start, stop, pointer, transfer and pause) +may be called inside the internal pthread mutex, and they shouldn't +call the PCM functions again unnecessarily from the callback itself; +otherwise it may lead to a deadlock. + +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: 0x%x\n", + ioplug->version); + 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; + if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) + ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; + else + ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + 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; +} + +/** + * \brief Get the available frames. This function can be used to calculate the + * the available frames before calling #snd_pcm_avail_update() + * \param ioplug the ioplug handle + * \param hw_ptr hardware pointer in frames + * \param appl_ptr application pointer in frames + * \return available frames for the application + */ +snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr); +} + +/** + * \brief Get the available frames. This function can be used to calculate the + * the available frames before calling #snd_pcm_avail_update() + * \param ioplug the ioplug handle + * \param hw_ptr hardware pointer in frames + * \param appl_ptr application pointer in frames + * \return available frames for the hardware + */ +snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + /* available data/space which can be transferred by the user + * application + */ + const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug, + hw_ptr, + appl_ptr); + + if (user_avail > ioplug->pcm->buffer_size) { + /* there was an Xrun */ + return 0; + } + /* available data/space which can be transferred by the DMA */ + return ioplug->pcm->buffer_size - user_avail; +} diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c new file mode 100644 index 0000000..ad73347 --- /dev/null +++ b/src/pcm/pcm_ladspa.c @@ -0,0 +1,1808 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_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; + list_for_each(pos, list) { + snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list); + 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; + } + 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->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); + if (plugin->desc->activate) + plugin->desc->activate(instance->handle); + } + 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) { + free(pchannels); + return -ENOMEM; + } + for (idx = 0; idx < instance->input.channels.size; idx++) { + chn = instance->input.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) { + free(pchannels); + 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) { + free(pchannels); + 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) { + free(pchannels); + 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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +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 *)malloc(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->tstamp_type = slave->tstamp_type; + 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..f32a82a --- /dev/null +++ b/src/pcm/pcm_lfloat.c @@ -0,0 +1,540 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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_get_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_put_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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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..33e7fc4 --- /dev/null +++ b/src/pcm/pcm_linear.c @@ -0,0 +1,557 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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 + 20; + } else { + if (width == 20) + width = 40; + + width = width / 8 - 1; + return width * 4 + endian * 2 + sign; + } +} + +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 + 20; + } else { + if (width == 20) + width = 40; + + 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; + uint32_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 || + snd_pcm_format_width(format) == 20 || + snd_pcm_format_width(linear->sformat) == 20); + if (linear->use_getput) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + linear->get_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32); + linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, linear->sformat); + } else { + linear->get_idx = snd_pcm_linear_get_index(linear->sformat, SND_PCM_FORMAT_S32); + linear->put_idx = snd_pcm_linear_put_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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + + +/** + * \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->tstamp_type = slave->tstamp_type; + 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..05ed935 --- /dev/null +++ b/src/pcm/pcm_local.h @@ -0,0 +1,1179 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#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" + +#ifdef THREAD_SAFE_API +#define __USE_UNIX98 1 /* for old glibc */ +#include +#endif + +#define SND_INTERVAL_INLINE +#include "interval.h" + +#define SND_MASK_INLINE +#include "mask.h" + +#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); /* always locked */ + 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); /* always locked */ + 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_chmap_query_t **(*query_chmaps)(snd_pcm_t *pcm); + snd_pcm_chmap_t *(*get_chmap)(snd_pcm_t *pcm); + int (*set_chmap)(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); +} snd_pcm_ops_t; + +typedef struct { + int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status); /* locked */ + int (*prepare)(snd_pcm_t *pcm); /* locked */ + int (*reset)(snd_pcm_t *pcm); /* locked */ + int (*start)(snd_pcm_t *pcm); /* locked */ + int (*drop)(snd_pcm_t *pcm); /* locked */ + int (*drain)(snd_pcm_t *pcm); /* need own locking */ + int (*pause)(snd_pcm_t *pcm, int enable); /* locked */ + snd_pcm_state_t (*state)(snd_pcm_t *pcm); /* locked */ + int (*hwsync)(snd_pcm_t *pcm); /* locked */ + int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); /* locked */ + int (*resume)(snd_pcm_t *pcm); /* need own locking */ + 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); /* locked */ + snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); /* locked */ + snd_pcm_sframes_t (*forwardable)(snd_pcm_t *pcm); /* locked */ + snd_pcm_sframes_t (*forward)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); /* locked */ + snd_pcm_sframes_t (*writei)(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); /* need own locking */ + snd_pcm_sframes_t (*writen)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); /* need own locking */ + snd_pcm_sframes_t (*readi)(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); /* need own locking */ + snd_pcm_sframes_t (*readn)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); /* need own locking */ + snd_pcm_sframes_t (*avail_update)(snd_pcm_t *pcm); /* locked */ + snd_pcm_sframes_t (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size); /* locked */ + int (*htimestamp)(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, snd_htimestamp_t *tstamp); /* locked */ + int (*poll_descriptors_count)(snd_pcm_t *pcm); /* locked */ + int (*poll_descriptors)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); /* locked */ + int (*poll_revents)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); /* locked */ + int (*may_wait_for_avail_min)(snd_pcm_t *pcm, snd_pcm_uframes_t avail); + int (*mmap_begin)(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames); /* locked */ +} 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, + 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 */ + snd_pcm_tstamp_type_t tstamp_type; /* timestamp type */ + 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 */ + unsigned int own_state_check:1; /* plugin has own PCM state check */ + 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; +#ifdef THREAD_SAFE_API + int need_lock; /* true = this PCM (plugin) is thread-unsafe, + * thus it needs a lock. + */ + int lock_enabled; /* thread-safety lock is enabled on the system; + * it's set depending on $LIBASOUND_THREAD_SAFE. + */ + pthread_mutex_t lock; +#endif +}; + +/* 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_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) +{ + if (!pcm->ops->channel_info) + return -ENOSYS; + 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 */ + +/* locked versions */ +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); +int __snd_pcm_wait_in_lock(snd_pcm_t *pcm, int timeout); + +static inline snd_pcm_sframes_t __snd_pcm_avail_update(snd_pcm_t *pcm) +{ + if (!pcm->fast_ops->avail_update) + return -ENOSYS; + return pcm->fast_ops->avail_update(pcm->fast_op_arg); +} + +static inline int __snd_pcm_start(snd_pcm_t *pcm) +{ + if (!pcm->fast_ops->start) + return -ENOSYS; + return pcm->fast_ops->start(pcm->fast_op_arg); +} + +static inline snd_pcm_state_t __snd_pcm_state(snd_pcm_t *pcm) +{ + if (!pcm->fast_ops->state) + return -ENOSYS; + return pcm->fast_ops->state(pcm->fast_op_arg); +} + +static inline int __snd_pcm_hwsync(snd_pcm_t *pcm) +{ + if (!pcm->fast_ops->hwsync) + return -ENOSYS; + return pcm->fast_ops->hwsync(pcm->fast_op_arg); +} + +static inline int __snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + if (!pcm->fast_ops->delay) + return -ENOSYS; + return pcm->fast_ops->delay(pcm->fast_op_arg, delayp); +} + +/* 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_playback_avail(snd_pcm_t *pcm, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + snd_pcm_sframes_t avail; + avail = hw_ptr + pcm->buffer_size - 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_playback_avail(snd_pcm_t *pcm) +{ + return __snd_pcm_playback_avail(pcm, *pcm->hw.ptr, *pcm->appl.ptr); +} + +static inline snd_pcm_uframes_t __snd_pcm_capture_avail(snd_pcm_t *pcm, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + snd_pcm_sframes_t avail; + avail = hw_ptr - appl_ptr; + if (avail < 0) + avail += pcm->boundary; + return avail; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm) +{ + return __snd_pcm_capture_avail(pcm, *pcm->hw.ptr, *pcm->appl.ptr); +} + +static inline snd_pcm_uframes_t __snd_pcm_avail(snd_pcm_t *pcm, + const snd_pcm_uframes_t hw_ptr, + const snd_pcm_uframes_t appl_ptr) +{ + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + return __snd_pcm_playback_avail(pcm, hw_ptr, appl_ptr); + else + return __snd_pcm_capture_avail(pcm, hw_ptr, appl_ptr); +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_avail(snd_pcm_t *pcm) +{ + return __snd_pcm_avail(pcm, *pcm->hw.ptr, *pcm->appl.ptr); +} + +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) +{ + return pcm->buffer_size - snd_pcm_mmap_avail(pcm); +} + +static inline snd_pcm_sframes_t snd_pcm_mmap_playback_hw_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t ret = snd_pcm_mmap_playback_hw_avail(pcm); + return (ret >= 0) ? ret : 0; +} + +static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t ret = snd_pcm_mmap_capture_hw_avail(pcm); + return (ret >= 0) ? ret : 0; +} + +static inline snd_pcm_uframes_t snd_pcm_mmap_hw_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_sframes_t ret = snd_pcm_mmap_hw_avail(pcm); + return (ret >= 0) ? ret : 0; +} + +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) +{ + /* lock handled in the callback */ + if (!pcm->fast_ops->writei) + return -ENOSYS; + 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) +{ + /* lock handled in the callback */ + if (!pcm->fast_ops->writen) + return -ENOSYS; + 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) +{ + /* lock handled in the callback */ + if (!pcm->fast_ops->readi) + return -ENOSYS; + 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) +{ + /* lock handled in the callback */ + if (!pcm->fast_ops->readn) + return -ENOSYS; + 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_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +#undef _snd_pcm_hw_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); +} + +#define snd_pcm_conf_generic_id(id) _snd_conf_generic_id(id) + +int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, + 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_S20_LE) | \ + (1U << SND_PCM_FORMAT_S20_BE) | \ + (1U << SND_PCM_FORMAT_U20_LE) | \ + (1U << SND_PCM_FORMAT_U20_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 */ +#ifdef HAVE_CLOCK_GETTIME +static inline void gettimestamp(snd_htimestamp_t *tstamp, + snd_pcm_tstamp_type_t tstamp_type) +{ + clockid_t id; + + switch (tstamp_type) { +#ifdef CLOCK_MONOTONIC_RAW + case SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW: + id = CLOCK_MONOTONIC_RAW; + break; +#endif +#ifdef CLOCK_MONOTONIC + case SND_PCM_TSTAMP_TYPE_MONOTONIC: + id = CLOCK_MONOTONIC; + break; +#endif + default: + id = CLOCK_REALTIME; + break; + } + clock_gettime(id, tstamp); +} +#else /* HAVE_CLOCK_GETTIME */ +static inline void gettimestamp(snd_htimestamp_t *tstamp, + snd_pcm_tstamp_type_t tstamp_type) +{ + struct timeval tv; + + gettimeofday(&tv, 0); + tstamp->tv_sec = tv.tv_sec; + tstamp->tv_nsec = tv.tv_usec * 1000L; +} +#endif /* HAVE_CLOCK_GETTIME */ + +snd_pcm_chmap_query_t ** +_snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t *src); +snd_pcm_chmap_t *_snd_pcm_copy_chmap(const snd_pcm_chmap_t *src); +snd_pcm_chmap_query_t ** +_snd_pcm_copy_chmap_query(snd_pcm_chmap_query_t * const *src); +snd_pcm_chmap_query_t ** +_snd_pcm_parse_config_chmaps(snd_config_t *conf); +snd_pcm_chmap_t * +_snd_pcm_choose_fixed_chmap(snd_pcm_t *pcm, snd_pcm_chmap_query_t * const *maps); + +/* return true if the PCM stream may wait to get avail_min space */ +static inline int snd_pcm_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail) +{ + if (avail >= pcm->avail_min) + return 0; + if (pcm->fast_ops->may_wait_for_avail_min) + return pcm->fast_ops->may_wait_for_avail_min(pcm, avail); + return 1; +} + +/* hack to access to internal period_event in snd_pcm_sw_parmams */ +static inline int sw_get_period_event(const snd_pcm_sw_params_t *params) +{ + return params->reserved[sizeof(params->reserved) / sizeof(params->reserved[0])- 1]; +} + +static inline void sw_set_period_event(snd_pcm_sw_params_t *params, int val) +{ + params->reserved[sizeof(params->reserved) / sizeof(params->reserved[0]) - 1] = val; +} + +#define PCMINABORT(pcm) (((pcm)->mode & SND_PCM_ABORT) != 0) + +#ifdef THREAD_SAFE_API +/* + * __snd_pcm_lock() and __snd_pcm_unlock() are used to lock/unlock the plugin + * forcibly even if it's declared as thread-safe. It's needed only for some + * codes that are thread-unsafe per design (e.g. snd_pcm_nonblock()). + * + * OTOH, snd_pcm_lock() and snd_pcm_unlock() are used to lock/unlock the plugin + * in normal situations. They do lock/unlock only when the plugin is + * thread-unsafe. + * + * Both __snd_pcm_lock() and snd_pcm_lock() (and their unlocks) wouldn't do + * any action when the whole locking is disabled via $LIBASOUND_THREAD_SAFE=0. + */ +static inline void __snd_pcm_lock(snd_pcm_t *pcm) +{ + if (pcm->lock_enabled) + pthread_mutex_lock(&pcm->lock); +} +static inline void __snd_pcm_unlock(snd_pcm_t *pcm) +{ + if (pcm->lock_enabled) + pthread_mutex_unlock(&pcm->lock); +} +static inline void snd_pcm_lock(snd_pcm_t *pcm) +{ + if (pcm->lock_enabled && pcm->need_lock) + pthread_mutex_lock(&pcm->lock); +} +static inline void snd_pcm_unlock(snd_pcm_t *pcm) +{ + if (pcm->lock_enabled && pcm->need_lock) + pthread_mutex_unlock(&pcm->lock); +} +#else /* THREAD_SAFE_API */ +#define __snd_pcm_lock(pcm) do {} while (0) +#define __snd_pcm_unlock(pcm) do {} while (0) +#define snd_pcm_lock(pcm) do {} while (0) +#define snd_pcm_unlock(pcm) do {} while (0) +#endif /* THREAD_SAFE_API */ diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c new file mode 100644 index 0000000..20b4187 --- /dev/null +++ b/src/pcm/pcm_meter.c @@ -0,0 +1,1234 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#include "bswap.h" +#include +#include +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#define atomic_read(ptr) __atomic_load_n(ptr, __ATOMIC_SEQ_CST ) +#define atomic_add(ptr, n) __atomic_add_fetch(ptr, n, __ATOMIC_SEQ_CST) +#define atomic_dec(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST) + +#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; + int 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; + 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_add(&meter->reset, 1); + 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_internal(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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +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, + .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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], errbuf[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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + open_func = h ? dlsym(h, open_name) : NULL; + err = 0; + if (!h) { + SNDERR("Cannot open shared library %s (%s)", lib, errbuf); + 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..7ee0dac --- /dev/null +++ b/src/pcm/pcm_misc.c @@ -0,0 +1,898 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include "bswap.h" +#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_S20_LE: + case SNDRV_PCM_FORMAT_S20_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_U20_LE: + case SNDRV_PCM_FORMAT_U20_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: + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U16_BE: + case SNDRV_PCM_FORMAT_DSD_U32_BE: + 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_S20_LE: + case SNDRV_PCM_FORMAT_U20_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: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + return 1; + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_BE: + case SNDRV_PCM_FORMAT_S20_BE: + case SNDRV_PCM_FORMAT_U20_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: + case SNDRV_PCM_FORMAT_DSD_U16_BE: + case SNDRV_PCM_FORMAT_DSD_U32_BE: + 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: + case SNDRV_PCM_FORMAT_DSD_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: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_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_LE: + case SNDRV_PCM_FORMAT_S20_BE: + case SNDRV_PCM_FORMAT_U20_LE: + case SNDRV_PCM_FORMAT_U20_BE: + 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: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U32_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: + case SNDRV_PCM_FORMAT_DSD_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: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_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_S20_LE: + case SNDRV_PCM_FORMAT_S20_BE: + case SNDRV_PCM_FORMAT_U20_LE: + case SNDRV_PCM_FORMAT_U20_BE: + 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: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U32_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: + case SNDRV_PCM_FORMAT_DSD_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: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_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_S20_LE: + case SNDRV_PCM_FORMAT_S20_BE: + case SNDRV_PCM_FORMAT_U20_LE: + case SNDRV_PCM_FORMAT_U20_BE: + 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_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U32_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 + */ +uint64_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_S20_LE: + case SNDRV_PCM_FORMAT_S20_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; + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U16_BE: + case SNDRV_PCM_FORMAT_DSD_U32_BE: + return 0x6969696969696969ULL; +#ifdef SNDRV_LITTLE_ENDIAN + case SNDRV_PCM_FORMAT_U16_LE: + return 0x8000800080008000ULL; + case SNDRV_PCM_FORMAT_U20_LE: + return 0x0008000000080000ULL; + 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_U20_BE: + return 0x0000080000000800ULL; + 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_U20_LE: + return 0x0000080000000800ULL; + 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_U20_BE: + return 0x0008000000080000ULL; + 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]; + uint64_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; + uint64_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]; + uint64_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; + uint64_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 + */ +uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format) +{ + assert(snd_pcm_format_physical_width(format) <= 32); + return (uint32_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 + */ +uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format) +{ + assert(snd_pcm_format_physical_width(format) <= 16); + return (uint16_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 + */ +uint8_t snd_pcm_format_silence(snd_pcm_format_t format) +{ + assert(snd_pcm_format_physical_width(format) <= 8); + return (uint8_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: { + uint8_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: { + uint8_t silence = snd_pcm_format_silence_64(format); + memset(data, silence, samples); + break; + } + case 16: { + uint16_t silence = snd_pcm_format_silence_64(format); + uint16_t *pdata = (uint16_t *)data; + if (! silence) + memset(data, 0, samples * 2); + else { + while (samples-- > 0) + *pdata++ = silence; + } + break; + } + case 24: { + uint32_t silence = snd_pcm_format_silence_64(format); + uint8_t *pdata = (uint8_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: { + uint32_t silence = snd_pcm_format_silence_64(format); + uint32_t *pdata = (uint32_t *)data; + if (! silence) + memset(data, 0, samples * 4); + else { + while (samples-- > 0) + *pdata++ = silence; + } + break; + } + case 64: { + uint64_t silence = snd_pcm_format_silence_64(format); + uint64_t *pdata = (uint64_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[5][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_S20_LE, SNDRV_PCM_FORMAT_S20_BE }, + { SNDRV_PCM_FORMAT_U20_LE, SNDRV_PCM_FORMAT_U20_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 20: + width = 2; + break; + case 24: + width = 3; + break; + case 32: + width = 4; + 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..9600c38 --- /dev/null +++ b/src/pcm/pcm_mmap.c @@ -0,0 +1,636 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SHM_H +#include +#endif +#include "pcm_local.h" + +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; + } + if (pcm->ops->mmap) + err = pcm->ops->mmap(pcm); + else + err = -ENOSYS; + 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) { + free(pcm->mmap_channels); + free(pcm->running_areas); + pcm->mmap_channels = NULL; + pcm->running_areas = NULL; + 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: +#ifdef HAVE_SYS_SHM_H + 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; +#else + SYSERR("shm support not available"); + return -ENOSYS; +#endif + 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; + /* fall through */ + 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) { + if (pcm->ops->munmap) + return pcm->ops->munmap(pcm); + else + return -ENOSYS; + } + 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: +#ifdef HAVE_SYS_SHM_H + 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; +#else + SYSERR("shm support not available"); + return -ENOSYS; +#endif + case SND_PCM_AREA_LOCAL: + free(i->addr); + break; + default: + assert(0); + } + i->addr = NULL; + } + if (pcm->ops->munmap) + err = pcm->ops->munmap(pcm); + else + err = -ENOSYS; + if (err < 0) + return err; + free(pcm->mmap_channels); + free(pcm->running_areas); + pcm->mmap_channels = NULL; + pcm->running_areas = NULL; + return 0; +} + +/* called in pcm lock */ +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); + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = _snd_pcm_writei(pcm, buf, frames); + snd_pcm_lock(pcm); + 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); + } + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = _snd_pcm_writen(pcm, bufs, frames); + snd_pcm_lock(pcm); + 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; +} + +/* called in pcm lock */ +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); + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = _snd_pcm_readi(pcm, buf, frames); + snd_pcm_lock(pcm); + 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); + } + snd_pcm_unlock(pcm); /* to avoid deadlock */ + err = _snd_pcm_readn(pcm->fast_op_arg, bufs, frames); + snd_pcm_lock(pcm); + 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; +} diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c new file mode 100644 index 0000000..009cebb --- /dev/null +++ b/src/pcm/pcm_mmap_emul.c @@ -0,0 +1,514 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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_internal(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_internal(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; + + if (!map->mmap_emul) + return snd_pcm_generic_sw_params(pcm, params); + + 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; + + snd_pcm_mmap_appl_forward(pcm, size); + if (!map->mmap_emul) + return snd_pcm_mmap_commit(slave, offset, 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; + + if (!map->mmap_emul || 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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +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, + .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, +}; + +#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->tstamp_type = slave->tstamp_type; + 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..73b0c3b --- /dev/null +++ b/src/pcm/pcm_mulaw.c @@ -0,0 +1,570 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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->tstamp_type = slave->tstamp_type; + 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..53c414d --- /dev/null +++ b/src/pcm/pcm_multi.c @@ -0,0 +1,1451 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 { + snd_pcm_uframes_t appl_ptr, hw_ptr; + 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 void snd_pcm_multi_hwptr_update(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_uframes_t hw_ptr = 0, slave_hw_ptr, avail, last_avail; + unsigned int i; + /* the logic is really simple, choose the lowest hw_ptr from slaves */ + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + last_avail = 0; + for (i = 0; i < multi->slaves_count; ++i) { + slave_hw_ptr = *multi->slaves[i].pcm->hw.ptr; + avail = __snd_pcm_playback_avail(pcm, multi->hw_ptr, slave_hw_ptr); + if (avail > last_avail) { + hw_ptr = slave_hw_ptr; + last_avail = avail; + } + } + } else { + last_avail = LONG_MAX; + for (i = 0; i < multi->slaves_count; ++i) { + slave_hw_ptr = *multi->slaves[i].pcm->hw.ptr; + avail = __snd_pcm_capture_avail(pcm, multi->hw_ptr, slave_hw_ptr); + if (avail < last_avail) { + hw_ptr = slave_hw_ptr; + last_avail = avail; + } + } + } + multi->hw_ptr = hw_ptr; +} + +static int snd_pcm_multi_hwsync(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + int err; + for (i = 0; i < multi->slaves_count; ++i) { + err = snd_pcm_hwsync(multi->slaves[i].pcm); + if (err < 0) + return err; + } + snd_pcm_multi_hwptr_update(pcm); + return 0; +} + +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_sframes_t d, dr = 0; + unsigned int i; + int err; + for (i = 0; i < multi->slaves_count; ++i) { + err = snd_pcm_delay(multi->slaves[i].pcm, &d); + if (err < 0) + return err; + if (dr < d) + dr = d; + } + *delayp = dr; + return 0; +} + +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; + } + snd_pcm_multi_hwptr_update(pcm); + 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; + } + multi->hw_ptr = multi->appl_ptr = 0; + 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; + } + multi->hw_ptr = multi->appl_ptr = 0; + 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_rewindable(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + snd_pcm_sframes_t frames = LONG_MAX; + + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_sframes_t f = snd_pcm_rewindable(multi->slaves[i].pcm); + if (f <= 0) + return f; + if (f < frames) + frames = f; + } + + return frames; + +} + +static snd_pcm_sframes_t snd_pcm_multi_forwardable(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + snd_pcm_sframes_t frames = LONG_MAX; + + for (i = 0; i < multi->slaves_count; ++i) { + snd_pcm_sframes_t f = snd_pcm_forwardable(multi->slaves[i].pcm); + if (f <= 0) + return f; + if (f < frames) + frames = f; + } + + return frames; + +} + +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; + } + multi->appl_ptr += size; + multi->appl_ptr %= pcm->boundary; + 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 int snd_pcm_multi_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail) +{ + snd_pcm_multi_t *multi = pcm->private_data; + unsigned int i; + for (i = 0; i < multi->slaves_count; ++i) { + if (snd_pcm_may_wait_for_avail_min(multi->slaves[i].pcm, avail)) + return 1; + } + return 0; +} + +static snd_pcm_chmap_query_t **snd_pcm_multi_query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_chmap_query_t **slave_maps[multi->slaves_count]; + snd_pcm_chmap_query_t **maps; + unsigned int i; + int err = -ENOMEM; + + memset(slave_maps, 0, sizeof(slave_maps)); + maps = calloc(2, sizeof(*maps)); + if (!maps) + return NULL; + maps[0] = calloc(multi->channels_count + 2, sizeof(int *)); + if (!maps[0]) + goto error; + maps[0]->type = SND_CHMAP_TYPE_FIXED; + maps[0]->map.channels = multi->channels_count; + + for (i = 0; i < multi->slaves_count; i++) { + slave_maps[i] = snd_pcm_query_chmaps(multi->slaves[i].pcm); + if (!slave_maps[i]) + goto error; + } + + for (i = 0; i < multi->channels_count; i++) { + snd_pcm_multi_channel_t *bind = &multi->channels[i]; + unsigned int slave_channels = + multi->slaves[bind->slave_idx].channels_count; + snd_pcm_chmap_query_t **p; + + for (p = slave_maps[bind->slave_idx]; *p; p++) { + if ((*p)->map.channels == slave_channels) { + maps[0]->map.pos[i] = + (*p)->map.pos[bind->slave_channel]; + break; + } + } + } + err = 0; + + error: + for (i = 0; i < multi->slaves_count; i++) { + if (slave_maps[i]) + snd_pcm_free_chmaps(slave_maps[i]); + } + + if (err) { + snd_pcm_free_chmaps(maps); + return NULL; + } + + return maps; +} + +static snd_pcm_chmap_t *snd_pcm_multi_get_chmap(snd_pcm_t *pcm) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_chmap_t *map; + snd_pcm_chmap_t *slave_maps[multi->slaves_count]; + unsigned int i; + int err = -ENOMEM; + + memset(slave_maps, 0, sizeof(slave_maps)); + map = calloc(multi->channels_count + 1, sizeof(int)); + if (!map) + return NULL; + + for (i = 0; i < multi->slaves_count; i++) { + slave_maps[i] = snd_pcm_get_chmap(multi->slaves[i].pcm); + if (!slave_maps[i]) + goto error; + } + + map->channels = multi->channels_count; + for (i = 0; i < multi->channels_count; i++) { + snd_pcm_multi_channel_t *bind = &multi->channels[i]; + map->pos[i] = slave_maps[bind->slave_idx]->pos[bind->slave_channel]; + } + err = 0; + + error: + for (i = 0; i < multi->slaves_count; i++) + free(slave_maps[i]); + + if (err) { + free(map); + return NULL; + } + + return map; +} + +static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) +{ + snd_pcm_multi_t *multi = pcm->private_data; + snd_pcm_chmap_t *slave_maps[multi->slaves_count]; + unsigned int i; + int err = 0; + + if (map->channels != multi->channels_count) + return -EINVAL; + + for (i = 0; i < multi->slaves_count; i++) { + slave_maps[i] = calloc(multi->slaves[i].channels_count + 1, + sizeof(int)); + if (!slave_maps[i]) { + for (i++; i < multi->slaves_count; i++) + slave_maps[i] = NULL; + err = -ENOMEM; + goto error; + } + } + + for (i = 0; i < multi->channels_count; i++) { + snd_pcm_multi_channel_t *bind = &multi->channels[i]; + slave_maps[bind->slave_idx]->pos[bind->slave_channel] = + map->pos[i]; + } + + for (i = 0; i < multi->slaves_count; i++) { + err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_maps[i]); + if (err < 0) + goto error; + } + + error: + for (i = 0; i < multi->slaves_count; i++) + free(slave_maps[i]); + + return err; +} + +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, + .query_chmaps = snd_pcm_multi_query_chmaps, + .get_chmap = snd_pcm_multi_get_chmap, + .set_chmap = snd_pcm_multi_set_chmap, +}; + +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, + .rewindable = snd_pcm_multi_rewindable, + .rewind = snd_pcm_multi_rewind, + .forwardable = snd_pcm_multi_forwardable, + .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, + .may_wait_for_avail_min = snd_pcm_multi_may_wait_for_avail_min, +}; + +/** + * \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; + 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; + } + 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->slaves); + free(multi->channels); + 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->tstamp_type = multi->slaves[master_slave].pcm->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &multi->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &multi->appl_ptr, -1, 0); + *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..1d81548 --- /dev/null +++ b/src/pcm/pcm_null.c @@ -0,0 +1,503 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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_chmap_query_t **chmap; +} 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) { + snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id)); + snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name)); + snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname)); + } + info->subdevices_count = 1; + return 0; +} + +static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + if (null->state == SND_PCM_STATE_PREPARED) { + /* it is required to return the correct avail count for */ + /* the prepared stream, otherwise the start is not called */ + return snd_pcm_mmap_avail(pcm); + } + return pcm->buffer_size; +} + +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->tstamp_type); + status->avail = snd_pcm_null_avail_update(pcm); + status->avail_max = pcm->buffer_size; + 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_reset(snd_pcm_t *pcm) +{ + *pcm->appl.ptr = 0; + *pcm->hw.ptr = 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; + return snd_pcm_null_reset(pcm); +} + +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_rewindable(snd_pcm_t *pcm) +{ + return pcm->buffer_size; +} + +static snd_pcm_sframes_t snd_pcm_null_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + 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 int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) +{ + int err; + + /* Do not return a period size of 0 because for example portaudio cannot + * handle it. + */ + err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_PERIOD_SIZE, 1, + 0); + if (err < 0) + return err; + + 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 snd_pcm_chmap_query_t **snd_pcm_null_query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + + if (null->chmap) + return _snd_pcm_copy_chmap_query(null->chmap); + return NULL; +} + +static snd_pcm_chmap_t *snd_pcm_null_get_chmap(snd_pcm_t *pcm) +{ + snd_pcm_null_t *null = pcm->private_data; + + if (null->chmap) + return _snd_pcm_choose_fixed_chmap(pcm, null->chmap); + return NULL; +} + +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, + .query_chmaps = snd_pcm_null_query_chmaps, + .get_chmap = snd_pcm_null_get_chmap, + .set_chmap = NULL, +}; + +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, + .rewindable = snd_pcm_null_rewindable, + .rewind = snd_pcm_null_rewind, + .forwardable = snd_pcm_null_forwardable, + .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 + [chmap MAP] # Provide channel maps; MAP is a string array +} +\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_pcm_null_t *null; + snd_pcm_chmap_query_t **chmap = NULL; + 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, "chmap") == 0) { + snd_pcm_free_chmaps(chmap); + chmap = _snd_pcm_parse_config_chmaps(n); + if (!chmap) { + SNDERR("Invalid channel map for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + snd_pcm_free_chmaps(chmap); + return -EINVAL; + } + err = snd_pcm_null_open(pcmp, name, stream, mode); + if (err < 0) { + snd_pcm_free_chmaps(chmap); + return err; + } + + null = (*pcmp)->private_data; + null->chmap = chmap; + return 0; +} +#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..ceb3b1a --- /dev/null +++ b/src/pcm/pcm_params.c @@ -0,0 +1,2447 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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])) +#define PCM_BIT(x) \ + (1U << ((x) < 32 ? (x) : ((x) - 32))) + +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 = { + PCM_BIT(SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | + PCM_BIT(SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) | + PCM_BIT(SNDRV_PCM_ACCESS_MMAP_COMPLEX) | + PCM_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED) | + PCM_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) + }, + }, + [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = { + .bits = { + /* first 32bits */ + PCM_BIT(SNDRV_PCM_FORMAT_S8) | + PCM_BIT(SNDRV_PCM_FORMAT_U8) | + PCM_BIT(SNDRV_PCM_FORMAT_S16_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S16_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U16_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U16_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_S24_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S24_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U24_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U24_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_S32_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S32_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U32_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U32_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) | + PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) | + PCM_BIT(SNDRV_PCM_FORMAT_MU_LAW) | + PCM_BIT(SNDRV_PCM_FORMAT_A_LAW) | + PCM_BIT(SNDRV_PCM_FORMAT_IMA_ADPCM) | + PCM_BIT(SNDRV_PCM_FORMAT_MPEG) | + PCM_BIT(SNDRV_PCM_FORMAT_GSM) | + PCM_BIT(SNDRV_PCM_FORMAT_S20_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S20_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U20_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U20_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_SPECIAL), + /* second 32bits */ + PCM_BIT(SNDRV_PCM_FORMAT_S24_3LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S24_3BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U24_3LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U24_3BE) | + PCM_BIT(SNDRV_PCM_FORMAT_S20_3LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S20_3BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U20_3LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U20_3BE) | + PCM_BIT(SNDRV_PCM_FORMAT_S18_3LE) | + PCM_BIT(SNDRV_PCM_FORMAT_S18_3BE) | + PCM_BIT(SNDRV_PCM_FORMAT_U18_3LE) | + PCM_BIT(SNDRV_PCM_FORMAT_U18_3BE) | + PCM_BIT(SNDRV_PCM_FORMAT_G723_24) | + PCM_BIT(SNDRV_PCM_FORMAT_G723_24) | + PCM_BIT(SNDRV_PCM_FORMAT_G723_40) | + PCM_BIT(SNDRV_PCM_FORMAT_G723_40) | + PCM_BIT(SNDRV_PCM_FORMAT_DSD_U8) | + PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_LE) | + PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_BE) | + PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_BE) + }, + }, + [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = { + .bits = { + PCM_BIT(SNDRV_PCM_SUBFORMAT_STD) + }, + }, +}; + +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); + if (err < 0) + return err; + err = schange(pcm, params, &slave_params); + if (err < 0) + return err; + 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->proto = SNDRV_PCM_VERSION; + params->tstamp_mode = SND_PCM_TSTAMP_NONE; + params->tstamp_type = pcm->tstamp_type; + 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 + if (pcm->ops->hw_refine) + res = pcm->ops->hw_refine(pcm->op_arg, params); + else + res = -ENOSYS; +#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_internal(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; + } + if (pcm->ops->hw_params) + err = pcm->ops->hw_params(pcm->op_arg, params); + else + err = -ENOSYS; + 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); + if (err < 0) + return err; + + 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..abf6f1a --- /dev/null +++ b/src/pcm/pcm_plug.c @@ -0,0 +1,1336 @@ +/* + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + snd_config_t *rate_converter; + enum snd_pcm_plug_route_policy route_policy; + snd_pcm_route_ttable_entry_t *ttable; + int ttable_ok; + 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); + if (plug->rate_converter) { + snd_config_delete(plug->rate_converter); + plug->rate_converter = NULL; + } + 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_S20_LE, + SND_PCM_FORMAT_U20_LE, + SND_PCM_FORMAT_S20_BE, + SND_PCM_FORMAT_U20_BE, +#else + SND_PCM_FORMAT_S20_BE, + SND_PCM_FORMAT_U20_BE, + SND_PCM_FORMAT_S20_LE, + SND_PCM_FORMAT_U20_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_ok)) + 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 && + (!plug->ttable || plug->ttable_ok)) + return 0; + + if (snd_pcm_format_linear(slv->format)) { + /* Conversion is done in another plugin */ + if (clt->rate != slv->rate || + clt->channels != slv->channels || + (plug->ttable && !plug->ttable_ok)) + 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)) { + if (snd_pcm_format_linear(clt->format)) { + cfmt = clt->format; + f = snd_pcm_lfloat_open; + } else if (clt->rate != slv->rate || clt->channels != slv->channels || + (plug->ttable && !plug->ttable_ok)) { + cfmt = SND_PCM_FORMAT_S16; + 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 = 0; + while (client->format != p.format || + client->channels != p.channels || + client->rate != p.rate || + client->access != p.access || + (plug->ttable && !plug->ttable_ok)) { + snd_pcm_t *new; + int err; + if (k >= sizeof(funcs)/sizeof(*funcs)) { + snd_pcm_plug_clear(pcm); + 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; + } + k++; + } + 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_internal(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); + + pcm->fast_ops = slave->fast_ops; + pcm->fast_op_arg = slave->fast_op_arg; + 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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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->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; + if (rate_converter) { + err = snd_config_copy(&plug->rate_converter, + (snd_config_t *)rate_converter); + if (err < 0) { + snd_pcm_free(pcm); + free(plug); + return err; + } + } + pcm->private_data = plug; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; + pcm->tstamp_type = slave->tstamp_type; + 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..ea60eb9 --- /dev/null +++ b/src/pcm/pcm_plugin.c @@ -0,0 +1,651 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "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; +} + +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; + err = snd_pcm_prepare(plugin->gen.slave); + if (err < 0) + return err; + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + 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; + err = snd_pcm_reset(plugin->gen.slave); + if (err < 0) + return err; + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + 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_rewindable(pcm); +} + +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_plugin_rewindable(pcm); + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n < frames) + frames = n; + if (frames == 0) + return 0; + + sframes = frames; + sframes = snd_pcm_rewind(plugin->gen.slave, sframes); + if (sframes < 0) + return sframes; + snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) sframes); + return (snd_pcm_sframes_t) sframes; +} + +static snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm) +{ + return snd_pcm_mmap_avail(pcm); +} + +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_plugin_forwardable(pcm); + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n < frames) + frames = n; + if (frames == 0) + return 0; + + sframes = frames; + sframes = INTERNAL(snd_pcm_forward)(plugin->gen.slave, sframes); + if (sframes < 0) + return sframes; + snd_pcm_mmap_appl_forward(pcm, (snd_pcm_uframes_t) frames); + 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; + + result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) { + err = result; + goto error; + } + if (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)); + err = -EPIPE; + goto error; + } + 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) { + err = res; + goto error; + } + frames -= res; + } + if (result <= 0) { + err = result; + goto error; + } + snd_pcm_mmap_appl_forward(pcm, frames); + offset += frames; + xfer += frames; + size -= frames; + } + return (snd_pcm_sframes_t)xfer; + + error: + return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; +} + +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; + 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; + + result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) { + err = result; + goto error; + } + 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)); + err = -EPIPE; + goto error; + } + 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) { + err = res; + goto error; + } + frames -= res; + } + if (result <= 0) { + err = result; + goto error; + } + snd_pcm_mmap_appl_forward(pcm, frames); + offset += frames; + xfer += frames; + size -= frames; + } + return (snd_pcm_sframes_t)xfer; + + error: + return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; +} + + +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; + int err; + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + snd_pcm_mmap_appl_forward(pcm, size); + 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; + + result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) { + err = result; + goto error; + } + if (frames > cont) + frames = cont; + frames = plugin->write(pcm, areas, appl_offset, frames, + slave_areas, slave_offset, &slave_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) { + err = res; + goto error; + } + frames -= res; + } + if (result <= 0) { + err = result; + goto error; + } + snd_pcm_mmap_appl_forward(pcm, frames); + 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; + + error: + return xfer > 0 ? xfer : err; +} + +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; + int err; + + 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; + /* As mentioned in the ALSA API (see pcm/pcm.c:942): + * The function #snd_pcm_avail_update() + * have to be called before any mmap begin+commit operation. + * Otherwise the snd_pcm_areas_copy will not called a second time. + * But this is needed, if the ring buffer wrap is reached and + * there is more data available. + */ + slave_size = snd_pcm_avail_update(slave); + result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) { + err = result; + goto error; + } + if (frames > cont) + frames = cont; + frames = (plugin->read)(pcm, areas, hw_offset, frames, + slave_areas, slave_offset, &slave_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, hw_offset, frames, slave_frames - result); + if (res < 0) { + err = res; + goto error; + } + frames -= res; + } + if (result <= 0) { + err = result; + goto error; + } + snd_pcm_mmap_hw_forward(pcm, frames); + if (frames == cont) + hw_offset = 0; + else + hw_offset += frames; + size -= frames; + slave_size -= slave_frames; + xfer += frames; + } + return (snd_pcm_sframes_t)xfer; + + error: + return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; + } +} + +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; + + /* 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) + return err; + status->appl_ptr = *pcm->appl.ptr; + status->hw_ptr = *pcm->hw.ptr; + return 0; +} + +int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, + snd_pcm_uframes_t avail) +{ + if (pcm->stream == SND_PCM_STREAM_CAPTURE && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { + /* mmap access on capture device already consumes data from + * slave in avail_update operation. Entering snd_pcm_wait after + * having already consumed some fragments leads to waiting for + * too long time, as slave will unnecessarily wait for avail_min + * condition reached again. To avoid unnecessary wait times we + * adapt the avail_min threshold on slave dynamically. Just + * modifying slave->avail_min as a shortcut and lightweight + * solution does not work for all slave plugin types and in + * addition it will not propagate the change through all + * downstream plugins, so we have to use the sw_params API. + * note: reading fragmental parts from slave will only happen + * in case + * a) the slave can provide contineous hw_ptr between periods + * b) avail_min does not match one slave_period + */ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; + snd_pcm_uframes_t needed_slave_avail_min; + snd_pcm_sframes_t available; + + /* update, as it might have changed. This will also call + * avail_update on slave and also can return error + */ + available = snd_pcm_avail_update(pcm); + if (available < 0) + return 0; + + if ((snd_pcm_uframes_t)available >= pcm->avail_min) + /* don't wait at all. As we can't configure avail_min + * of slave to 0 return here + */ + return 0; + + needed_slave_avail_min = pcm->avail_min - available; + if (slave->avail_min != needed_slave_avail_min) { + snd_pcm_sw_params_t *swparams; + snd_pcm_sw_params_alloca(&swparams); + /* pray that changing sw_params while running is + * properly implemented in all downstream plugins... + * it's legal but not commonly used. + */ + snd_pcm_sw_params_current(slave, swparams); + /* snd_pcm_sw_params_set_avail_min() restricts setting + * to >= period size. This conflicts at least with our + * dshare patch which allows combining multiple periods + * or with slaves which return hw postions between + * periods -> set directly in sw_param structure + */ + swparams->avail_min = needed_slave_avail_min; + snd_pcm_sw_params(slave, swparams); + } + avail = available; + } + return snd_pcm_generic_may_wait_for_avail_min(pcm, avail); +} + +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, + .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, +}; + +#endif diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h new file mode 100644 index 0000000..d7788b2 --- /dev/null +++ b/src/pcm/pcm_plugin.h @@ -0,0 +1,155 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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_pcm_plugin_t; + +/* make local functions really local */ +#define snd_pcm_plugin_init \ + snd1_pcm_plugin_init +#define snd_pcm_plugin_may_wait_for_avail_min \ + snd1_pcm_plugin_may_wait_for_avail_min +#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 +#define snd_pcm_plugin_rewind \ + snd1_pcm_plugin_rewind +#define snd_pcm_plugin_forward \ + snd1_pcm_plugin_forward + +void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin); +snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); +int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail); + +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_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_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..fdcaa8d --- /dev/null +++ b/src/pcm/pcm_rate.c @@ -0,0 +1,1599 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include "bswap.h" +#include "pcm_local.h" +#include "pcm_plugin.h" +#include "pcm_rate.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_pcm_uframes_t appl_ptr, hw_ptr, last_slave_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 = (char *)rate->pareas[0].addr + (cwidth * chn * cinfo->period_size) / 8; + rate->pareas[chn].first = 0; + rate->pareas[chn].step = cwidth; + rate->sareas[chn].addr = (char *)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 = (int16_t *)src_areas->addr + src_offset * 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 = (int16_t *)dst_areas->addr + dst_offset * 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 void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) +{ + snd_pcm_rate_t *rate = pcm->private_data; + + snd_pcm_sframes_t slave_hw_ptr_diff = slave_hw_ptr - rate->last_slave_hw_ptr; + snd_pcm_sframes_t last_slave_hw_ptr_frac; + + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return; + + if (slave_hw_ptr_diff < 0) + slave_hw_ptr_diff += rate->gen.slave->boundary; /* slave boundary wraparound */ + else if (slave_hw_ptr_diff == 0) + return; + last_slave_hw_ptr_frac = rate->last_slave_hw_ptr % rate->gen.slave->period_size; + /* While handling fraction part fo slave period, rounded value will be + * introduced by input_frames(). + * To eliminate rounding issue on rate->hw_ptr, subtract last rounded + * value from rate->hw_ptr and add new rounded value of present + * slave_hw_ptr fraction part to rate->hw_ptr. Hence, + * rate->hw_ptr += [ (no. of updated slave periods * pcm rate period size) - + * fractional part of last_slave_hw_ptr rounded value + + * fractional part of updated slave hw ptr's rounded value ] + */ + rate->hw_ptr += ( + (((last_slave_hw_ptr_frac + slave_hw_ptr_diff) / rate->gen.slave->period_size) * pcm->period_size) - + rate->ops.input_frames(rate->obj, last_slave_hw_ptr_frac) + + rate->ops.input_frames(rate->obj, (last_slave_hw_ptr_frac + slave_hw_ptr_diff) % rate->gen.slave->period_size)); + rate->last_slave_hw_ptr = slave_hw_ptr; + + rate->hw_ptr %= pcm->boundary; +} + +static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_rate_sync_hwptr0(pcm, *rate->gen.slave->hw.ptr); +} + +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_pcm_rate_sync_hwptr(pcm); + return 0; +} + +static snd_pcm_uframes_t snd_pcm_rate_playback_internal_delay(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + + if (rate->appl_ptr < rate->last_commit_ptr) { + return rate->appl_ptr - rate->last_commit_ptr + pcm->boundary; + } else { + return rate->appl_ptr - rate->last_commit_ptr; + } +} + +static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_sframes_t slave_delay; + int err; + + snd_pcm_rate_hwsync(pcm); + + err = snd_pcm_delay(rate->gen.slave, &slave_delay); + if (err < 0) { + return err; + } + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + *delayp = rate->ops.input_frames(rate->obj, slave_delay) + + snd_pcm_rate_playback_internal_delay(pcm); + } else { + *delayp = rate->ops.output_frames(rate->obj, slave_delay) + + 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; + + err = snd_pcm_prepare(rate->gen.slave); + if (err < 0) + return err; + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + rate->last_slave_hw_ptr = 0; + 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; + err = snd_pcm_reset(rate->gen.slave); + if (err < 0) + return err; + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; + rate->last_slave_hw_ptr = 0; + err = snd_pcm_rate_init(pcm); + if (err < 0) + return err; + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_rewindable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +{ + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + snd_pcm_uframes_t frames ATTRIBUTE_UNUSED) +{ + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_forward(snd_pcm_t *pcm ATTRIBUTE_UNUSED, + snd_pcm_uframes_t frames ATTRIBUTE_UNUSED) +{ + return 0; +} + +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_pcm_mmap_appl_forward(pcm, size); + 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_sframes_t slave_size; + + slave_size = snd_pcm_avail_update(slave); + if (slave_size < 0) + return slave_size; + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + goto _capture; + snd_pcm_rate_sync_hwptr(pcm); + 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 && + (snd_pcm_uframes_t)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); +} + +/* locking */ +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; + + __snd_pcm_lock(pcm); + /* 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; + int err; + + err = __snd_pcm_wait_in_lock(rate->gen.slave, -1); + if (err < 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); + __snd_pcm_unlock(pcm); + } + 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_sframes_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->tstamp_type); + + avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave); + if (avail < 0) /* can't happen on healthy drivers */ + return -EBADFD; + + 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; + + err = snd_pcm_status(rate->gen.slave, status); + if (err < 0) + 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_hwptr0(pcm, status->hw_ptr); + status->appl_ptr = *pcm->appl.ptr; + status->hw_ptr = *pcm->hw.ptr; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + status->delay = rate->ops.input_frames(rate->obj, status->delay) + + snd_pcm_rate_playback_internal_delay(pcm); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max); + } else { + /* FIXME: Maybe possible to somthing similar to + * snd_pcm_rate_playback_internal_delay() + * for the capture case. + */ + status->delay = rate->ops.output_frames(rate->obj, 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); + } + 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, + .rewindable = snd_pcm_rate_rewindable, + .rewind = snd_pcm_rate_rewind, + .forwardable = snd_pcm_rate_forwardable, + .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, + .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, +}; + +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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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, const snd_config_t *converter_conf, int verbose) +{ + char open_name[64], open_conf_name[64], lib_name[128], *lib = NULL; + snd_pcm_rate_open_func_t open_func; + snd_pcm_rate_open_conf_func_t open_conf_func; + int err; + + snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type); + snprintf(open_conf_name, sizeof(open_conf_name), "_snd_pcm_rate_%s_open_conf", 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; + } + + rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; + rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; + rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; + + open_conf_func = snd_dlobj_cache_get(lib, open_conf_name, NULL, verbose && converter_conf != NULL); + if (open_conf_func) { + err = open_conf_func(SND_PCM_RATE_PLUGIN_VERSION, + &rate->obj, &rate->ops, converter_conf); + 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); + rate->open_func = open_conf_func; + return 0; + } else { + snd_dlobj_cache_put(open_conf_func); + return err; + } + } + + open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose); + if (!open_func) + return -ENOENT; + + rate->open_func = open_func; + + 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 + +/* + * If the conf is an array of alternatives then the id of + * the first element will be "0" (or maybe NULL). Otherwise assume it is + * a structure. + */ +static int is_string_array(const snd_config_t *conf) +{ + snd_config_iterator_t i; + + if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) + return 0; + + i = snd_config_iterator_first(conf); + if (i && i != snd_config_iterator_end(conf)) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + return 0; + if (id && strcmp(id, "0") != 0) + return 0; + } + + return 1; +} + +/** + * \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; + + 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, NULL, 0); + if (!err) { + type = *types; + break; + } + } + } else if (!snd_config_get_string(converter, &type)) + err = rate_open_func(rate, type, NULL, 1); + else if (is_string_array(converter)) { + 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, NULL, 0); + if (!err) + break; + } + } 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); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "name") != 0) + continue; + snd_config_get_string(n, &type); + break; + } + if (!type) { + SNDERR("No name given for rate converter"); + snd_pcm_free(pcm); + free(rate); + return -EINVAL; + } + err = rate_open_func(rate, type, converter, 1); + } else { + SNDERR("Invalid type for rate converter"); + snd_pcm_free(pcm); + free(rate); + return -EINVAL; + } + if (err < 0) { + SNDERR("Cannot find rate converter"); + snd_pcm_free(pcm); + free(rate); + 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_free(pcm); + free(rate); + 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_free(pcm); + free(rate); + 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->tstamp_type = slave->tstamp_type; + 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 + # or + converter { # optional + name STR # Convertor type + xxx yyy # optional convertor-specific configuration + } +} +\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..53ce902 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "bswap.h" +#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 768000 -> 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 = (((uint64_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 = (((uint64_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..bbcc611 --- /dev/null +++ b/src/pcm/pcm_route.c @@ -0,0 +1,1397 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#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 {UINT64, FLOAT} 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 nsrcs; + 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_chmap_t *chmap; +} 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; + uint32_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 GET32_LABELS +#define PUT32_LABELS +#include "plugin_ops.h" +#undef GET32_LABELS +#undef PUT32_LABELS + static void *const zero_labels[2] = { + &&zero_int64, +#if SND_PCM_PLUGIN_ROUTE_FLOAT + &&zero_float +#endif + }; + /* sum_type att */ + static void *const add_labels[2 * 2] = { + &&add_int64_noatt, &&add_int64_att, +#if SND_PCM_PLUGIN_ROUTE_FLOAT + &&add_float_noatt, &&add_float_att +#endif + }; + /* sum_type att */ + static void *const norm_labels[2 * 2] = { + &&norm_int64_noatt, + &&norm_int64_att, +#if SND_PCM_PLUGIN_ROUTE_FLOAT + &&norm_float, + &&norm_float, +#endif + }; + void *zero, *get32, *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]; + get32 = get32_labels[params->get_idx]; + add = add_labels[params->sum_idx * 2 + ttable->att]; + norm = norm_labels[params->sum_idx * 2 + ttable->att]; + 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_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 *get32; +#define GET32_END after_get +#include "plugin_ops.h" +#undef GET32_END + after_get: + + /* Sum */ + goto *add; + 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_int64_att: + div(sum.as_sint64); + /* fallthru */ + norm_int64_noatt: + 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: + 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); + } + free(route->chmap); + 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; + /* 3 bytes or 20-bit formats? */ + route->params.use_getput = + (snd_pcm_format_physical_width(src_format) + 7) / 8 == 3 || + (snd_pcm_format_physical_width(dst_format) + 7) / 8 == 3 || + snd_pcm_format_width(src_format) == 20 || + snd_pcm_format_width(dst_format) == 20; + route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32); + route->params.put_idx = snd_pcm_linear_put_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 + route->params.sum_idx = UINT64; +#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 snd_pcm_chmap_t *snd_pcm_route_get_chmap(snd_pcm_t *pcm) +{ + snd_pcm_route_t *route = pcm->private_data; + snd_pcm_chmap_t *map, *slave_map; + unsigned int src, dst, nsrcs; + + slave_map = snd_pcm_generic_get_chmap(pcm); + if (!slave_map) + return NULL; + nsrcs = route->params.nsrcs; + map = calloc(4, nsrcs + 1); + if (!map) { + free(slave_map); + return NULL; + } + map->channels = nsrcs; + for (src = 0; src < nsrcs; src++) + map->pos[src] = SND_CHMAP_NA; + for (dst = 0; dst < route->params.ndsts; dst++) { + snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst]; + for (src = 0; src < d->nsrcs; src++) { + unsigned int c = d->srcs[src].channel; + if (c < nsrcs && map->pos[c] == SND_CHMAP_NA) + map->pos[c] = slave_map->pos[dst]; + } + } + free(slave_map); + return map; +} + +static snd_pcm_chmap_query_t **snd_pcm_route_query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_chmap_query_t **maps; + snd_pcm_chmap_t *map = snd_pcm_route_get_chmap(pcm); + if (!map) + return NULL; + maps = _snd_pcm_make_single_query_chmaps(map); + free(map); + return maps; +} + +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); +} + +/* + * Converts a string to an array of channel indices: + * - Given a number, the result is an array with one element, + * containing that number + * - Given a channel name (e g "FL") and a chmap, + * it will look this up in the chmap and return all matches + * - Given a channel name and no chmap, the result is an array with one element, + containing alsa standard channel map. Note that this might be a negative + number in case of "UNKNOWN", "NA" or "MONO". + * Return value is number of matches written. + */ +static int strtochannel(const char *id, snd_pcm_chmap_t *chmap, + long *channel, int channel_size) +{ + int ch; + if (safe_strtol(id, channel) >= 0) + return 1; + + ch = (int) snd_pcm_chmap_from_string(id); + if (ch == -1) + return -EINVAL; + + if (chmap) { + int i, r = 0; + /* Start with highest channel to simplify implementation of + determine ttable size */ + for (i = chmap->channels - 1; i >= 0; i--) { + if ((int) chmap->pos[i] != ch) + continue; + if (r >= channel_size) + continue; + channel[r++] = i; + } + return r; + } + else { + /* Assume ALSA standard channel mapping */ + *channel = ch - SND_CHMAP_FL; + return 1; + } +} + +#define MAX_CHMAP_CHANNELS 256 + +static int determine_chmap(snd_config_t *tt, snd_pcm_chmap_t **tt_chmap) +{ + snd_config_iterator_t i, inext; + snd_pcm_chmap_t *chmap; + + assert(tt && tt_chmap); + chmap = malloc(sizeof(snd_pcm_chmap_t) + + MAX_CHMAP_CHANNELS * sizeof(unsigned int)); + + chmap->channels = 0; + snd_config_for_each(i, inext, tt) { + const char *id; + snd_config_iterator_t j, jnext; + snd_config_t *in = snd_config_iterator_entry(i); + + if (snd_config_get_id(in, &id) < 0) + continue; + if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND) + goto err; + snd_config_for_each(j, jnext, in) { + int ch, k, found; + long schannel; + snd_config_t *jnode = snd_config_iterator_entry(j); + if (snd_config_get_id(jnode, &id) < 0) + continue; + if (safe_strtol(id, &schannel) >= 0) + continue; + ch = (int) snd_pcm_chmap_from_string(id); + if (ch == -1) + goto err; + + found = 0; + for (k = 0; k < (int) chmap->channels; k++) + if (ch == (int) chmap->pos[k]) { + found = 1; + break; + } + if (found) + continue; + + if (chmap->channels >= MAX_CHMAP_CHANNELS) { + SNDERR("Too many channels in ttable chmap"); + goto err; + } + chmap->pos[chmap->channels++] = ch; + } + } + + if (chmap->channels == 0) { + free(chmap); + chmap = NULL; + } + *tt_chmap = chmap; + return 0; + +err: + *tt_chmap = NULL; + free(chmap); + return -EINVAL; +} + +static int find_matching_chmap(snd_pcm_t *spcm, snd_pcm_chmap_t *tt_chmap, + snd_pcm_chmap_t **found_chmap, int *schannels) +{ + snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(spcm); + int i; + + *found_chmap = NULL; + + if (chmaps == NULL) + return 0; /* chmap API not supported for this slave */ + + for (i = 0; chmaps[i]; i++) { + unsigned int j, k; + int match = 1; + snd_pcm_chmap_t *c = &chmaps[i]->map; + if (*schannels >= 0 && (int) c->channels != *schannels) + continue; + + for (j = 0; j < tt_chmap->channels; j++) { + int found = 0; + unsigned int ch = tt_chmap->pos[j]; + for (k = 0; k < c->channels; k++) + if (c->pos[k] == ch) { + found = 1; + break; + } + if (!found) { + match = 0; + break; + } + } + + if (match) { + int size = sizeof(snd_pcm_chmap_t) + c->channels * sizeof(unsigned int); + *found_chmap = malloc(size); + if (!*found_chmap) { + snd_pcm_free_chmaps(chmaps); + return -ENOMEM; + } + memcpy(*found_chmap, c, size); + *schannels = c->channels; + break; + } + } + + snd_pcm_free_chmaps(chmaps); + + if (*found_chmap == NULL) { + SNDERR("Found no matching channel map"); + return -EINVAL; + } + return 0; +} + +static int route_chmap_init(snd_pcm_t *pcm) +{ + int set_map = 0; + snd_pcm_chmap_t *current; + snd_pcm_route_t *route = pcm->private_data; + if (!route->chmap) + return 0; + if (__snd_pcm_state(pcm) != SND_PCM_STATE_PREPARED) + return 0; + + /* Check if we really need to set the chmap or not. + This is important in case set_chmap is not implemented. */ + current = snd_pcm_get_chmap(route->plug.gen.slave); + if (!current) + return -ENOSYS; + if (current->channels != route->chmap->channels) + set_map = 1; + else + set_map = memcmp(current->pos, route->chmap->pos, + current->channels); + free(current); + if (!set_map) + return 0; + + return snd_pcm_set_chmap(route->plug.gen.slave, route->chmap); +} + + +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, + .query_chmaps = snd_pcm_route_query_chmaps, + .get_chmap = snd_pcm_route_get_chmap, + .set_chmap = NULL, /* NYI */ +}; + +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; + params->nsrcs = sused; + 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; + route->plug.init = route_chmap_init; + + 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->tstamp_type = slave->tstamp_type; + 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; +} + +static int _snd_pcm_route_determine_ttable(snd_config_t *tt, + unsigned int *tt_csize, + unsigned int *tt_ssize, + snd_pcm_chmap_t *chmap) +{ + 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 = strtochannel(id, chmap, &schannel, 1); + 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 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) +{ + return _snd_pcm_route_determine_ttable(tt, tt_csize, tt_ssize, NULL); +} + +/** + * \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 + */ +static 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, snd_pcm_chmap_t *chmap) +{ + 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; + int ss; + long *scha = alloca(tt_ssize * sizeof(long)); + const char *id; + if (snd_config_get_id(jnode, &id) < 0) + continue; + + ss = strtochannel(id, chmap, scha, tt_ssize); + if (ss < 0) { + 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; + } + + for (k = 0; (int) k < ss; k++) { + long schannel = scha[k]; + if (schannel < 0 || (unsigned int) schannel > tt_ssize || + (schannels > 0 && schannel >= schannels)) { + SNDERR("Invalid slave channel: %s", id); + return -EINVAL; + } + 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; +} + +/** + * \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) +{ + return _snd_pcm_route_load_ttable(tt, ttable, tt_csize, tt_ssize, + tt_cused, tt_sused, schannels, NULL); +} + +/*! \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. + +SCHANNEL can be a channel name instead of a number (e g FL, LFE). +If so, a matching channel map will be selected for the slave. + +\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_chmap_t *tt_chmap = NULL, *chmap = NULL; + 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 = determine_chmap(tt, &tt_chmap); + if (err < 0) { + free(ttable); + return err; + } + + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); + if (err < 0) { + free(tt_chmap); + free(ttable); + return err; + } + + if (tt_chmap) { + err = find_matching_chmap(spcm, tt_chmap, &chmap, &schannels); + free(tt_chmap); + if (err < 0) { + snd_pcm_close(spcm); + return err; + } + } + + err = _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap); + if (err < 0) { + free(chmap); + snd_pcm_close(spcm); + return err; + } + ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t)); + if (ttable == NULL) { + free(chmap); + snd_pcm_close(spcm); + return -ENOMEM; + } + err = _snd_pcm_route_load_ttable(tt, ttable, csize, ssize, + &cused, &sused, schannels, chmap); + if (err < 0) { + free(chmap); + free(ttable); + snd_pcm_close(spcm); + return err; + } + + err = snd_pcm_route_open(pcmp, name, sformat, schannels, + ttable, ssize, + cused, sused, + spcm, 1); + free(ttable); + if (err < 0) { + free(chmap); + snd_pcm_close(spcm); + } else { + ((snd_pcm_route_t*) (*pcmp)->private_data)->chmap = chmap; + } + + 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..bff9507 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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 " __func__ "\n", *(mutex##_holder)); \ + pthread_mutex_lock(mutex); \ + fprintf(stderr, "... got\n"); \ + } \ + *(mutex##_holder) = __func__; \ +} 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; + else if ((snd_pcm_uframes_t) avail >= pcm->boundary) + 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; + 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); + buffer_size = slave->pcm->buffer_size; + min_frames = slave_avail; + max_frames = 0; + 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"); + Pthread_mutex_unlock(&slave->mutex); + 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"); + Pthread_mutex_unlock(&slave->mutex); + 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_internal(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->tstamp_type); + _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->tstamp_type); + 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->tstamp_type = slave->pcm->tstamp_type; + 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..26a27a5 --- /dev/null +++ b/src/pcm/pcm_shm.c @@ -0,0 +1,907 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; +} + +/** + * \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 *sockname = NULL; + long port = -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 (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) + 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 (!sockname) { + SNDERR("socket is not defined"); + 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..a991315 --- /dev/null +++ b/src/pcm/pcm_simple.c @@ -0,0 +1,299 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) { + 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 = {0}; + snd_pcm_sw_params_t sw_params = {0}; + unsigned int rrate; + unsigned int buffer_time; + + assert(pcm); + assert(rate >= 5000 && rate <= 786000); + 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 = {0}; + snd_pcm_sw_params_t sw_params = {0}; + unsigned int rrate; + unsigned int xbuffer_time, buffer_time[2]; + unsigned int period_time[2]; + snd_pcm_t *pcms[2]; + + assert(playback_pcm); + assert(capture_pcm); + assert(rate >= 5000 && rate <= 768000); + 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..f08208f --- /dev/null +++ b/src/pcm/pcm_softvol.c @@ -0,0 +1,1168 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bswap.h" +#include +#include "pcm_local.h" +#include "pcm_plugin.h" + +#include + +#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 +/* + * The gain algorithm as it stands supports gain factors up to 32767, which + * is a fraction more than 90 dB, so set 90 dB as the maximum possible gain. + */ +#define MAX_DB_UPPER_LIMIT 90 + +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 CONVERT_AREA_S24_LE() do { \ + unsigned int ch, fr; \ + int *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) \ + / sizeof(int); \ + dst_step = snd_pcm_channel_area_step(dst_area) \ + / sizeof(int); \ + 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 += dst_step; \ + dst += src_step; \ + } \ + } else { \ + while (fr--) { \ + tmp = *src << 8; \ + tmp = (signed int) tmp >> 8; \ + *dst = MULTI_DIV_24(tmp, vol_scale); \ + 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_LE: + /* 24bit samples */ + CONVERT_AREA_S24_LE(); + 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_LE: + /* 24bit samples */ + CONVERT_AREA_S24_LE(); + 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_S24_LE) | + (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_S24_LE && + slave->format != SND_PCM_FORMAT_S32_LE && + slave->format != SND_PCM_FORMAT_S32_BE) { + SNDERR("softvol supports only S16_LE, S16_BE, S24_LE, 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[SNDRV_CTL_TLVO_TYPE] = SND_CTL_TLVT_DB_SCALE; + tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(int); + tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] = (int)(svol->min_dB * 100); + tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] = + (int)((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_add_boolean_elem_set(svol->ctl, cinfo, 1, count); + else + err = snd_ctl_add_integer_elem_set(svol->ctl, cinfo, 1, 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 = {0}; + snd_ctl_elem_info_t cinfo = {0}; + int err; + unsigned int i; + + if (ctl_card < 0) { + 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_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) { + err = snd_ctl_elem_remove(svol->ctl, &cinfo.id); + if (err < 0) { + SNDERR("Control %s mismatch", tmp_name); + return err; + } + /* reset numid */ + snd_ctl_elem_info_set_id(&cinfo, ctl_id); + 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, + .query_chmaps = snd_pcm_generic_query_chmaps, + .get_chmap = snd_pcm_generic_get_chmap, + .set_chmap = snd_pcm_generic_set_chmap, +}; + +/** + * \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_S24_LE && + 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->tstamp_type = slave->tstamp_type; + 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 = {0}; + 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 { + 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_S24_LE && + sformat != SND_PCM_FORMAT_S32_LE && + sformat != SND_PCM_FORMAT_S32_BE) { + SNDERR("only S16_LE, S16_BE, S24_LE, 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; + err = snd_pcm_parse_control_id(control, &ctl_id, &card, + &cchannels, NULL); + if (err < 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..c8596ed --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/plugin_ops.h b/src/pcm/plugin_ops.h new file mode 100644 index 0000000..6392073 --- /dev/null +++ b/src/pcm/plugin_ops.h @@ -0,0 +1,742 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef SX_INLINES +#define SX_INLINES +static inline uint32_t sx20(uint32_t x) +{ + if(x&0x00080000) + return x|0xFFF00000; + return x&0x000FFFFF; +} +static inline uint32_t sx24(uint32_t x) +{ + if(x&0x00800000) + return x|0xFF000000; + return x&0x00FFFFFF; +} +static inline uint32_t sx24s(uint32_t x) +{ + if(x&0x00008000) + return x|0x000000FF; + return x&0xFFFFFF00; +} +#endif + +#define as_u8(ptr) (*(uint8_t*)(ptr)) +#define as_u16(ptr) (*(uint16_t*)(ptr)) +#define as_u32(ptr) (*(uint32_t*)(ptr)) +#define as_u64(ptr) (*(uint64_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 uint8_t*)(ptr)) +#define as_u16c(ptr) (*(const uint16_t*)(ptr)) +#define as_u32c(ptr) (*(const uint32_t*)(ptr)) +#define as_u64c(ptr) (*(const uint64_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) (*(uint8_t*)(ptr) | (uint32_t)*((uint8_t*)(ptr) + 1) << 8 | (uint32_t)*((uint8_t*)(ptr) + 2) << 16) +#define _get_triple_be(ptr) ((uint32_t)*(uint8_t*)(ptr) << 16 | (uint32_t)*((uint8_t*)(ptr) + 1) << 8 | *((uint8_t*)(ptr) + 2)) +#define _put_triple_le(ptr,val) do { \ + uint8_t *_tmp = (uint8_t *)(ptr); \ + uint32_t _val = (val); \ + _tmp[0] = _val; \ + _tmp[1] = _val >> 8; \ + _tmp[2] = _val >> 16; \ +} while(0) +#define _put_triple_be(ptr,val) do { \ + uint8_t *_tmp = (uint8_t *)(ptr); \ + uint32_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 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) = (uint16_t)as_u8c(src) << 8; goto CONV_END; +conv_xxx1_xx01: as_u16(dst) = (uint16_t)as_u8c(src); goto CONV_END; +conv_xxx1_x100: as_u32(dst) = sx24((uint32_t)as_u8c(src) << 16); goto CONV_END; +conv_xxx1_001x: as_u32(dst) = sx24s((uint32_t)as_u8c(src) << 8); goto CONV_END; +conv_xxx1_1000: as_u32(dst) = (uint32_t)as_u8c(src) << 24; goto CONV_END; +conv_xxx1_0001: as_u32(dst) = (uint32_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) = (uint16_t)(as_u8c(src) ^ 0x80) << 8; goto CONV_END; +conv_xxx1_xx09: as_u16(dst) = (uint16_t)(as_u8c(src) ^ 0x80); goto CONV_END; +conv_xxx1_x900: as_u32(dst) = sx24((uint32_t)(as_u8c(src) ^ 0x80) << 16); goto CONV_END; +conv_xxx1_009x: as_u32(dst) = sx24s((uint32_t)(as_u8c(src) ^ 0x80) << 8); goto CONV_END; +conv_xxx1_9000: as_u32(dst) = (uint32_t)(as_u8c(src) ^ 0x80) << 24; goto CONV_END; +conv_xxx1_0009: as_u32(dst) = (uint32_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((uint32_t)as_u16c(src) << 8); goto CONV_END; +conv_xx12_021x: as_u32(dst) = sx24s((uint32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +conv_xx12_1200: as_u32(dst) = (uint32_t)as_u16c(src) << 16; goto CONV_END; +conv_xx12_0021: as_u32(dst) = (uint32_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((uint32_t)(as_u16c(src) ^ 0x8000) << 8); goto CONV_END; +conv_xx12_029x: as_u32(dst) = sx24s((uint32_t)(bswap_16(as_u16c(src)) ^ 0x80) << 8); goto CONV_END; +conv_xx12_9200: as_u32(dst) = (uint32_t)(as_u16c(src) ^ 0x8000) << 16; goto CONV_END; +conv_xx12_0029: as_u32(dst) = (uint32_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((uint32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +conv_xx12_012x: as_u32(dst) = sx24s((uint32_t)as_u16c(src) << 8); goto CONV_END; +conv_xx12_2100: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src)) << 16; goto CONV_END; +conv_xx12_0012: as_u32(dst) = (uint32_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((uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +conv_xx12_01Ax: as_u32(dst) = sx24s((uint32_t)(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +conv_xx12_A100: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto CONV_END; +conv_xx12_001A: as_u32(dst) = (uint32_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[5 * 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 */ + /* 4 byte formats */ + &&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 */ + &&get16_0123_12_20, /* 20h -> 16h */ + &&get16_0123_92_20, /* 20h ^> 16h */ + &&get16_1230_32_20, /* 20s -> 16h */ + &&get16_1230_B2_20, /* 20s ^> 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 = (uint16_t)as_u8c(src) << 8; goto GET16_END; +get16_1_90: sample = (uint16_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_0123_12_20: sample = as_u32c(src) >> 4; goto GET16_END; +get16_0123_92_20: sample = (as_u32c(src) >> 4) ^ 0x8000; goto GET16_END; +get16_1230_32_20: sample = bswap_32(as_u32c(src)) >> 4; goto GET16_END; +get16_1230_B2_20: sample = (bswap_32(as_u32c(src)) >> 4) ^ 0x8000; 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[5 * 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 */ + /* 4 byte formats */ + &&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 */ + &&put16_12_0120_20, /* 16h -> 20h */ + &&put16_12_0920_20, /* 16h ^> 20h */ + &&put16_12_0210_20, /* 16h -> 20s */ + &&put16_12_0290_20, /* 16h ^> 20s */ + /* 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((uint32_t)sample << 8); goto PUT16_END; +put16_12_0920: as_u32(dst) = sx24((uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_0210: as_u32(dst) = sx24s((uint32_t)bswap_16(sample) << 8); goto PUT16_END; +put16_12_0290: as_u32(dst) = sx24s((uint32_t)(bswap_16(sample) ^ 0x80) << 8); goto PUT16_END; +put16_12_1200: as_u32(dst) = (uint32_t)sample << 16; goto PUT16_END; +put16_12_9200: as_u32(dst) = (uint32_t)(sample ^ 0x8000) << 16; goto PUT16_END; +put16_12_0021: as_u32(dst) = (uint32_t)bswap_16(sample); goto PUT16_END; +put16_12_0029: as_u32(dst) = (uint32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; +put16_12_0120_20: as_u32(dst) = sx20((uint32_t)sample << 4); goto PUT16_END; +put16_12_0920_20: as_u32(dst) = sx20((uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_0210_20: as_u32(dst) = bswap_32(sx20((uint32_t)sample << 4)); goto PUT16_END; +put16_12_0290_20: as_u32(dst) = bswap_32(sx20((uint32_t)(sample ^ 0x8000) << 4)); goto PUT16_END; +put16_12_120: _put_triple(dst, (uint32_t)sample << 8); goto PUT16_END; +put16_12_920: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_021: _put_triple_s(dst, (uint32_t)sample << 8); goto PUT16_END; +put16_12_029: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +put16_12_120_20: _put_triple(dst, (uint32_t)sample << 4); goto PUT16_END; +put16_12_920_20: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_021_20: _put_triple_s(dst, (uint32_t)sample << 4); goto PUT16_END; +put16_12_029_20: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +put16_12_120_18: _put_triple(dst, (uint32_t)sample << 2); goto PUT16_END; +put16_12_920_18: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 2); goto PUT16_END; +put16_12_021_18: _put_triple_s(dst, (uint32_t)sample << 2); goto PUT16_END; +put16_12_029_18: _put_triple_s(dst, (uint32_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[5 * 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 */ + /* 4 byte formats */ + &&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 */ + &&get32_0123_1230_20, /* 20h -> 32h */ + &&get32_0123_9230_20, /* 20h ^> 32h */ + &&get32_1230_3210_20, /* 20s -> 32h */ + &&get32_1230_B210_20, /* 20s ^> 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 = (uint32_t)as_u8c(src) << 24; goto GET32_END; +get32_1_9000: sample = (uint32_t)(as_u8c(src) ^ 0x80) << 24; goto GET32_END; +get32_12_1200: sample = (uint32_t)as_u16c(src) << 16; goto GET32_END; +get32_12_9200: sample = (uint32_t)(as_u16c(src) ^ 0x8000) << 16; goto GET32_END; +get32_12_2100: sample = (uint32_t)bswap_16(as_u16c(src)) << 16; goto GET32_END; +get32_12_A100: sample = (uint32_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_0123_1230_20: sample = as_u32c(src) << 12; goto GET32_END; +get32_0123_9230_20: sample = (as_u32c(src) << 12) ^ 0x80000000; goto GET32_END; +get32_1230_3210_20: sample = bswap_32(as_u32c(src)) << 12; goto GET32_END; +get32_1230_B210_20: sample = (bswap_32(as_u32c(src)) << 12) ^ 0x80000000; 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[5 * 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 */ + /* 4 byte formats */ + &&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 */ + &&put32_1234_0123_20, /* 32h -> 20h */ + &&put32_1234_0923_20, /* 32h ^> 20h */ + &&put32_1234_3210_20, /* 32h -> 20s */ + &&put32_1234_3290_20, /* 32h ^> 20s */ + /* 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 -> 20h */ + &&put32_1234_923_20, /* 32h ^> 20h */ + &&put32_1234_321_20, /* 32h -> 20s */ + &&put32_1234_329_20, /* 32h ^> 20s */ + &&put32_1234_123_18, /* 32h -> 18h */ + &&put32_1234_923_18, /* 32h ^> 18h */ + &&put32_1234_321_18, /* 32h -> 18s */ + &&put32_1234_329_18, /* 32h ^> 18s */ +}; +#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_0123_20: as_u32(dst) = sx20(sample >> 12); goto PUT32_END; +put32_1234_0923_20: as_u32(dst) = sx20((sample ^ 0x80000000) >> 12); goto PUT32_END; +put32_1234_3210_20: as_u32(dst) = bswap_32(sx20(sample >> 12)); goto PUT32_END; +put32_1234_3290_20: as_u32(dst) = bswap_32(sx20((sample ^ 0x80000000) >> 12)); 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 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 + +#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..c2bbbd4 --- /dev/null +++ b/src/pcm/scopes/Makefile.in @@ -0,0 +1,671 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +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 \ + $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/level.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(scope_level_la_SOURCES) +DIST_SOURCES = $(scope_level_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @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 " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ + 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)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +scope-level.la: $(scope_level_la_OBJECTS) $(scope_level_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/level.Plo + -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 -f ./$(DEPDIR)/level.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + cscopelist-am ctags ctags-am 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 tags-am uninstall \ + uninstall-am uninstall-pkglibLTLIBRARIES + +.PRECIOUS: Makefile + + +# 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..ca7c0f6 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..41858a1 --- /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 + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/rawmidi/Makefile.in b/src/rawmidi/Makefile.in new file mode 100644 index 0000000..7fc7568 --- /dev/null +++ b/src/rawmidi/Makefile.in @@ -0,0 +1,618 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/rawmidi.Plo \ + ./$(DEPDIR)/rawmidi_hw.Plo ./$(DEPDIR)/rawmidi_symbols.Plo \ + ./$(DEPDIR)/rawmidi_virt.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(librawmidi_la_SOURCES) +DIST_SOURCES = $(am__librawmidi_la_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +librawmidi.la: $(librawmidi_la_OBJECTS) $(librawmidi_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi_symbols.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi_virt.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/rawmidi.Plo + -rm -f ./$(DEPDIR)/rawmidi_hw.Plo + -rm -f ./$(DEPDIR)/rawmidi_symbols.Plo + -rm -f ./$(DEPDIR)/rawmidi_virt.Plo + -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 -f ./$(DEPDIR)/rawmidi.Plo + -rm -f ./$(DEPDIR)/rawmidi_hw.Plo + -rm -f ./$(DEPDIR)/rawmidi_symbols.Plo + -rm -f ./$(DEPDIR)/rawmidi_virt.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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..1b5f852 --- /dev/null +++ b/src/rawmidi/rawmidi.c @@ -0,0 +1,991 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 writing 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 + 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); + 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_rawmidi_%s_open", str); + } +#ifndef PIC + snd_rawmidi_open_symbols(); +#endif + open_func = snd_dlobj_cache_get2(lib, open_name, + SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION), 1); + if (!open_func) { + err = -ENXIO; + goto _err; + } + if (type_conf) + snd_config_delete(type_conf); + err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode); + if (err < 0) + goto _err; + if (inputp) { + (*inputp)->open_func = open_func; + snd_rawmidi_params_default(*inputp, ¶ms); + err = snd_rawmidi_params(*inputp, ¶ms); + assert(err >= 0); + } + if (outputp) { + (*outputp)->open_func = open_func; + snd_rawmidi_params_default(*outputp, ¶ms); + err = snd_rawmidi_params(*outputp, ¶ms); + assert(err >= 0); + } + return 0; + + _err: + if (open_func) + snd_dlobj_cache_put(open_func); + if (type_conf) + snd_config_delete(type_conf); + return err; +} + +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) +{ + snd_config_t *top; + int err; + + assert((inputp || outputp) && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode); + snd_config_unref(top); + return err; +} + +/** + * \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->open_func) + snd_dlobj_cache_put(rawmidi->open_func); + 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); +} diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c new file mode 100644 index 0000000..eaa8a76 --- /dev/null +++ b/src/rawmidi/rawmidi_hw.c @@ -0,0 +1,363 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 (!inputp && !outputp) + return -EINVAL; + + 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..721e1ec --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 *open_func; + 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); + +#define snd_rawmidi_conf_generic_id(id) _snd_conf_generic_id(id) diff --git a/src/rawmidi/rawmidi_symbols.c b/src/rawmidi/rawmidi_symbols.c new file mode 100644 index 0000000..83e36f8 --- /dev/null +++ b/src/rawmidi/rawmidi_symbols.c @@ -0,0 +1,40 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef PIC + +extern const char *_snd_module_rawmidi_hw; +#ifdef BUILD_SEQ +extern const char *_snd_module_rawmidi_virt; +#endif + +static const char **snd_rawmidi_open_objects[] = { + &_snd_module_rawmidi_hw, +#ifdef BUILD_SEQ + &_snd_module_rawmidi_virt +#endif +}; + +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..2c4c27f --- /dev/null +++ b/src/rawmidi/rawmidi_virt.c @@ -0,0 +1,471 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) { + memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size); + virt->in_buf_ofs += 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) { + 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..6cefe39 --- /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 + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/seq/Makefile.in b/src/seq/Makefile.in new file mode 100644 index 0000000..63b50dc --- /dev/null +++ b/src/seq/Makefile.in @@ -0,0 +1,628 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/seq.Plo ./$(DEPDIR)/seq_event.Plo \ + ./$(DEPDIR)/seq_hw.Plo ./$(DEPDIR)/seq_midi_event.Plo \ + ./$(DEPDIR)/seq_old.Plo ./$(DEPDIR)/seq_symbols.Plo \ + ./$(DEPDIR)/seqmid.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libseq_la_SOURCES) +DIST_SOURCES = $(am__libseq_la_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libseq.la: $(libseq_la_OBJECTS) $(libseq_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_event.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_midi_event.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_old.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_symbols.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seqmid.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/seq.Plo + -rm -f ./$(DEPDIR)/seq_event.Plo + -rm -f ./$(DEPDIR)/seq_hw.Plo + -rm -f ./$(DEPDIR)/seq_midi_event.Plo + -rm -f ./$(DEPDIR)/seq_old.Plo + -rm -f ./$(DEPDIR)/seq_symbols.Plo + -rm -f ./$(DEPDIR)/seqmid.Plo + -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 -f ./$(DEPDIR)/seq.Plo + -rm -f ./$(DEPDIR)/seq_event.Plo + -rm -f ./$(DEPDIR)/seq_hw.Plo + -rm -f ./$(DEPDIR)/seq_midi_event.Plo + -rm -f ./$(DEPDIR)/seq_old.Plo + -rm -f ./$(DEPDIR)/seq_symbols.Plo + -rm -f ./$(DEPDIR)/seqmid.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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..afc8842 --- /dev/null +++ b/src/seq/seq.c @@ -0,0 +1,4853 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, int queue) +{ + 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, queue, 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], errbuf[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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", lib, errbuf); + 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) +{ + snd_config_t *top; + int err; + + assert(seqp && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_seq_open_noupdate(seqp, top, name, streams, mode, 0); + snd_config_unref(top); + return err; +} + +/** + * \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 Get the sound card number. + * \param info client_info container + * \return card number or -1 if value is not available. + * + * Only available for #SND_SEQ_KERNEL_CLIENT clients. + * + * The card number can be used to query state about the hardware + * device providing this client, by concatenating "hw:CARD=" + * with the card number and using it as the name parameter + * to #snd_ctl_open(). + * + * \note + * The return value of -1 is returned for two different conditions: when the + * running kernel does not support this operation, and when the client + * does not have a hardware card attached. See + * #snd_seq_client_info_get_pid() for a way to determine if the + * currently running kernel has support for this operation. + * + * \sa snd_seq_client_info_get_pid(), + * snd_card_get_name(), + * snd_card_get_longname(), + * snd_ctl_open(), + * snd_ctl_card_info() + */ +int snd_seq_client_info_get_card(const snd_seq_client_info_t *info) +{ + assert(info); + return info->card; +} + +/** + * \brief Get the owning PID. + * \param info client_info container + * \return pid or -1 if value is not available. + * + * Only available for #SND_SEQ_USER_CLIENT clients. + * + * \note + * The functionality for getting a client's PID and getting a + * client's card was added to the kernel at the same time, so you can + * use this function to determine if the running kernel + * supports reporting these values. If your own client has a valid + * PID as reported by this function, then the running kernel supports + * both #snd_seq_client_info_get_card() and #snd_seq_client_info_get_pid(). + * + * \note + * Example code for determining kernel support: + * \code + * int is_get_card_or_pid_supported(snd_seq_t *seq) + * { + * snd_seq_client_info_t *my_client_info; + * snd_seq_client_info_alloca(&my_client_info); + * snd_seq_get_client_info(seq, my_client_info); + * return snd_seq_client_info_get_pid(my_client_info) != -1; + * } + * \endcode + * + * \sa snd_seq_client_info_get_card() + */ +int snd_seq_client_info_get_pid(const snd_seq_client_info_t *info) +{ + assert(info); + return info->pid; +} + +/** + * \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); + snd_strlcpy(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 (const snd_seq_addr_t *) &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 = *(const struct sndrv_seq_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); + snd_strlcpy(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 (const snd_seq_addr_t *)&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 (const snd_seq_addr_t *)&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 (const snd_seq_addr_t *)&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 (const snd_seq_addr_t *)&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 = *(const struct snd_seq_addr *)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); + snd_strlcpy(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) + snd_strlcpy(info.name, name, sizeof(info.name)); + 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); + snd_strlcpy(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 snd_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 snd_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 (const snd_seq_real_time_t *)&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 (const snd_seq_timestamp_t *)&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 (const snd_seq_addr_t *)&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 = *(const union sndrv_seq_timestamp *)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 = *(const struct sndrv_seq_addr *)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, (snd_seq_real_time_t *)&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, (snd_seq_real_time_t *)&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..e4b4d2a --- /dev/null +++ b/src/seq/seq_hw.c @@ -0,0 +1,565 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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, 2) + +typedef struct { + int fd; + int version; +} 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; + } + if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 2)) { + info->card = -1; + info->pid = -1; + } + 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; + } + if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 2)) { + info->card = -1; + info->pid = -1; + } + 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; + hw->version = ver; + 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 snd_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 (_snd_conf_generic_id(id)) + 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..f97a520 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 snd_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..5a12a18 --- /dev/null +++ b/src/seq/seq_midi_event.c @@ -0,0 +1,729 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "local.h" + +#ifndef DOC_HIDDEN + +/* midi status */ +struct snd_midi_event { + ssize_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 (qlen <= 0) + return 0; + 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..a024e67 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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..b0f23cb --- /dev/null +++ b/src/seq/seqmid.c @@ -0,0 +1,441 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 tokens 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. + * Actually \a arg need to be only a prefix of the wanted client. + * That is, if a client named "Foobar XXL Master 2012" with number 128 is available, + * then parsing "Foobar" will return the address 128:0 if no other client is + * an exact match. + */ +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; + client = -1; + cinfo.client = -1; + while (snd_seq_query_next_client(seq, &cinfo) >= 0) { + if (!strncmp(arg, cinfo.name, len)) { + if (strlen(cinfo.name) == (size_t)len) { + /* exact match */ + addr->client = cinfo.client; + return 0; + } + if (client < 0) + client = cinfo.client; + } + } + if (client >= 0) { + /* prefix match */ + addr->client = 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..18937d9 --- /dev/null +++ b/src/shmarea.c @@ -0,0 +1,115 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" + +/* These funcs are only used by pcm_mmap when sys/shm.h is available. */ +#ifdef HAVE_SYS_SHM_H + +#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); + } +} + +#endif diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..99da23e --- /dev/null +++ b/src/socket.c @@ -0,0 +1,109 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; +} +#endif diff --git a/src/timer/Makefile.am b/src/timer/Makefile.am new file mode 100644 index 0000000..7cfbe45 --- /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 + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/timer/Makefile.in b/src/timer/Makefile.in new file mode 100644 index 0000000..3daea02 --- /dev/null +++ b/src/timer/Makefile.in @@ -0,0 +1,617 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/timer.Plo ./$(DEPDIR)/timer_hw.Plo \ + ./$(DEPDIR)/timer_query.Plo ./$(DEPDIR)/timer_query_hw.Plo \ + ./$(DEPDIR)/timer_symbols.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libtimer_la_SOURCES) +DIST_SOURCES = $(libtimer_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +libtimer.la: $(libtimer_la_OBJECTS) $(libtimer_la_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_query.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_query_hw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer_symbols.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/timer.Plo + -rm -f ./$(DEPDIR)/timer_hw.Plo + -rm -f ./$(DEPDIR)/timer_query.Plo + -rm -f ./$(DEPDIR)/timer_query_hw.Plo + -rm -f ./$(DEPDIR)/timer_symbols.Plo + -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 -f ./$(DEPDIR)/timer.Plo + -rm -f ./$(DEPDIR)/timer_hw.Plo + -rm -f ./$(DEPDIR)/timer_query.Plo + -rm -f ./$(DEPDIR)/timer_query_hw.Plo + -rm -f ./$(DEPDIR)/timer_symbols.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +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..670becd --- /dev/null +++ b/src/timer/timer.c @@ -0,0 +1,958 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "timer_local.h" + +#include + +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], errbuf[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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", lib, errbuf); + 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) +{ + snd_config_t *top; + int err; + + assert(timer && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_timer_open_noupdate(timer, top, name, mode); + snd_config_unref(top); + return err; +} + +/** + * \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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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..f08c0ac --- /dev/null +++ b/src/timer/timer_hw.c @@ -0,0 +1,343 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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 snd_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; +#ifdef F_SETSIG + if (fcntl(fd, F_SETSIG, (long)sig) < 0) { + SYSERR("F_SETSIG failed"); + return -errno; + } +#endif + 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 snd_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 (_snd_conf_generic_id(id)) + 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..ac28954 --- /dev/null +++ b/src/timer/timer_local.h @@ -0,0 +1,85 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "local.h" +#include +#include + +#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); + +#ifdef INTERNAL +int INTERNAL(snd_timer_params_set_exclusive)(snd_timer_params_t * params, int exclusive); +int INTERNAL(snd_timer_params_get_exclusive)(snd_timer_params_t * params); +void INTERNAL(snd_timer_params_set_filter)(snd_timer_params_t * params, unsigned int filter); +unsigned int INTERNAL(snd_timer_params_get_filter)(snd_timer_params_t * params); +int INTERNAL(snd_timer_query_info)(snd_timer_query_t *timer, snd_timer_ginfo_t *info); +int INTERNAL(snd_timer_query_params)(snd_timer_query_t *timer, snd_timer_gparams_t *params); +int INTERNAL(snd_timer_query_status)(snd_timer_query_t *timer, snd_timer_gstatus_t *status); +#endif /* INTERNAL */ diff --git a/src/timer/timer_query.c b/src/timer/timer_query.c new file mode 100644 index 0000000..084ff61 --- /dev/null +++ b/src/timer/timer_query.c @@ -0,0 +1,592 @@ +/** + * \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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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], errbuf[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 = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); + 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 (%s)", lib, errbuf); + 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) +{ + snd_config_t *top; + int err; + + assert(timer && name); + err = snd_config_update_ref(&top); + if (err < 0) + return err; + err = snd_timer_query_open_noupdate(timer, top, name, mode); + snd_config_unref(top); + return err; +} + +/** + * \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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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 +EXPORT_SYMBOL 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..dad228c --- /dev/null +++ b/src/timer/timer_query_hw.c @@ -0,0 +1,138 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#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 (_snd_conf_generic_id(id)) + 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..8393d12 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/topology/Makefile.am b/src/topology/Makefile.am new file mode 100644 index 0000000..9dc472d --- /dev/null +++ b/src/topology/Makefile.am @@ -0,0 +1,34 @@ +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 = libatopology.la + +libatopology_la_LIBADD = ../libasound.la +libatopology_la_LDFLAGS = -version-info $(COMPATNUM) $(VSYMS) $(SYMFUNCS) $(LDFLAGS_NOUNDEFINED) + +libatopology_la_SOURCES =\ + parser.c \ + builder.c \ + ctl.c \ + dapm.c \ + pcm.c \ + data.c \ + text.c \ + channel.c \ + ops.c \ + elem.c + +noinst_HEADERS = tplg_local.h + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/topology/Makefile.in b/src/topology/Makefile.in new file mode 100644 index 0000000..54c40a6 --- /dev/null +++ b/src/topology/Makefile.in @@ -0,0 +1,722 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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/topology +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libatopology_la_DEPENDENCIES = ../libasound.la +am_libatopology_la_OBJECTS = parser.lo builder.lo ctl.lo dapm.lo \ + pcm.lo data.lo text.lo channel.lo ops.lo elem.lo +libatopology_la_OBJECTS = $(am_libatopology_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libatopology_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libatopology_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/builder.Plo ./$(DEPDIR)/channel.Plo \ + ./$(DEPDIR)/ctl.Plo ./$(DEPDIR)/dapm.Plo ./$(DEPDIR)/data.Plo \ + ./$(DEPDIR)/elem.Plo ./$(DEPDIR)/ops.Plo \ + ./$(DEPDIR)/parser.Plo ./$(DEPDIR)/pcm.Plo \ + ./$(DEPDIR)/text.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libatopology_la_SOURCES) +DIST_SOURCES = $(libatopology_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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@ +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 = libatopology.la +libatopology_la_LIBADD = ../libasound.la +libatopology_la_LDFLAGS = -version-info $(COMPATNUM) $(VSYMS) $(SYMFUNCS) $(LDFLAGS_NOUNDEFINED) +libatopology_la_SOURCES = \ + parser.c \ + builder.c \ + ctl.c \ + dapm.c \ + pcm.c \ + data.c \ + text.c \ + channel.c \ + ops.c \ + elem.c + +noinst_HEADERS = tplg_local.h +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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/topology/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/topology/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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @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 " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + 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)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libatopology.la: $(libatopology_la_OBJECTS) $(libatopology_la_DEPENDENCIES) $(EXTRA_libatopology_la_DEPENDENCIES) + $(AM_V_CCLD)$(libatopology_la_LINK) -rpath $(libdir) $(libatopology_la_OBJECTS) $(libatopology_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builder.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dapm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elem.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ops.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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)$(libdir)"; 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: + 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-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/builder.Plo + -rm -f ./$(DEPDIR)/channel.Plo + -rm -f ./$(DEPDIR)/ctl.Plo + -rm -f ./$(DEPDIR)/dapm.Plo + -rm -f ./$(DEPDIR)/data.Plo + -rm -f ./$(DEPDIR)/elem.Plo + -rm -f ./$(DEPDIR)/ops.Plo + -rm -f ./$(DEPDIR)/parser.Plo + -rm -f ./$(DEPDIR)/pcm.Plo + -rm -f ./$(DEPDIR)/text.Plo + -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-libLTLIBRARIES + +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 ./$(DEPDIR)/builder.Plo + -rm -f ./$(DEPDIR)/channel.Plo + -rm -f ./$(DEPDIR)/ctl.Plo + -rm -f ./$(DEPDIR)/dapm.Plo + -rm -f ./$(DEPDIR)/data.Plo + -rm -f ./$(DEPDIR)/elem.Plo + -rm -f ./$(DEPDIR)/ops.Plo + -rm -f ./$(DEPDIR)/parser.Plo + -rm -f ./$(DEPDIR)/pcm.Plo + -rm -f ./$(DEPDIR)/text.Plo + -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-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ + ctags ctags-am 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 maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES + +.PRECIOUS: Makefile + + +# 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/topology/builder.c b/src/topology/builder.c new file mode 100644 index 0000000..5ae3ae8 --- /dev/null +++ b/src/topology/builder.c @@ -0,0 +1,356 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +/* verbose output detailing each object size and file position */ +static void verbose(snd_tplg_t *tplg, const char *fmt, ...) +{ + int offset; + va_list va; + + if (!tplg->verbose) + return; + + offset = lseek(tplg->out_fd, 0, SEEK_CUR); + + va_start(va, fmt); + fprintf(stdout, "0x%6.6x/%6.6d -", offset, offset); + vfprintf(stdout, fmt, va); + va_end(va); +} + +/* write out block header to output file */ +static int write_block_header(snd_tplg_t *tplg, unsigned int type, + unsigned int vendor_type, unsigned int version, unsigned int index, + size_t payload_size, int count) +{ + struct snd_soc_tplg_hdr hdr; + size_t bytes; + int offset = lseek(tplg->out_fd, 0, SEEK_CUR); + + memset(&hdr, 0, sizeof(hdr)); + hdr.magic = SND_SOC_TPLG_MAGIC; + hdr.abi = SND_SOC_TPLG_ABI_VERSION; + hdr.type = type; + hdr.vendor_type = vendor_type; + hdr.version = version; + hdr.payload_size = payload_size; + hdr.index = index; + hdr.size = sizeof(hdr); + hdr.count = count; + + /* make sure file offset is aligned with the calculated HDR offset */ + if ((unsigned int)offset != tplg->next_hdr_pos) { + SNDERR("error: New header is at offset 0x%x but file" + " offset 0x%x is %s by %d bytes\n", + tplg->next_hdr_pos, offset, + (unsigned int)offset > tplg->next_hdr_pos ? "ahead" : "behind", + abs(offset - tplg->next_hdr_pos)); + exit(-EINVAL); + } + + verbose(tplg, " header index %d type %d count %d size 0x%lx/%ld vendor %d " + "version %d\n", index, type, count, + (long unsigned int)payload_size, (long int)payload_size, + vendor_type, version); + + tplg->next_hdr_pos += hdr.payload_size + sizeof(hdr); + + bytes = write(tplg->out_fd, &hdr, sizeof(hdr)); + if (bytes != sizeof(hdr)) { + SNDERR("error: can't write section header %lu\n", + (long unsigned int)bytes); + return bytes; + } + + return bytes; +} + +static int write_elem_block(snd_tplg_t *tplg, + struct list_head *base, int size, int tplg_type, const char *obj_name) +{ + struct list_head *pos, *sub_pos, *sub_base; + struct tplg_elem *elem, *elem_next; + int ret, wsize = 0, total_size = 0, count = 0, block_size = 0; + + sub_base = base; + list_for_each(pos, base) { + /* find elems with the same index to make a block */ + elem = list_entry(pos, struct tplg_elem, list); + + if (elem->compound_elem) + continue; + + elem_next = list_entry(pos->next, struct tplg_elem, list); + block_size += elem->size; + count++; + + if ((pos->next == base) || (elem_next->index != elem->index)) { + /* write header for the block */ + ret = write_block_header(tplg, tplg_type, elem->vendor_type, + tplg->version, elem->index, block_size, count); + if (ret < 0) { + SNDERR("error: failed to write %s block %d\n", + obj_name, ret); + return ret; + } + + /* write elems for the block */ + list_for_each(sub_pos, sub_base) { + elem = list_entry(sub_pos, struct tplg_elem, list); + /* compound elems have already been copied to other elems */ + if (elem->compound_elem) + continue; + + if (elem->type != SND_TPLG_TYPE_DAPM_GRAPH) + verbose(tplg, " %s '%s': write %d bytes\n", + obj_name, elem->id, elem->size); + else + verbose(tplg, " %s '%s -> %s -> %s': write %d bytes\n", + obj_name, elem->route->source, + elem->route->control, + elem->route->sink, elem->size); + + wsize = write(tplg->out_fd, elem->obj, elem->size); + if (wsize < 0) { + SNDERR("error: failed to write %s %d\n", + obj_name, ret); + return ret; + } + + total_size += wsize; + /* get to the end of sub list */ + if (sub_pos == pos) + break; + } + /* the last elem of the current sub list as the head of + next sub list*/ + sub_base = pos; + count = 0; + block_size = 0; + } + } + + /* make sure we have written the correct size */ + if (total_size != size) { + SNDERR("error: size mismatch. Expected %d wrote %d\n", + size, total_size); + return -EIO; + } + + return 0; +} + +static int calc_block_size(struct list_head *base) +{ + struct list_head *pos; + struct tplg_elem *elem; + int size = 0; + + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + + /* compound elems have already been copied to other elems */ + if (elem->compound_elem) + continue; + + size += elem->size; + } + + return size; +} + +static int write_block(snd_tplg_t *tplg, struct list_head *base, + int type) +{ + int size; + + /* calculate the block size in bytes for all elems in this list */ + size = calc_block_size(base); + if (size <= 0) + return size; + + verbose(tplg, " block size for type %d is %d\n", type, size); + + /* write each elem for this block */ + switch (type) { + case SND_TPLG_TYPE_MIXER: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_MIXER, "mixer"); + case SND_TPLG_TYPE_BYTES: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_BYTES, "bytes"); + case SND_TPLG_TYPE_ENUM: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_ENUM, "enum"); + case SND_TPLG_TYPE_DAPM_GRAPH: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAPM_GRAPH, "route"); + case SND_TPLG_TYPE_DAPM_WIDGET: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAPM_WIDGET, "widget"); + case SND_TPLG_TYPE_PCM: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_PCM, "pcm"); + case SND_TPLG_TYPE_BE: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_BACKEND_LINK, "be"); + case SND_TPLG_TYPE_CC: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_CODEC_LINK, "cc"); + case SND_TPLG_TYPE_DATA: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_PDATA, "data"); + case SND_TPLG_TYPE_DAI: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAI, "dai"); + default: + return -EINVAL; + } + + return 0; +} + +/* write the manifest including its private data */ +static int write_manifest_data(snd_tplg_t *tplg) +{ + int ret; + + /* write the header for this block */ + ret = write_block_header(tplg, SND_SOC_TPLG_TYPE_MANIFEST, 0, + tplg->version, 0, + sizeof(tplg->manifest) + tplg->manifest.priv.size, 1); + if (ret < 0) { + SNDERR("error: failed to write manifest block %d\n", ret); + return ret; + } + + verbose(tplg, "manifest : write %d bytes\n", sizeof(tplg->manifest)); + ret = write(tplg->out_fd, &tplg->manifest, sizeof(tplg->manifest)); + if (ret < 0) { + SNDERR("error: failed to write manifest %d\n", ret); + return ret; + } + + verbose(tplg, "manifest : write %d priv bytes\n", tplg->manifest.priv.size); + ret = write(tplg->out_fd, tplg->manifest_pdata, tplg->manifest.priv.size); + if (ret < 0) { + SNDERR("error: failed to write manifest priv data %d\n", ret); + return ret; + } + + return 0; +} + +int tplg_write_data(snd_tplg_t *tplg) +{ + int ret; + + /* write manifest */ + ret = write_manifest_data(tplg); + if (ret < 0) { + SNDERR("failed to write manifest %d\n", ret); + return ret; + } + + /* write mixer elems. */ + ret = write_block(tplg, &tplg->mixer_list, + SND_TPLG_TYPE_MIXER); + if (ret < 0) { + SNDERR("failed to write control elems %d\n", ret); + return ret; + } + + /* write enum control elems. */ + ret = write_block(tplg, &tplg->enum_list, + SND_TPLG_TYPE_ENUM); + if (ret < 0) { + SNDERR("failed to write control elems %d\n", ret); + return ret; + } + + /* write bytes extended control elems. */ + ret = write_block(tplg, &tplg->bytes_ext_list, + SND_TPLG_TYPE_BYTES); + if (ret < 0) { + SNDERR("failed to write control elems %d\n", ret); + return ret; + } + + /* write widget elems */ + ret = write_block(tplg, &tplg->widget_list, + SND_TPLG_TYPE_DAPM_WIDGET); + if (ret < 0) { + SNDERR("failed to write widget elems %d\n", ret); + return ret; + } + + /* write pcm elems */ + ret = write_block(tplg, &tplg->pcm_list, + SND_TPLG_TYPE_PCM); + if (ret < 0) { + SNDERR("failed to write pcm elems %d\n", ret); + return ret; + } + + /* write physical dai elems */ + ret = write_block(tplg, &tplg->dai_list, + SND_TPLG_TYPE_DAI); + if (ret < 0) { + SNDERR("failed to write physical dai elems %d\n", ret); + return ret; + } + + /* write be elems */ + ret = write_block(tplg, &tplg->be_list, + SND_TPLG_TYPE_BE); + if (ret < 0) { + SNDERR("failed to write be elems %d\n", ret); + return ret; + } + + /* write cc elems */ + ret = write_block(tplg, &tplg->cc_list, + SND_TPLG_TYPE_CC); + if (ret < 0) { + SNDERR("failed to write cc elems %d\n", ret); + return ret; + } + + /* write route elems */ + ret = write_block(tplg, &tplg->route_list, + SND_TPLG_TYPE_DAPM_GRAPH); + if (ret < 0) { + SNDERR("failed to write graph elems %d\n", ret); + return ret; + } + + /* write private data */ + ret = write_block(tplg, &tplg->pdata_list, + SND_TPLG_TYPE_DATA); + if (ret < 0) { + SNDERR("failed to write private data %d\n", ret); + return ret; + } + + return 0; +} diff --git a/src/topology/channel.c b/src/topology/channel.c new file mode 100644 index 0000000..8516b23 --- /dev/null +++ b/src/topology/channel.c @@ -0,0 +1,125 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +/* mapping of channel text names to types */ +static const struct map_elem channel_map[] = { + {"mono", SNDRV_CHMAP_MONO}, /* mono stream */ + {"fl", SNDRV_CHMAP_FL}, /* front left */ + {"fr", SNDRV_CHMAP_FR}, /* front right */ + {"rl", SNDRV_CHMAP_RL}, /* rear left */ + {"rr", SNDRV_CHMAP_RR}, /* rear right */ + {"fc", SNDRV_CHMAP_FC}, /* front center */ + {"lfe", SNDRV_CHMAP_LFE}, /* LFE */ + {"sl", SNDRV_CHMAP_SL}, /* side left */ + {"sr", SNDRV_CHMAP_SR}, /* side right */ + {"rc", SNDRV_CHMAP_RC}, /* rear center */ + {"flc", SNDRV_CHMAP_FLC}, /* front left center */ + {"frc", SNDRV_CHMAP_FRC}, /* front right center */ + {"rlc", SNDRV_CHMAP_RLC}, /* rear left center */ + {"rrc", SNDRV_CHMAP_RRC}, /* rear right center */ + {"flw", SNDRV_CHMAP_FLW}, /* front left wide */ + {"frw", SNDRV_CHMAP_FRW}, /* front right wide */ + {"flh", SNDRV_CHMAP_FLH}, /* front left high */ + {"fch", SNDRV_CHMAP_FCH}, /* front center high */ + {"frh", SNDRV_CHMAP_FRH}, /* front right high */ + {"tc", SNDRV_CHMAP_TC}, /* top center */ + {"tfl", SNDRV_CHMAP_TFL}, /* top front left */ + {"tfr", SNDRV_CHMAP_TFR}, /* top front right */ + {"tfc", SNDRV_CHMAP_TFC}, /* top front center */ + {"trl", SNDRV_CHMAP_TRL}, /* top rear left */ + {"trr", SNDRV_CHMAP_TRR}, /* top rear right */ + {"trc", SNDRV_CHMAP_TRC}, /* top rear center */ + {"tflc", SNDRV_CHMAP_TFLC}, /* top front left center */ + {"tfrc", SNDRV_CHMAP_TFRC}, /* top front right center */ + {"tsl", SNDRV_CHMAP_TSL}, /* top side left */ + {"tsr", SNDRV_CHMAP_TSR}, /* top side right */ + {"llfe", SNDRV_CHMAP_LLFE}, /* left LFE */ + {"rlfe", SNDRV_CHMAP_RLFE}, /* right LFE */ + {"bc", SNDRV_CHMAP_BC}, /* bottom center */ + {"blc", SNDRV_CHMAP_BLC}, /* bottom left center */ + {"brc", SNDRV_CHMAP_BRC}, /* bottom right center */ +}; + + +static int lookup_channel(const char *c) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(channel_map); i++) { + if (strcasecmp(channel_map[i].name, c) == 0) { + return channel_map[i].id; + } + } + + return -EINVAL; +} + +/* Parse a channel mapping. */ +int tplg_parse_channel(snd_tplg_t *tplg, + snd_config_t *cfg, void *private) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct snd_soc_tplg_channel *channel = private; + const char *id, *value; + int channel_id; + + if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + channel += tplg->channel_idx; + snd_config_get_id(cfg, &id); + tplg_dbg("\tChannel %s at index %d\n", id, tplg->channel_idx); + + channel_id = lookup_channel(id); + if (channel_id < 0) { + SNDERR("error: invalid channel %s\n", id); + return -EINVAL; + } + + channel->id = channel_id; + channel->size = sizeof(*channel); + tplg_dbg("\tChan %s = %d\n", id, channel->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get id */ + if (snd_config_get_id(n, &id) < 0) + continue; + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + if (strcmp(id, "reg") == 0) + channel->reg = atoi(value); + else if (strcmp(id, "shift") == 0) + channel->shift = atoi(value); + + tplg_dbg("\t\t%s = %s\n", id, value); + } + + tplg->channel_idx++; + return 0; +} diff --git a/src/topology/ctl.c b/src/topology/ctl.c new file mode 100644 index 0000000..a096252 --- /dev/null +++ b/src/topology/ctl.c @@ -0,0 +1,1005 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +#define ENUM_VAL_SIZE (SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2) + +struct ctl_access_elem { + const char *name; + unsigned int value; +}; + +/* CTL access strings and codes */ +static const struct ctl_access_elem ctl_access[] = { + {"read", SNDRV_CTL_ELEM_ACCESS_READ}, + {"write", SNDRV_CTL_ELEM_ACCESS_WRITE}, + {"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE}, + {"volatile", SNDRV_CTL_ELEM_ACCESS_VOLATILE}, + {"timestamp", SNDRV_CTL_ELEM_ACCESS_TIMESTAMP}, + {"tlv_read", SNDRV_CTL_ELEM_ACCESS_TLV_READ}, + {"tlv_write", SNDRV_CTL_ELEM_ACCESS_TLV_WRITE}, + {"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE}, + {"tlv_command", SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, + {"inactive", SNDRV_CTL_ELEM_ACCESS_INACTIVE}, + {"lock", SNDRV_CTL_ELEM_ACCESS_LOCK}, + {"owner", SNDRV_CTL_ELEM_ACCESS_OWNER}, + {"tlv_callback", SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK}, +}; + +/* find CTL access strings and conver to values */ +static int parse_access_values(snd_config_t *cfg, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *value = NULL; + unsigned int j; + + tplg_dbg(" Access:\n"); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + /* match access value and set flags */ + for (j = 0; j < ARRAY_SIZE(ctl_access); j++) { + if (strcmp(value, ctl_access[j].name) == 0) { + hdr->access |= ctl_access[j].value; + tplg_dbg("\t%s\n", value); + break; + } + } + } + + return 0; +} + +/* Parse Access */ +int parse_access(snd_config_t *cfg, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + int err = 0; + + 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, "access") == 0) { + err = parse_access_values(n, hdr); + if (err < 0) { + SNDERR("error: failed to parse access"); + return err; + } + continue; + } + } + + return err; +} + +/* copy referenced TLV to the mixer control */ +static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref) +{ + struct snd_soc_tplg_mixer_control *mixer_ctrl = elem->mixer_ctrl; + struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv; + + tplg_dbg("TLV '%s' used by '%s\n", ref->id, elem->id); + + /* TLV has a fixed size */ + mixer_ctrl->hdr.tlv = *tlv; + return 0; +} + +/* check referenced TLV for a mixer control */ +static int tplg_build_mixer_control(snd_tplg_t *tplg, + struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err = 0; + + base = &elem->ref_list; + + /* for each ref in this control elem */ + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_TLV) { + ref->elem = tplg_elem_lookup(&tplg->tlv_list, + ref->id, SND_TPLG_TYPE_TLV, elem->index); + if (ref->elem) + err = copy_tlv(elem, ref->elem); + + } else if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + + if (!ref->elem) { + SNDERR("error: cannot find '%s' referenced by" + " control '%s'\n", ref->id, elem->id); + return -EINVAL; + } else if (err < 0) + return err; + } + + return 0; +} + +static void copy_enum_texts(struct tplg_elem *enum_elem, + struct tplg_elem *ref_elem) +{ + struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl; + struct tplg_texts *texts = ref_elem->texts; + + memcpy(ec->texts, texts->items, + SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + ec->items += texts->num_items; +} + +/* check referenced text for a enum control */ +static int tplg_build_enum_control(snd_tplg_t *tplg, + struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err; + + base = &elem->ref_list; + + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_TEXT) { + ref->elem = tplg_elem_lookup(&tplg->text_list, + ref->id, SND_TPLG_TYPE_TEXT, elem->index); + if (ref->elem) + copy_enum_texts(elem, ref->elem); + + } else if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + if (!ref->elem) { + SNDERR("error: cannot find '%s' referenced by" + " control '%s'\n", ref->id, elem->id); + return -EINVAL; + } + } + + return 0; +} + +/* check referenced private data for a byte control */ +static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err; + + base = &elem->ref_list; + + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + } + + return 0; +} + +int tplg_build_controls(snd_tplg_t *tplg) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + int err = 0; + + base = &tplg->mixer_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + err = tplg_build_mixer_control(tplg, elem); + if (err < 0) + return err; + + /* add control to manifest */ + tplg->manifest.control_elems++; + } + + base = &tplg->enum_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + err = tplg_build_enum_control(tplg, elem); + if (err < 0) + return err; + + /* add control to manifest */ + tplg->manifest.control_elems++; + } + + base = &tplg->bytes_ext_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + err = tplg_build_bytes_control(tplg, elem); + if (err < 0) + return err; + + /* add control to manifest */ + tplg->manifest.control_elems++; + } + + return 0; +} + + +/* + * Parse TLV of DBScale type. + * + * Parse DBScale describing min, step, mute in DB. + */ +static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct snd_soc_tplg_ctl_tlv *tplg_tlv; + struct snd_soc_tplg_tlv_dbscale *scale; + const char *id = NULL, *value = NULL; + + tplg_dbg(" scale: %s\n", elem->id); + + tplg_tlv = calloc(1, sizeof(*tplg_tlv)); + if (!tplg_tlv) + return -ENOMEM; + + elem->tlv = tplg_tlv; + tplg_tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv); + tplg_tlv->type = SNDRV_CTL_TLVT_DB_SCALE; + scale = &tplg_tlv->scale; + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get ID */ + if (snd_config_get_id(n, &id) < 0) { + SNDERR("error: cant get ID\n"); + return -EINVAL; + } + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + tplg_dbg("\t%s = %s\n", id, value); + + /* get TLV data */ + if (strcmp(id, "min") == 0) + scale->min = atoi(value); + else if (strcmp(id, "step") == 0) + scale->step = atoi(value); + else if (strcmp(id, "mute") == 0) + scale->mute = atoi(value); + else + SNDERR("error: unknown key %s\n", id); + } + + return 0; +} + +/* Parse TLV */ +int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + int err = 0; + struct tplg_elem *elem; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV); + if (!elem) + return -ENOMEM; + + 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, "scale") == 0) { + err = tplg_parse_tlv_dbscale(n, elem); + if (err < 0) { + SNDERR("error: failed to DBScale"); + return err; + } + continue; + } + } + + return err; +} + +/* Parse Control Bytes */ +int tplg_parse_control_bytes(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_bytes_control *be; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err; + bool access_set = false, tlv_set = false; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES); + if (!elem) + return -ENOMEM; + + be = elem->bytes_ext; + be->size = elem->size; + snd_strlcpy(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + be->hdr.type = SND_SOC_TPLG_TYPE_BYTES; + + tplg_dbg(" Control Bytes: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "base") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + be->base = atoi(val); + tplg_dbg("\t%s: %d\n", id, be->base); + continue; + } + + if (strcmp(id, "num_regs") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + be->num_regs = atoi(val); + tplg_dbg("\t%s: %d\n", id, be->num_regs); + continue; + } + + if (strcmp(id, "max") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + be->max = atoi(val); + tplg_dbg("\t%s: %d\n", id, be->max); + continue; + } + + if (strcmp(id, "mask") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + be->mask = strtol(val, NULL, 16); + tplg_dbg("\t%s: %d\n", id, be->mask); + continue; + } + + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "tlv") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val); + if (err < 0) + return err; + + tlv_set = true; + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "ops") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_ops, + &be->hdr); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "extops") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_ext_ops, + be); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "access") == 0) { + err = parse_access(cfg, &be->hdr); + if (err < 0) + return err; + access_set = true; + continue; + } + } + + /* set CTL access to default values if none are provided */ + if (!access_set) { + + be->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (tlv_set) + be->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + } + + return 0; +} + +/* Parse Control Enums. */ +int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_enum_control *ec; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err, j; + bool access_set = false; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM); + if (!elem) + return -ENOMEM; + + ec = elem->enum_ctrl; + snd_strlcpy(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM; + ec->size = elem->size; + tplg->channel_idx = 0; + + /* set channel reg to default state */ + for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++) + ec->channel[j].reg = -1; + + tplg_dbg(" Control Enum: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "texts") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val); + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "channel") == 0) { + if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) { + SNDERR("error: too many channels %s\n", + elem->id); + return -EINVAL; + } + + err = tplg_parse_compound(tplg, n, tplg_parse_channel, + ec->channel); + if (err < 0) + return err; + + ec->num_channels = tplg->channel_idx; + continue; + } + + if (strcmp(id, "ops") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_ops, + &ec->hdr); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "access") == 0) { + err = parse_access(cfg, &ec->hdr); + if (err < 0) + return err; + access_set = true; + continue; + } + } + + /* set CTL access to default values if none are provided */ + if (!access_set) { + ec->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + } + + return 0; +} + +/* Parse Controls. + * + * Mixer control. Supports multiple channels. + */ +int tplg_parse_control_mixer(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_mixer_control *mc; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err, j; + bool access_set = false, tlv_set = false; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MIXER); + if (!elem) + return -ENOMEM; + + /* init new mixer */ + mc = elem->mixer_ctrl; + snd_strlcpy(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER; + mc->size = elem->size; + tplg->channel_idx = 0; + + /* set channel reg to default state */ + for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++) + mc->channel[j].reg = -1; + + tplg_dbg(" Control Mixer: %s\n", elem->id); + + /* giterate trough each mixer elment */ + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "channel") == 0) { + if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) { + SNDERR("error: too many channels %s\n", + elem->id); + return -EINVAL; + } + + err = tplg_parse_compound(tplg, n, tplg_parse_channel, + mc->channel); + if (err < 0) + return err; + + mc->num_channels = tplg->channel_idx; + continue; + } + + if (strcmp(id, "max") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + mc->max = atoi(val); + tplg_dbg("\t%s: %d\n", id, mc->max); + continue; + } + + if (strcmp(id, "invert") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (strcmp(val, "true") == 0) + mc->invert = 1; + else if (strcmp(val, "false") == 0) + mc->invert = 0; + + tplg_dbg("\t%s: %d\n", id, mc->invert); + continue; + } + + if (strcmp(id, "ops") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_ops, + &mc->hdr); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "tlv") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val); + if (err < 0) + return err; + + tlv_set = true; + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "access") == 0) { + err = parse_access(cfg, &mc->hdr); + if (err < 0) + return err; + access_set = true; + continue; + } + } + + /* set CTL access to default values if none are provided */ + if (!access_set) { + + mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (tlv_set) + mc->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + } + + return 0; +} + +static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr, + struct snd_tplg_ctl_template *t) +{ + hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr); + hdr->type = t->type; + + snd_strlcpy(hdr->name, t->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + /* clean up access flag */ + if (t->access == 0) + t->access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + t->access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); + + hdr->access = t->access; + hdr->ops.get = t->ops.get; + hdr->ops.put = t->ops.put; + hdr->ops.info = t->ops.info; + + /* TLV */ + if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE + && !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { + + struct snd_tplg_tlv_template *tlvt = t->tlv; + struct snd_soc_tplg_ctl_tlv *tlv = &hdr->tlv; + struct snd_tplg_tlv_dbscale_template *scalet; + struct snd_soc_tplg_tlv_dbscale *scale; + + if (!tlvt) { + SNDERR("error: missing TLV data\n"); + return -EINVAL; + } + + tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv); + tlv->type = tlvt->type; + + switch (tlvt->type) { + case SNDRV_CTL_TLVT_DB_SCALE: + scalet = container_of(tlvt, + struct snd_tplg_tlv_dbscale_template, hdr); + scale = &tlv->scale; + scale->min = scalet->min; + scale->step = scalet->step; + scale->mute = scalet->mute; + break; + + /* TODO: add support for other TLV types */ + default: + SNDERR("error: unsupported TLV type %d\n", tlv->type); + break; + } + } + + return 0; +} + +int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer, + struct tplg_elem **e) +{ + struct snd_soc_tplg_private *priv = mixer->priv; + struct snd_soc_tplg_mixer_control *mc; + struct tplg_elem *elem; + int ret, i, num_channels; + + tplg_dbg(" Control Mixer: %s\n", mixer->hdr.name); + + if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) { + SNDERR("error: invalid mixer type %d\n", mixer->hdr.type); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name, + SND_TPLG_TYPE_MIXER); + if (!elem) + return -ENOMEM; + + /* init new mixer */ + mc = elem->mixer_ctrl; + mc->size = elem->size; + ret = init_ctl_hdr(&mc->hdr, &mixer->hdr); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + mc->min = mixer->min; + mc->max = mixer->max; + mc->platform_max = mixer->platform_max; + mc->invert = mixer->invert; + + /* set channel reg to default state */ + for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) + mc->channel[i].reg = -1; + + num_channels = mixer->map ? mixer->map->num_channels : 0; + mc->num_channels = num_channels; + + for (i = 0; i < num_channels; i++) { + struct snd_tplg_channel_elem *channel = &mixer->map->channel[i]; + + mc->channel[i].size = channel->size; + mc->channel[i].reg = channel->reg; + mc->channel[i].shift = channel->shift; + mc->channel[i].id = channel->id; + } + + /* priv data */ + if (priv) { + mc = realloc(mc, elem->size + priv->size); + if (!mc) { + tplg_elem_free(elem); + return -ENOMEM; + } + + elem->mixer_ctrl = mc; + elem->size += priv->size; + mc->priv.size = priv->size; + memcpy(mc->priv.data, priv->data, priv->size); + } + + if (e) + *e = elem; + return 0; +} + +int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl, + struct tplg_elem **e) +{ + struct snd_soc_tplg_enum_control *ec; + struct tplg_elem *elem; + int ret, i, num_items; + + tplg_dbg(" Control Enum: %s\n", enum_ctl->hdr.name); + + if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) { + SNDERR("error: invalid enum type %d\n", enum_ctl->hdr.type); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name, + SND_TPLG_TYPE_ENUM); + if (!elem) + return -ENOMEM; + + ec = elem->enum_ctrl; + ec->size = elem->size; + ret = init_ctl_hdr(&ec->hdr, &enum_ctl->hdr); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + num_items = enum_ctl->items < SND_SOC_TPLG_NUM_TEXTS ? + enum_ctl->items : SND_SOC_TPLG_NUM_TEXTS; + ec->items = num_items; + ec->mask = enum_ctl->mask; + ec->count = enum_ctl->items; + + if (enum_ctl->texts != NULL) { + for (i = 0; i < num_items; i++) { + if (enum_ctl->texts[i] != NULL) + snd_strlcpy(ec->texts[i], enum_ctl->texts[i], + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + } + } + + if (enum_ctl->values != NULL) { + for (i = 0; i < num_items; i++) { + if (enum_ctl->values[i] == NULL) + continue; + + memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE], + enum_ctl->values[i], + sizeof(int) * ENUM_VAL_SIZE); + } + } + + if (enum_ctl->priv != NULL) { + ec = realloc(ec, + elem->size + enum_ctl->priv->size); + if (!ec) { + tplg_elem_free(elem); + return -ENOMEM; + } + + elem->enum_ctrl = ec; + elem->size += enum_ctl->priv->size; + + memcpy(ec->priv.data, enum_ctl->priv->data, + enum_ctl->priv->size); + + ec->priv.size = enum_ctl->priv->size; + } + + if (e) + *e = elem; + return 0; +} + +int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl, + struct tplg_elem **e) +{ + struct snd_soc_tplg_bytes_control *be; + struct tplg_elem *elem; + int ret; + + tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name); + + if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) { + SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name, + SND_TPLG_TYPE_BYTES); + if (!elem) + return -ENOMEM; + + be = elem->bytes_ext; + be->size = elem->size; + ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + be->max = bytes_ctl->max; + be->mask = bytes_ctl->mask; + be->base = bytes_ctl->base; + be->num_regs = bytes_ctl->num_regs; + be->ext_ops.put = bytes_ctl->ext_ops.put; + be->ext_ops.get = bytes_ctl->ext_ops.get; + + if (bytes_ctl->priv != NULL) { + be = realloc(be, + elem->size + bytes_ctl->priv->size); + if (!be) { + tplg_elem_free(elem); + return -ENOMEM; + } + elem->bytes_ext = be; + elem->size += bytes_ctl->priv->size; + + memcpy(be->priv.data, bytes_ctl->priv->data, + bytes_ctl->priv->size); + + be->priv.size = bytes_ctl->priv->size; + } + + /* check on TLV bytes control */ + if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + if ((be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) + != SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { + SNDERR("error: Invalid TLV bytes control access 0x%x\n", + be->hdr.access); + tplg_elem_free(elem); + return -EINVAL; + } + + if (!be->max) { + tplg_elem_free(elem); + return -EINVAL; + } + } + + if (e) + *e = elem; + return 0; +} + +int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + return tplg_add_mixer(tplg, t->mixer, NULL); +} + +int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + return tplg_add_enum(tplg, t->enum_ctl, NULL); +} + +int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + return tplg_add_bytes(tplg, t->bytes_ctl, NULL); +} diff --git a/src/topology/dapm.c b/src/topology/dapm.c new file mode 100644 index 0000000..97c9695 --- /dev/null +++ b/src/topology/dapm.c @@ -0,0 +1,764 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +/* mapping of widget text names to types */ +static const struct map_elem widget_map[] = { + {"input", SND_SOC_TPLG_DAPM_INPUT}, + {"output", SND_SOC_TPLG_DAPM_OUTPUT}, + {"mux", SND_SOC_TPLG_DAPM_MUX}, + {"mixer", SND_SOC_TPLG_DAPM_MIXER}, + {"pga", SND_SOC_TPLG_DAPM_PGA}, + {"out_drv", SND_SOC_TPLG_DAPM_OUT_DRV}, + {"adc", SND_SOC_TPLG_DAPM_ADC}, + {"dac", SND_SOC_TPLG_DAPM_DAC}, + {"switch", SND_SOC_TPLG_DAPM_SWITCH}, + {"pre", SND_SOC_TPLG_DAPM_PRE}, + {"post", SND_SOC_TPLG_DAPM_POST}, + {"aif_in", SND_SOC_TPLG_DAPM_AIF_IN}, + {"aif_out", SND_SOC_TPLG_DAPM_AIF_OUT}, + {"dai_in", SND_SOC_TPLG_DAPM_DAI_IN}, + {"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT}, + {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK}, + {"buffer", SND_SOC_TPLG_DAPM_BUFFER}, + {"scheduler", SND_SOC_TPLG_DAPM_SCHEDULER}, + {"effect", SND_SOC_TPLG_DAPM_EFFECT}, + {"siggen", SND_SOC_TPLG_DAPM_SIGGEN}, + {"src", SND_SOC_TPLG_DAPM_SRC}, + {"asrc", SND_SOC_TPLG_DAPM_ASRC}, + {"encoder", SND_SOC_TPLG_DAPM_ENCODER}, + {"decoder", SND_SOC_TPLG_DAPM_DECODER}, +}; + +static int lookup_widget(const char *w) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(widget_map); i++) { + if (strcmp(widget_map[i].name, w) == 0) + return widget_map[i].id; + } + + return -EINVAL; +} + +static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *value = NULL; + + tplg_dbg(" DAPM Mixer Controls: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + tplg_ref_add(elem, SND_TPLG_TYPE_MIXER, value); + tplg_dbg("\t\t %s\n", value); + } + + return 0; +} + +static int tplg_parse_dapm_enums(snd_config_t *cfg, struct tplg_elem *elem) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *value = NULL; + + tplg_dbg(" DAPM Enum Controls: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + tplg_ref_add(elem, SND_TPLG_TYPE_ENUM, value); + tplg_dbg("\t\t %s\n", value); + } + + return 0; +} + +static int tplg_parse_dapm_bytes(snd_config_t *cfg, struct tplg_elem *elem) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *value = NULL; + + tplg_dbg(" DAPM Bytes Controls: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + tplg_ref_add(elem, SND_TPLG_TYPE_BYTES, value); + tplg_dbg("\t\t %s\n", value); + } + + return 0; +} + +/* move referenced controls to the widget */ +static int copy_dapm_control(struct tplg_elem *elem, struct tplg_elem *ref) +{ + struct snd_soc_tplg_dapm_widget *widget = elem->widget; + + tplg_dbg("Control '%s' used by '%s'\n", ref->id, elem->id); + tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d\n", + elem->size, ref->size, elem->size + ref->size, + widget->priv.size); + + widget = realloc(widget, elem->size + ref->size); + if (!widget) + return -ENOMEM; + + elem->widget = widget; + + /* append the control to the end of the widget */ + memcpy((void*)widget + elem->size, ref->obj, ref->size); + elem->size += ref->size; + + widget->num_kcontrols++; + ref->compound_elem = 1; + return 0; +} + +/* check referenced controls for a widget */ +static int tplg_build_widget(snd_tplg_t *tplg, + struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err = 0; + + base = &elem->ref_list; + + /* A widget's private data sits before the embedded controls. + * So merge the private data blocks at first + */ + list_for_each(pos, base) { + ref = list_entry(pos, struct tplg_ref, list); + + if (ref->type != SND_TPLG_TYPE_DATA) + continue; + + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + + /* Merge the embedded controls */ + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + switch (ref->type) { + case SND_TPLG_TYPE_MIXER: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->mixer_list, + ref->id, SND_TPLG_TYPE_MIXER, elem->index); + if (ref->elem) + err = copy_dapm_control(elem, ref->elem); + break; + + case SND_TPLG_TYPE_ENUM: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->enum_list, + ref->id, SND_TPLG_TYPE_ENUM, elem->index); + if (ref->elem) + err = copy_dapm_control(elem, ref->elem); + break; + + case SND_TPLG_TYPE_BYTES: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->bytes_ext_list, + ref->id, SND_TPLG_TYPE_BYTES, elem->index); + if (ref->elem) + err = copy_dapm_control(elem, ref->elem); + break; + + default: + break; + } + + if (!ref->elem) { + SNDERR("error: cannot find '%s'" + " referenced by widget '%s'\n", + ref->id, elem->id); + return -EINVAL; + } + + if (err < 0) + return err; + } + + return 0; +} + +int tplg_build_widgets(snd_tplg_t *tplg) +{ + + struct list_head *base, *pos; + struct tplg_elem *elem; + int err; + + base = &tplg->widget_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + if (!elem->widget || elem->type != SND_TPLG_TYPE_DAPM_WIDGET) { + SNDERR("error: invalid widget '%s'\n", + elem->id); + return -EINVAL; + } + + err = tplg_build_widget(tplg, elem); + if (err < 0) + return err; + + /* add widget to manifest */ + tplg->manifest.widget_elems++; + } + + return 0; +} + +int tplg_build_routes(snd_tplg_t *tplg) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + struct snd_soc_tplg_dapm_graph_elem *route; + + base = &tplg->route_list; + + list_for_each(pos, base) { + elem = list_entry(pos, struct tplg_elem, list); + + if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH) { + SNDERR("error: invalid route '%s'\n", + elem->id); + return -EINVAL; + } + + route = elem->route; + tplg_dbg("\nCheck route: sink '%s', control '%s', source '%s'\n", + route->sink, route->control, route->source); + + /* validate sink */ + if (strlen(route->sink) <= 0) { + SNDERR("error: no sink\n"); + return -EINVAL; + + } + if (!tplg_elem_lookup(&tplg->widget_list, route->sink, + SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) { + SNDERR("warning: undefined sink widget/stream '%s'\n", + route->sink); + } + + /* validate control name */ + if (strlen(route->control)) { + if (!tplg_elem_lookup(&tplg->mixer_list, route->control, + SND_TPLG_TYPE_MIXER, elem->index) && + !tplg_elem_lookup(&tplg->enum_list, route->control, + SND_TPLG_TYPE_ENUM, elem->index)) { + SNDERR("warning: Undefined mixer/enum control '%s'\n", + route->control); + } + } + + /* validate source */ + if (strlen(route->source) <= 0) { + SNDERR("error: no source\n"); + return -EINVAL; + + } + if (!tplg_elem_lookup(&tplg->widget_list, route->source, + SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) { + SNDERR("warning: Undefined source widget/stream '%s'\n", + route->source); + } + + /* add graph to manifest */ + tplg->manifest.graph_elems++; + } + + return 0; +} + +struct tplg_elem* tplg_elem_new_route(snd_tplg_t *tplg) +{ + struct tplg_elem *elem; + struct snd_soc_tplg_dapm_graph_elem *line; + + elem = tplg_elem_new(); + if (!elem) + return NULL; + + list_add_tail(&elem->list, &tplg->route_list); + strcpy(elem->id, "line"); + elem->type = SND_TPLG_TYPE_DAPM_GRAPH; + elem->size = sizeof(*line); + + line = calloc(1, sizeof(*line)); + if (!line) { + tplg_elem_free(elem); + return NULL; + } + elem->route = line; + + return elem; +} + +#define LINE_SIZE 1024 + +/* line is defined as '"source, control, sink"' */ +static int tplg_parse_line(const char *text, + struct snd_soc_tplg_dapm_graph_elem *line) +{ + char buf[LINE_SIZE]; + unsigned int len, i; + const char *source = NULL, *sink = NULL, *control = NULL; + + snd_strlcpy(buf, text, LINE_SIZE); + + len = strlen(buf); + if (len <= 2) { + SNDERR("error: invalid route \"%s\"\n", buf); + return -EINVAL; + } + + /* find first , */ + for (i = 1; i < len; i++) { + if (buf[i] == ',') + goto second; + } + SNDERR("error: invalid route \"%s\"\n", buf); + return -EINVAL; + +second: + /* find second , */ + sink = buf; + control = &buf[i + 2]; + buf[i] = 0; + + for (; i < len; i++) { + if (buf[i] == ',') + goto done; + } + + SNDERR("error: invalid route \"%s\"\n", buf); + return -EINVAL; + +done: + buf[i] = 0; + source = &buf[i + 2]; + + strcpy(line->source, source); + strcpy(line->control, control); + strcpy(line->sink, sink); + return 0; +} + + +static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg, int index) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct tplg_elem *elem; + struct snd_soc_tplg_dapm_graph_elem *line; + int err; + + snd_config_for_each(i, next, cfg) { + const char *val; + + n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &val) < 0) + continue; + + elem = tplg_elem_new_route(tplg); + if (!elem) + return -ENOMEM; + elem->index = index; + line = elem->route; + + err = tplg_parse_line(val, line); + if (err < 0) + return err; + + tplg_dbg("route: sink '%s', control '%s', source '%s'\n", + line->sink, line->control, line->source); + } + + return 0; +} + +int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + const char *graph_id, *val = NULL; + int index = -1; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound is expected for dapm graph definition\n"); + return -EINVAL; + } + + snd_config_get_id(cfg, &graph_id); + + 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, "index") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + index = atoi(val); + } + + if (strcmp(id, "lines") == 0) { + if (index < 0) { + SNDERR("error: failed to parse dapm graph %s, missing index\n", + graph_id); + return -EINVAL; + } + err = tplg_parse_routes(tplg, n, index); + if (err < 0) { + SNDERR("error: failed to parse dapm graph %s\n", + graph_id); + return err; + } + continue; + } + } + + return 0; +} + +/* DAPM Widget */ +int tplg_parse_dapm_widget(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_dapm_widget *widget; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int widget_type, err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAPM_WIDGET); + if (!elem) + return -ENOMEM; + + tplg_dbg(" Widget: %s\n", elem->id); + + widget = elem->widget; + snd_strlcpy(widget->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + widget->size = elem->size; + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "type") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget_type = lookup_widget(val); + if (widget_type < 0){ + SNDERR("Widget '%s': Unsupported widget type %s\n", + elem->id, val); + return -EINVAL; + } + + widget->id = widget_type; + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "stream_name") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + snd_strlcpy(widget->sname, val, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "no_pm") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (strcmp(val, "true") == 0) + widget->reg = -1; + + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "shift") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget->shift = atoi(val); + tplg_dbg("\t%s: %d\n", id, widget->shift); + continue; + } + + if (strcmp(id, "reg") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget->reg = atoi(val); + tplg_dbg("\t%s: %d\n", id, widget->reg); + continue; + } + + if (strcmp(id, "invert") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget->invert = atoi(val); + tplg_dbg("\t%s: %d\n", id, widget->invert); + continue; + } + + if (strcmp(id, "subseq") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget->subseq= atoi(val); + tplg_dbg("\t%s: %d\n", id, widget->subseq); + continue; + } + + if (strcmp(id, "event_type") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget->event_type = atoi(val); + tplg_dbg("\t%s: %d\n", id, widget->event_type); + continue; + } + + if (strcmp(id, "event_flags") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + widget->event_flags = atoi(val); + tplg_dbg("\t%s: %d\n", id, widget->event_flags); + continue; + } + + if (strcmp(id, "enum") == 0) { + err = tplg_parse_dapm_enums(n, elem); + if (err < 0) + return err; + + continue; + } + + if (strcmp(id, "mixer") == 0) { + err = tplg_parse_dapm_mixers(n, elem); + if (err < 0) + return err; + + continue; + } + + if (strcmp(id, "bytes") == 0) { + err = tplg_parse_dapm_bytes(n, elem); + if (err < 0) + return err; + + continue; + } + + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + } + + return 0; +} + +int tplg_add_route(snd_tplg_t *tplg, struct snd_tplg_graph_elem *t) +{ + struct tplg_elem *elem; + struct snd_soc_tplg_dapm_graph_elem *line; + + if (!t->src || !t->sink) + return -EINVAL; + + elem = tplg_elem_new_route(tplg); + if (!elem) + return -ENOMEM; + + line = elem->route; + snd_strlcpy(line->source, t->src, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (t->ctl) + snd_strlcpy(line->control, t->ctl, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + snd_strlcpy(line->sink, t->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + return 0; +} + +int tplg_add_graph_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_graph_template *gt = t->graph; + int i, ret; + + for (i = 0; i < gt->count; i++) { + ret = tplg_add_route(tplg, gt->elem + i); + if (ret < 0) + return ret; + } + + return 0; +} + +int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_widget_template *wt = t->widget; + struct snd_soc_tplg_dapm_widget *w; + struct tplg_elem *elem; + int i, ret = 0; + + tplg_dbg("Widget: %s\n", wt->name); + + elem = tplg_elem_new_common(tplg, NULL, wt->name, + SND_TPLG_TYPE_DAPM_WIDGET); + if (!elem) + return -ENOMEM; + + /* init new widget */ + w = elem->widget; + w->size = elem->size; + + w->id = wt->id; + snd_strlcpy(w->name, wt->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (wt->sname) + snd_strlcpy(w->sname, wt->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + w->reg = wt->reg; + w->shift = wt->shift; + w->mask = wt->mask; + w->subseq = wt->subseq; + w->invert = wt->invert; + w->ignore_suspend = wt->ignore_suspend; + w->event_flags = wt->event_flags; + w->event_type = wt->event_type; + + if (wt->priv != NULL) { + w = realloc(w, + elem->size + wt->priv->size); + if (!w) { + tplg_elem_free(elem); + return -ENOMEM; + } + + elem->widget = w; + elem->size += wt->priv->size; + + memcpy(w->priv.data, wt->priv->data, + wt->priv->size); + w->priv.size = wt->priv->size; + } + + /* add controls to the widget's reference list */ + for (i = 0 ; i < wt->num_ctls; i++) { + struct snd_tplg_ctl_template *ct = wt->ctl[i]; + struct tplg_elem *elem_ctl; + struct snd_tplg_mixer_template *mt; + struct snd_tplg_bytes_template *bt; + struct snd_tplg_enum_template *et; + + if (!ct) { + tplg_elem_free(elem); + return -EINVAL; + } + + switch (ct->type) { + case SND_SOC_TPLG_TYPE_MIXER: + mt = container_of(ct, struct snd_tplg_mixer_template, hdr); + ret = tplg_add_mixer(tplg, mt, &elem_ctl); + break; + + case SND_SOC_TPLG_TYPE_BYTES: + bt = container_of(ct, struct snd_tplg_bytes_template, hdr); + ret = tplg_add_bytes(tplg, bt, &elem_ctl); + break; + + case SND_SOC_TPLG_TYPE_ENUM: + et = container_of(ct, struct snd_tplg_enum_template, hdr); + ret = tplg_add_enum(tplg, et, &elem_ctl); + break; + + default: + SNDERR("error: widget %s: invalid type %d for ctl %d\n", + wt->name, ct->type, i); + ret = -EINVAL; + break; + } + + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + ret = tplg_ref_add_elem(elem, elem_ctl); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + } + + return 0; +} diff --git a/src/topology/data.c b/src/topology/data.c new file mode 100644 index 0000000..729ce1f --- /dev/null +++ b/src/topology/data.c @@ -0,0 +1,1160 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" +#include + +/* Get private data buffer of an element */ +struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem) +{ + struct snd_soc_tplg_private *priv = NULL; + + switch (elem->type) { + case SND_TPLG_TYPE_MANIFEST: + priv = &elem->manifest->priv; + break; + + case SND_TPLG_TYPE_MIXER: + priv = &elem->mixer_ctrl->priv; + break; + + case SND_TPLG_TYPE_ENUM: + priv = &elem->enum_ctrl->priv; + break; + + case SND_TPLG_TYPE_BYTES: + priv = &elem->bytes_ext->priv; + break; + + case SND_TPLG_TYPE_DAPM_WIDGET: + priv = &elem->widget->priv; + break; + + case SND_TPLG_TYPE_DAI: + priv = &elem->dai->priv; + break; + case SND_TPLG_TYPE_BE: + priv = &elem->link->priv; + break; + case SND_TPLG_TYPE_PCM: + priv = &elem->pcm->priv; + break; + default: + SNDERR("error: '%s': no support for private data for type %d\n", + elem->id, elem->type); + } + + return priv; +} + +/* Get Private data from a file. */ +static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem) +{ + struct snd_soc_tplg_private *priv = NULL; + const char *value = NULL; + char filename[MAX_FILE]; + char *env = getenv(ALSA_CONFIG_TPLG_VAR); + FILE *fp; + size_t size, bytes_read; + int ret = 0; + + tplg_dbg("data DataFile: %s\n", elem->id); + + if (snd_config_get_string(cfg, &value) < 0) + return -EINVAL; + + /* prepend alsa config directory to path */ + if (env) + snprintf(filename, sizeof(filename), "%s/%s", env, value); + else + snprintf(filename, sizeof(filename), "%s/topology/%s", + snd_config_topdir(), value); + + fp = fopen(filename, "r"); + if (fp == NULL) { + SNDERR("error: invalid data file path '%s'\n", + filename); + return -errno; + } + + fseek(fp, 0L, SEEK_END); + size = ftell(fp); + fseek(fp, 0L, SEEK_SET); + if (size <= 0) { + SNDERR("error: invalid data file size %zu\n", size); + ret = -EINVAL; + goto err; + } + if (size > TPLG_MAX_PRIV_SIZE) { + SNDERR("error: data file too big %zu\n", size); + ret = -EINVAL; + goto err; + } + + priv = calloc(1, sizeof(*priv) + size); + if (!priv) { + ret = -ENOMEM; + goto err; + } + + bytes_read = fread(&priv->data, 1, size, fp); + if (bytes_read != size) { + ret = -errno; + goto err; + } + + elem->data = priv; + priv->size = size; + elem->size = sizeof(*priv) + size; + + if (fclose(fp) == EOF) { + SNDERR("Cannot close data file."); + return -errno; + } + return 0; + +err: + fclose(fp); + if (priv) + free(priv); + return ret; +} + +static void dump_priv_data(struct tplg_elem *elem) +{ + struct snd_soc_tplg_private *priv = elem->data; + unsigned int i, j = 0; + + tplg_dbg(" elem size = %d, priv data size = %d\n", + elem->size, priv->size); + + for (i = 0; i < priv->size; i++) { + if (j++ % 8 == 0) + tplg_dbg("\n"); + + tplg_dbg(" 0x%x", *p++); + } + + tplg_dbg("\n\n"); +} + +/* get number of hex value elements in CSV list */ +static int get_hex_num(const char *str) +{ + int commas = 0, values = 0, len = strlen(str); + const char *end = str + len; + + /* we expect "0x0, 0x0, 0x0" */ + while (str < end) { + + /* skip white space */ + if (isspace(*str)) { + str++; + continue; + } + + /* find delimeters */ + if (*str == ',') { + commas++; + str++; + continue; + } + + /* find 0x[0-9] values */ + if (*str == '0' && str + 2 <= end) { + if (str[1] == 'x' && str[2] >= '0' && str[2] <= 'f') { + values++; + str += 3; + } else { + str++; + } + } + + str++; + } + + /* there should always be one less comma than value */ + if (values -1 != commas) + return -EINVAL; + + return values; +} + +/* get uuid from a string made by 16 characters separated by commas */ +static int get_uuid(const char *str, unsigned char *uuid_le) +{ + unsigned long int val; + char *tmp, *s = NULL; + int values = 0, ret = 0; + + tmp = strdup(str); + if (tmp == NULL) + return -ENOMEM; + + s = strtok(tmp, ","); + + while (s != NULL) { + errno = 0; + val = strtoul(s, NULL, 0); + if ((errno == ERANGE && val == ULONG_MAX) + || (errno != 0 && val == 0) + || (val > UCHAR_MAX)) { + SNDERR("error: invalid value for uuid\n"); + ret = -EINVAL; + goto out; + } + + *(uuid_le + values) = (unsigned char)val; + + values++; + if (values >= 16) + break; + + s = strtok(NULL, ","); + } + + if (values < 16) { + SNDERR("error: less than 16 integers for uuid\n"); + ret = -EINVAL; + } + +out: + free(tmp); + return ret; +} + +static int write_hex(char *buf, char *str, int width) +{ + long val; + void *p = &val; + + errno = 0; + val = strtol(str, NULL, 16); + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) { + return -EINVAL; + } + + switch (width) { + case 1: + *(unsigned char *)buf = *(unsigned char *)p; + break; + case 2: + *(unsigned short *)buf = *(unsigned short *)p; + break; + case 4: + *(unsigned int *)buf = *(unsigned int *)p; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int copy_data_hex(char *data, int off, const char *str, int width) +{ + char *tmp, *s = NULL, *p = data; + int ret; + + tmp = strdup(str); + if (tmp == NULL) + return -ENOMEM; + + p += off; + s = strtok(tmp, ","); + + while (s != NULL) { + ret = write_hex(p, s, width); + if (ret < 0) { + free(tmp); + return ret; + } + + s = strtok(NULL, ","); + p += width; + } + + free(tmp); + return 0; +} + +static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem, + int width) +{ + struct snd_soc_tplg_private *priv; + const char *value = NULL; + int size, esize, off, num; + int ret; + + tplg_dbg(" data: %s\n", elem->id); + + if (snd_config_get_string(cfg, &value) < 0) + return -EINVAL; + + num = get_hex_num(value); + if (num <= 0) { + SNDERR("error: malformed hex variable list %s\n", value); + return -EINVAL; + } + + size = num * width; + priv = elem->data; + + if (size > TPLG_MAX_PRIV_SIZE) { + SNDERR("error: data too big %d\n", size); + return -EINVAL; + } + + if (priv != NULL) { + off = priv->size; + esize = elem->size + size; + priv = realloc(priv, esize); + } else { + off = 0; + esize = sizeof(*priv) + size; + priv = calloc(1, esize); + } + + if (!priv) + return -ENOMEM; + + elem->data = priv; + priv->size += size; + elem->size = esize; + + ret = copy_data_hex(priv->data, off, value, width); + + dump_priv_data(elem); + return ret; +} + +/* get the token integer value from its id */ +static int get_token_value(const char *token_id, + struct tplg_vendor_tokens *tokens) +{ + unsigned int i; + + for (i = 0; i < tokens->num_tokens; i++) { + if (strcmp(token_id, tokens->token[i].id) == 0) + return tokens->token[i].value; + } + + SNDERR("error: cannot find token id '%s'\n", token_id); + return -1; +} + +/* get the vendor tokens referred by the vendor tuples */ +static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + if (ref->type != SND_TPLG_TYPE_TOKEN) + continue; + + if (!ref->elem) { + ref->elem = tplg_elem_lookup(&tplg->token_list, + ref->id, SND_TPLG_TYPE_TOKEN, elem->index); + } + + return ref->elem; + } + + return NULL; +} + +/* check if a data element has tuples */ +static bool has_tuples(struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->type == SND_TPLG_TYPE_TUPLE) + return true; + } + + return false; +} + +/* get size of a tuple element from its type */ +static unsigned int get_tuple_size(int type) +{ + switch (type) { + + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + return sizeof(struct snd_soc_tplg_vendor_uuid_elem); + + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + return sizeof(struct snd_soc_tplg_vendor_string_elem); + + default: + return sizeof(struct snd_soc_tplg_vendor_value_elem); + } +} + +/* Add a tuples object to the private buffer of its parent data element */ +static int copy_tuples(struct tplg_elem *elem, + struct tplg_vendor_tuples *tuples, struct tplg_vendor_tokens *tokens) +{ + struct snd_soc_tplg_private *priv = elem->data, *priv2; + struct tplg_tuple_set *tuple_set; + struct tplg_tuple *tuple; + struct snd_soc_tplg_vendor_array *array; + struct snd_soc_tplg_vendor_uuid_elem *uuid; + struct snd_soc_tplg_vendor_string_elem *string; + struct snd_soc_tplg_vendor_value_elem *value; + int set_size, size, off; + unsigned int i, j; + int token_val; + + size = priv ? priv->size : 0; /* original private data size */ + + /* scan each tuples set (one set per type) */ + for (i = 0; i < tuples->num_sets ; i++) { + tuple_set = tuples->set[i]; + set_size = sizeof(struct snd_soc_tplg_vendor_array) + + get_tuple_size(tuple_set->type) + * tuple_set->num_tuples; + size += set_size; + if (size > TPLG_MAX_PRIV_SIZE) { + SNDERR("error: data too big %d\n", size); + return -EINVAL; + } + + if (priv != NULL) { + priv2 = realloc(priv, sizeof(*priv) + size); + if (priv2 == NULL) { + free(priv); + priv = NULL; + } else { + priv = priv2; + } + } else { + priv = calloc(1, sizeof(*priv) + size); + } + if (!priv) + return -ENOMEM; + + off = priv->size; + priv->size = size; /* update private data size */ + elem->data = priv; + + array = (struct snd_soc_tplg_vendor_array *)(priv->data + off); + array->size = set_size; + array->type = tuple_set->type; + array->num_elems = tuple_set->num_tuples; + + /* fill the private data buffer */ + for (j = 0; j < tuple_set->num_tuples; j++) { + tuple = &tuple_set->tuple[j]; + token_val = get_token_value(tuple->token, tokens); + if (token_val < 0) + return -EINVAL; + + switch (tuple_set->type) { + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + uuid = &array->uuid[j]; + uuid->token = token_val; + memcpy(uuid->uuid, tuple->uuid, 16); + break; + + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + string = &array->string[j]; + string->token = token_val; + snd_strlcpy(string->string, tuple->string, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + break; + + default: + value = &array->value[j]; + value->token = token_val; + value->value = tuple->value; + break; + } + } + } + + return 0; +} + +/* build a data element from its tuples */ +static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + struct tplg_elem *tuples, *tokens; + int err; + + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + if (ref->type != SND_TPLG_TYPE_TUPLE) + continue; + + tplg_dbg("tuples '%s' used by data '%s'\n", ref->id, elem->id); + + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->tuple_list, + ref->id, SND_TPLG_TYPE_TUPLE, elem->index); + tuples = ref->elem; + if (!tuples) { + SNDERR("error: cannot find tuples %s\n", ref->id); + return -EINVAL; + } + + tokens = get_tokens(tplg, tuples); + if (!tokens) { + SNDERR("error: cannot find token for %s\n", ref->id); + return -EINVAL; + } + + /* a data object can have multiple tuples objects */ + err = copy_tuples(elem, tuples->tuples, tokens->tokens); + if (err < 0) + return err; + } + + return 0; +} + +static int parse_tuple_set(snd_config_t *cfg, + struct tplg_tuple_set **s) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *value; + struct tplg_tuple_set *set; + unsigned int type, num_tuples = 0; + struct tplg_tuple *tuple; + unsigned long int tuple_val; + + snd_config_get_id(cfg, &id); + + if (strncmp(id, "uuid", 4) == 0) + type = SND_SOC_TPLG_TUPLE_TYPE_UUID; + else if (strncmp(id, "string", 5) == 0) + type = SND_SOC_TPLG_TUPLE_TYPE_STRING; + else if (strncmp(id, "bool", 4) == 0) + type = SND_SOC_TPLG_TUPLE_TYPE_BOOL; + else if (strncmp(id, "byte", 4) == 0) + type = SND_SOC_TPLG_TUPLE_TYPE_BYTE; + else if (strncmp(id, "short", 5) == 0) + type = SND_SOC_TPLG_TUPLE_TYPE_SHORT; + else if (strncmp(id, "word", 4) == 0) + type = SND_SOC_TPLG_TUPLE_TYPE_WORD; + else { + SNDERR("error: invalid tuple type '%s'\n", id); + return -EINVAL; + } + + snd_config_for_each(i, next, cfg) + num_tuples++; + if (!num_tuples) + return 0; + + tplg_dbg("\t %d %s tuples:\n", num_tuples, id); + set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple)); + if (!set) + return -ENOMEM; + + set->type = type; + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get id */ + if (snd_config_get_id(n, &id) < 0) + continue; + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + tuple = &set->tuple[set->num_tuples]; + snd_strlcpy(tuple->token, id, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + switch (type) { + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + if (get_uuid(value, tuple->uuid) < 0) + goto err; + break; + + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + snd_strlcpy(tuple->string, value, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + tplg_dbg("\t\t%s = %s\n", tuple->token, tuple->string); + break; + + case SND_SOC_TPLG_TUPLE_TYPE_BOOL: + if (strcmp(value, "true") == 0) + tuple->value = 1; + tplg_dbg("\t\t%s = %d\n", tuple->token, tuple->value); + break; + + case SND_SOC_TPLG_TUPLE_TYPE_BYTE: + case SND_SOC_TPLG_TUPLE_TYPE_SHORT: + case SND_SOC_TPLG_TUPLE_TYPE_WORD: + errno = 0; + /* no support for negative value */ + tuple_val = strtoul(value, NULL, 0); + if ((errno == ERANGE && tuple_val == ULONG_MAX) + || (errno != 0 && tuple_val == 0)) { + SNDERR("error: tuple %s:strtoul fail\n", id); + goto err; + } + + if ((type == SND_SOC_TPLG_TUPLE_TYPE_WORD + && tuple_val > UINT_MAX) + || (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT + && tuple_val > USHRT_MAX) + || (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE + && tuple_val > UCHAR_MAX)) { + SNDERR("error: tuple %s: invalid value\n", id); + goto err; + } + + tuple->value = (unsigned int) tuple_val; + tplg_dbg("\t\t%s = 0x%x\n", tuple->token, tuple->value); + break; + + default: + break; + } + + set->num_tuples++; + } + + *s = set; + return 0; + +err: + free(set); + return -EINVAL; +} + +static int parse_tuple_sets(snd_config_t *cfg, + struct tplg_vendor_tuples *tuples) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + unsigned int num_tuple_sets = 0; + int err; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + if (snd_config_get_id(cfg, &id) >= 0) + SNDERR("error: compound type expected for %s", id); + return -EINVAL; + } + + snd_config_for_each(i, next, cfg) { + num_tuple_sets++; + } + + if (!num_tuple_sets) + return 0; + + tuples->set = calloc(1, num_tuple_sets * sizeof(void *)); + if (!tuples->set) + return -ENOMEM; + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound type expected for %s, is %d", + id, snd_config_get_type(n)); + return -EINVAL; + } + + err = parse_tuple_set(n, &tuples->set[tuples->num_sets]); + if (err < 0) + return err; + + /* overlook empty tuple sets */ + if (tuples->set[tuples->num_sets]) + tuples->num_sets++; + } + + return 0; +} + +/* Parse tuples references for a data element, either a single tuples section + * or a list of tuples sections. + */ +static int parse_tuples_refs(snd_config_t *cfg, + struct tplg_elem *elem) +{ + snd_config_type_t type; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *val = NULL; + + type = snd_config_get_type(cfg); + + /* refer to a single tuples section */ + if (type == SND_CONFIG_TYPE_STRING) { + if (snd_config_get_string(cfg, &val) < 0) + return -EINVAL; + tplg_dbg("\ttuples: %s\n", val); + return tplg_ref_add(elem, SND_TPLG_TYPE_TUPLE, val); + } + + if (type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound type expected for %s", elem->id); + return -EINVAL; + } + + /* refer to a list of data sections */ + snd_config_for_each(i, next, cfg) { + const char *val; + + n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &val) < 0) + continue; + + tplg_dbg("\ttuples: %s\n", val); + tplg_ref_add(elem, SND_TPLG_TYPE_TUPLE, val); + } + + return 0; +} + +/* Parse private data references for the element, either a single data section + * or a list of data sections. + */ +int tplg_parse_data_refs(snd_config_t *cfg, + struct tplg_elem *elem) +{ + snd_config_type_t type; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *val = NULL; + + type = snd_config_get_type(cfg); + + /* refer to a single data section */ + if (type == SND_CONFIG_TYPE_STRING) { + if (snd_config_get_string(cfg, &val) < 0) + return -EINVAL; + + tplg_dbg("\tdata: %s\n", val); + return tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); + } + + if (type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound type expected for %s", elem->id); + return -EINVAL; + } + + /* refer to a list of data sections */ + snd_config_for_each(i, next, cfg) { + const char *val; + + n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &val) < 0) + continue; + + tplg_dbg("\tdata: %s\n", val); + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); + } + + return 0; +} + +/* Parse vendor tokens + */ +int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *value; + struct tplg_elem *elem; + struct tplg_vendor_tokens *tokens; + int num_tokens = 0; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TOKEN); + if (!elem) + return -ENOMEM; + + snd_config_for_each(i, next, cfg) { + num_tokens++; + } + + if (!num_tokens) + return 0; + + tplg_dbg(" Vendor tokens: %s, %d tokens\n", elem->id, num_tokens); + + tokens = calloc(1, sizeof(*tokens) + + num_tokens * sizeof(struct tplg_token)); + if (!tokens) + return -ENOMEM; + elem->tokens = tokens; + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + if (snd_config_get_string(n, &value) < 0) + continue; + + snd_strlcpy(tokens->token[tokens->num_tokens].id, id, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + tokens->token[tokens->num_tokens].value = atoi(value); + tplg_dbg("\t\t %s : %d\n", tokens->token[tokens->num_tokens].id, + tokens->token[tokens->num_tokens].value); + tokens->num_tokens++; + } + + return 0; +} + +/* Parse vendor tuples. + */ +int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *value; + struct tplg_elem *elem; + struct tplg_vendor_tuples *tuples; + int err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE); + if (!elem) + return -ENOMEM; + + tplg_dbg(" Vendor Tuples: %s\n", elem->id); + + tuples = calloc(1, sizeof(*tuples)); + if (!tuples) + return -ENOMEM; + elem->tuples = tuples; + + 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, "tokens") == 0) { + if (snd_config_get_string(n, &value) < 0) + return -EINVAL; + tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value); + tplg_dbg("\t refer to vendor tokens: %s\n", value); + } + + if (strcmp(id, "tuples") == 0) { + err = parse_tuple_sets(n, tuples); + if (err < 0) + return err; + } + } + + return 0; +} + +/* Free handler of tuples */ +void tplg_free_tuples(void *obj) +{ + struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj; + unsigned int i; + + if (!tuples || !tuples->set) + return; + + for (i = 0; i < tuples->num_sets; i++) + free(tuples->set[i]); + + free(tuples->set); +} + +/* Parse manifest's data references + */ +int tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_manifest *manifest; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + int err; + + if (!list_empty(&tplg->manifest_list)) { + SNDERR("error: already has manifest data\n"); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MANIFEST); + if (!elem) + return -ENOMEM; + + manifest = elem->manifest; + manifest->size = elem->size; + + tplg_dbg(" Manifest: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + } + + return 0; +} + +/* merge private data of manifest */ +int tplg_build_manifest_data(snd_tplg_t *tplg) +{ + struct list_head *base, *pos; + struct tplg_elem *elem = NULL; + struct tplg_ref *ref; + struct snd_soc_tplg_manifest *manifest; + int err = 0; + + base = &tplg->manifest_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + break; + } + + if (!elem) /* no manifest data */ + return 0; + + base = &elem->ref_list; + + /* for each ref in this manifest elem */ + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + } + + manifest = elem->manifest; + if (!manifest->priv.size) /* no manifest data */ + return 0; + + tplg->manifest_pdata = malloc(manifest->priv.size); + if (!tplg->manifest_pdata) + return -ENOMEM; + + tplg->manifest.priv.size = manifest->priv.size; + memcpy(tplg->manifest_pdata, manifest->priv.data, manifest->priv.size); + return 0; +} + +/* Parse Private data. + * + * Object private data can either be from file or defined as bytes, shorts, + * words, tuples. + */ +int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err = 0; + struct tplg_elem *elem; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DATA); + if (!elem) + return -ENOMEM; + + 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, "file") == 0) { + err = tplg_parse_data_file(n, elem); + if (err < 0) { + SNDERR("error: failed to parse data file\n"); + return err; + } + continue; + } + + if (strcmp(id, "bytes") == 0) { + err = tplg_parse_data_hex(n, elem, 1); + if (err < 0) { + SNDERR("error: failed to parse data bytes\n"); + return err; + } + continue; + } + + if (strcmp(id, "shorts") == 0) { + err = tplg_parse_data_hex(n, elem, 2); + if (err < 0) { + SNDERR("error: failed to parse data shorts\n"); + return err; + } + continue; + } + + if (strcmp(id, "words") == 0) { + err = tplg_parse_data_hex(n, elem, 4); + if (err < 0) { + SNDERR("error: failed to parse data words\n"); + return err; + } + continue; + } + + if (strcmp(id, "tuples") == 0) { + err = parse_tuples_refs(n, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "type") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + elem->vendor_type = atoi(val); + tplg_dbg("\t%s: %d\n", id, elem->index); + continue; + } + } + + return err; +} + +/* Find a referenced data element and copy its data to the parent + * element's private data buffer. + * An element can refer to multiple data sections. Data of these sections + * will be merged in the their reference order. + */ +int tplg_copy_data(snd_tplg_t *tplg, struct tplg_elem *elem, + struct tplg_ref *ref) +{ + struct tplg_elem *ref_elem; + struct snd_soc_tplg_private *priv, *old_priv; + int priv_data_size, old_priv_data_size; + void *obj; + + ref_elem = tplg_elem_lookup(&tplg->pdata_list, + ref->id, SND_TPLG_TYPE_DATA, elem->index); + if (!ref_elem) { + SNDERR("error: cannot find data '%s' referenced by" + " element '%s'\n", ref->id, elem->id); + return -EINVAL; + } + + tplg_dbg("Data '%s' used by '%s'\n", ref->id, elem->id); + /* overlook empty private data */ + if (!ref_elem->data || !ref_elem->data->size) { + ref->elem = ref_elem; + return 0; + } + + old_priv = get_priv_data(elem); + if (!old_priv) + return -EINVAL; + old_priv_data_size = old_priv->size; + + priv_data_size = ref_elem->data->size; + obj = realloc(elem->obj, + elem->size + priv_data_size); + if (!obj) + return -ENOMEM; + elem->obj = obj; + + priv = get_priv_data(elem); + if (!priv) + return -EINVAL; + + /* merge the new data block */ + elem->size += priv_data_size; + priv->size = priv_data_size + old_priv_data_size; + ref_elem->compound_elem = 1; + memcpy(priv->data + old_priv_data_size, + ref_elem->data->data, priv_data_size); + + ref->elem = ref_elem; + return 0; +} + +/* check data objects and build those with tuples */ +int tplg_build_data(snd_tplg_t *tplg) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + int err = 0; + + base = &tplg->pdata_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + if (has_tuples(elem)) { + err = build_tuples(tplg, elem); + if (err < 0) + return err; + } + } + + return 0; +} diff --git a/src/topology/elem.c b/src/topology/elem.c new file mode 100644 index 0000000..a9d1d85 --- /dev/null +++ b/src/topology/elem.c @@ -0,0 +1,278 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +int tplg_ref_add(struct tplg_elem *elem, int type, const char* id) +{ + struct tplg_ref *ref; + + ref = calloc(1, sizeof(*ref)); + if (!ref) + return -ENOMEM; + + strncpy(ref->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + ref->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0; + ref->type = type; + + list_add_tail(&ref->list, &elem->ref_list); + return 0; +} + +/* directly add a reference elem */ +int tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref) +{ + struct tplg_ref *ref; + + ref = calloc(1, sizeof(*ref)); + if (!ref) + return -ENOMEM; + + ref->type = elem_ref->type; + ref->elem = elem_ref; + snd_strlcpy(ref->id, elem_ref->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + list_add_tail(&ref->list, &elem->ref_list); + return 0; +} + +void tplg_ref_free_list(struct list_head *base) +{ + struct list_head *pos, *npos; + struct tplg_ref *ref; + + list_for_each_safe(pos, npos, base) { + ref = list_entry(pos, struct tplg_ref, list); + list_del(&ref->list); + free(ref); + } +} + +struct tplg_elem *tplg_elem_new(void) +{ + struct tplg_elem *elem; + + elem = calloc(1, sizeof(*elem)); + if (!elem) + return NULL; + + INIT_LIST_HEAD(&elem->ref_list); + return elem; +} + +void tplg_elem_free(struct tplg_elem *elem) +{ + tplg_ref_free_list(&elem->ref_list); + + /* free struct snd_tplg_ object, + * the union pointers share the same address + */ + if (elem->obj) { + if (elem->free) + elem->free(elem->obj); + + free(elem->obj); + } + + free(elem); +} + +void tplg_elem_free_list(struct list_head *base) +{ + struct list_head *pos, *npos; + struct tplg_elem *elem; + + list_for_each_safe(pos, npos, base) { + elem = list_entry(pos, struct tplg_elem, list); + list_del(&elem->list); + tplg_elem_free(elem); + } +} + +struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id, + unsigned int type, int index) +{ + struct list_head *pos; + struct tplg_elem *elem; + + if (!base || !id) + return NULL; + + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + + if (!strcmp(elem->id, id) && elem->type == type) + return elem; + /* SND_TPLG_INDEX_ALL is the default value "0" and applicable + for all use cases */ + if ((index != SND_TPLG_INDEX_ALL) + && (elem->index > index)) + break; + } + + return NULL; +} + +/* insert a new element into list in the ascending order of index value*/ +static void tplg_elem_insert(struct tplg_elem *elem_p, struct list_head *list) +{ + struct list_head *pos, *p = &(elem_p->list); + struct tplg_elem *elem; + + list_for_each(pos, list) { + elem = list_entry(pos, struct tplg_elem, list); + if (elem_p->index < elem->index) + break; + } + p->prev = pos->prev; + pos->prev->next = p; + pos->prev = p; + p->next = pos; +} + +/* create a new common element and object */ +struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, + snd_config_t *cfg, const char *name, enum snd_tplg_type type) +{ + struct tplg_elem *elem; + const char *id, *val = NULL; + int obj_size = 0; + void *obj; + snd_config_iterator_t i, next; + snd_config_t *n; + + if (!cfg && !name) + return NULL; + + elem = tplg_elem_new(); + if (!elem) + return NULL; + + /* do we get name from cfg */ + if (cfg) { + snd_config_get_id(cfg, &id); + snd_strlcpy(elem->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + elem->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0; + /* as we insert new elem based on the index value, move index + parsing here */ + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id)) + continue; + if (strcmp(id, "index") == 0) { + if (snd_config_get_string(n, &val) < 0) { + free(elem); + return NULL; + } + elem->index = atoi(val); + } + } + } else if (name != NULL) + snd_strlcpy(elem->id, name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + switch (type) { + case SND_TPLG_TYPE_DATA: + tplg_elem_insert(elem, &tplg->pdata_list); + break; + case SND_TPLG_TYPE_MANIFEST: + tplg_elem_insert(elem, &tplg->manifest_list); + obj_size = sizeof(struct snd_soc_tplg_manifest); + break; + case SND_TPLG_TYPE_TEXT: + tplg_elem_insert(elem, &tplg->text_list); + obj_size = sizeof(struct tplg_texts); + break; + case SND_TPLG_TYPE_TLV: + tplg_elem_insert(elem, &tplg->tlv_list); + elem->size = sizeof(struct snd_soc_tplg_ctl_tlv); + break; + case SND_TPLG_TYPE_BYTES: + tplg_elem_insert(elem, &tplg->bytes_ext_list); + obj_size = sizeof(struct snd_soc_tplg_bytes_control); + break; + case SND_TPLG_TYPE_ENUM: + tplg_elem_insert(elem, &tplg->enum_list); + obj_size = sizeof(struct snd_soc_tplg_enum_control); + break; + case SND_TPLG_TYPE_MIXER: + tplg_elem_insert(elem, &tplg->mixer_list); + obj_size = sizeof(struct snd_soc_tplg_mixer_control); + break; + case SND_TPLG_TYPE_DAPM_WIDGET: + tplg_elem_insert(elem, &tplg->widget_list); + obj_size = sizeof(struct snd_soc_tplg_dapm_widget); + break; + case SND_TPLG_TYPE_STREAM_CONFIG: + tplg_elem_insert(elem, &tplg->pcm_config_list); + obj_size = sizeof(struct snd_soc_tplg_stream); + break; + case SND_TPLG_TYPE_STREAM_CAPS: + tplg_elem_insert(elem, &tplg->pcm_caps_list); + obj_size = sizeof(struct snd_soc_tplg_stream_caps); + break; + case SND_TPLG_TYPE_PCM: + tplg_elem_insert(elem, &tplg->pcm_list); + obj_size = sizeof(struct snd_soc_tplg_pcm); + break; + case SND_TPLG_TYPE_DAI: + tplg_elem_insert(elem, &tplg->dai_list); + obj_size = sizeof(struct snd_soc_tplg_dai); + break; + case SND_TPLG_TYPE_BE: + case SND_TPLG_TYPE_LINK: + tplg_elem_insert(elem, &tplg->be_list); + obj_size = sizeof(struct snd_soc_tplg_link_config); + break; + case SND_TPLG_TYPE_CC: + tplg_elem_insert(elem, &tplg->cc_list); + obj_size = sizeof(struct snd_soc_tplg_link_config); + break; + case SND_TPLG_TYPE_TOKEN: + tplg_elem_insert(elem, &tplg->token_list); + break; + case SND_TPLG_TYPE_TUPLE: + tplg_elem_insert(elem, &tplg->tuple_list); + elem->free = tplg_free_tuples; + break; + case SND_TPLG_TYPE_HW_CONFIG: + tplg_elem_insert(elem, &tplg->hw_cfg_list); + obj_size = sizeof(struct snd_soc_tplg_hw_config); + break; + default: + free(elem); + return NULL; + } + + /* create new object too if required */ + if (obj_size > 0) { + obj = calloc(1, obj_size); + if (obj == NULL) { + free(elem); + return NULL; + } + + elem->obj = obj; + elem->size = obj_size; + } + + elem->type = type; + return elem; +} diff --git a/src/topology/ops.c b/src/topology/ops.c new file mode 100644 index 0000000..6f8dc1f --- /dev/null +++ b/src/topology/ops.c @@ -0,0 +1,123 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +/* mapping of kcontrol text names to types */ +static const struct map_elem control_map[] = { + {"volsw", SND_SOC_TPLG_CTL_VOLSW}, + {"volsw_sx", SND_SOC_TPLG_CTL_VOLSW_SX}, + {"volsw_xr_sx", SND_SOC_TPLG_CTL_VOLSW_XR_SX}, + {"enum", SND_SOC_TPLG_CTL_ENUM}, + {"bytes", SND_SOC_TPLG_CTL_BYTES}, + {"enum_value", SND_SOC_TPLG_CTL_ENUM_VALUE}, + {"range", SND_SOC_TPLG_CTL_RANGE}, + {"strobe", SND_SOC_TPLG_CTL_STROBE}, +}; + +static int lookup_ops(const char *c) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(control_map); i++) { + if (strcmp(control_map[i].name, c) == 0) + return control_map[i].id; + } + + /* cant find string name in our table so we use its ID number */ + return atoi(c); +} + +/* Parse Control operations. Ops can come from standard names above or + * bespoke driver controls with numbers >= 256 + */ +int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct snd_soc_tplg_ctl_hdr *hdr = private; + const char *id, *value; + + tplg_dbg("\tOps\n"); + hdr->size = sizeof(*hdr); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get id */ + if (snd_config_get_id(n, &id) < 0) + continue; + + /* get value - try strings then ints */ + if (snd_config_get_string(n, &value) < 0) + continue; + + if (strcmp(id, "info") == 0) + hdr->ops.info = lookup_ops(value); + else if (strcmp(id, "put") == 0) + hdr->ops.put = lookup_ops(value); + else if (strcmp(id, "get") == 0) + hdr->ops.get = lookup_ops(value); + + tplg_dbg("\t\t%s = %s\n", id, value); + } + + return 0; +} + +/* Parse External Control operations. Ops can come from standard names above or + * bespoke driver controls with numbers >= 256 + */ +int tplg_parse_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct snd_soc_tplg_bytes_control *be = private; + const char *id, *value; + + tplg_dbg("\tExt Ops\n"); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get id */ + if (snd_config_get_id(n, &id) < 0) + continue; + + /* get value - try strings then ints */ + if (snd_config_get_string(n, &value) < 0) + continue; + + if (strcmp(id, "info") == 0) + be->ext_ops.info = lookup_ops(value); + else if (strcmp(id, "put") == 0) + be->ext_ops.put = lookup_ops(value); + else if (strcmp(id, "get") == 0) + be->ext_ops.get = lookup_ops(value); + + tplg_dbg("\t\t%s = %s\n", id, value); + } + + return 0; +} diff --git a/src/topology/parser.c b/src/topology/parser.c new file mode 100644 index 0000000..5940692 --- /dev/null +++ b/src/topology/parser.c @@ -0,0 +1,516 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include +#include "list.h" +#include "tplg_local.h" + +/* + * Parse compound + */ +int tplg_parse_compound(snd_tplg_t *tplg, snd_config_t *cfg, + int (*fcn)(snd_tplg_t *, snd_config_t *, void *), + void *private) +{ + const char *id; + snd_config_iterator_t i, next; + snd_config_t *n; + int err = -EINVAL; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("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) { + SNDERR("error: compound type expected for %s, is %d", + id, snd_config_get_type(cfg)); + return -EINVAL; + } + + err = fcn(tplg, n, private); + if (err < 0) + return err; + } + + return err; +} + +static int tplg_parse_config(snd_tplg_t *tplg, 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) { + SNDERR("error: compound type expected at top level"); + return -EINVAL; + } + + /* parse topology 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, "SectionTLV") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_tlv, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionControlMixer") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_control_mixer, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionControlEnum") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_control_enum, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionControlBytes") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_control_bytes, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionWidget") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_dapm_widget, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionPCMCapabilities") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_stream_caps, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionPCM") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_pcm, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionDAI") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_dai, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionHWConfig") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_hw_config, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionLink") == 0 + || strcmp(id, "SectionBE") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_link, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionCC") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_cc, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionGraph") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_dapm_graph, NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionText") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_text, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionData") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_data, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionVendorTokens") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_tokens, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionVendorTuples") == 0) { + err = tplg_parse_compound(tplg, n, tplg_parse_tuples, + NULL); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "SectionManifest") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_manifest_data, + NULL); + if (err < 0) + return err; + continue; + } + + SNDERR("error: unknown section %s\n", id); + } + return 0; +} + +static int tplg_load_config(const char *file, snd_config_t **cfg) +{ + FILE *fp; + snd_input_t *in; + snd_config_t *top; + int ret; + + fp = fopen(file, "r"); + if (fp == NULL) { + SNDERR("error: could not open configuration file %s", + file); + return -errno; + } + + ret = snd_input_stdio_attach(&in, fp, 1); + if (ret < 0) { + fclose(fp); + SNDERR("error: could not attach stdio %s", file); + return ret; + } + ret = snd_config_top(&top); + if (ret < 0) + goto err; + + ret = snd_config_load(top, in); + if (ret < 0) { + SNDERR("error: could not load configuration file %s", + file); + goto err_load; + } + + ret = snd_input_close(in); + if (ret < 0) { + in = NULL; + goto err_load; + } + + *cfg = top; + return 0; + +err_load: + snd_config_delete(top); +err: + if (in) + snd_input_close(in); + return ret; +} + +static int tplg_build_integ(snd_tplg_t *tplg) +{ + int err; + + err = tplg_build_data(tplg); + if (err < 0) + return err; + + err = tplg_build_manifest_data(tplg); + if (err < 0) + return err; + + err = tplg_build_controls(tplg); + if (err < 0) + return err; + + err = tplg_build_widgets(tplg); + if (err < 0) + return err; + + err = tplg_build_pcms(tplg, SND_TPLG_TYPE_PCM); + if (err < 0) + return err; + + err = tplg_build_dais(tplg, SND_TPLG_TYPE_DAI); + if (err < 0) + return err; + + err = tplg_build_links(tplg, SND_TPLG_TYPE_BE); + if (err < 0) + return err; + + err = tplg_build_links(tplg, SND_TPLG_TYPE_CC); + if (err < 0) + return err; + + err = tplg_build_routes(tplg); + if (err < 0) + return err; + + return err; +} + +int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile, + const char *outfile) +{ + snd_config_t *cfg = NULL; + int err = 0; + + tplg->out_fd = + open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (tplg->out_fd < 0) { + SNDERR("error: failed to open %s err %d\n", + outfile, -errno); + return -errno; + } + + err = tplg_load_config(infile, &cfg); + if (err < 0) { + SNDERR("error: failed to load topology file %s\n", + infile); + goto out_close; + } + + err = tplg_parse_config(tplg, cfg); + if (err < 0) { + SNDERR("error: failed to parse topology\n"); + goto out; + } + + err = tplg_build_integ(tplg); + if (err < 0) { + SNDERR("error: failed to check topology integrity\n"); + goto out; + } + + err = tplg_write_data(tplg); + if (err < 0) { + SNDERR("error: failed to write data %d\n", err); + goto out; + } + +out: + snd_config_delete(cfg); +out_close: + close(tplg->out_fd); + return err; +} + +int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + switch (t->type) { + case SND_TPLG_TYPE_MIXER: + return tplg_add_mixer_object(tplg, t); + case SND_TPLG_TYPE_ENUM: + return tplg_add_enum_object(tplg, t); + case SND_TPLG_TYPE_BYTES: + return tplg_add_bytes_object(tplg, t); + case SND_TPLG_TYPE_DAPM_WIDGET: + return tplg_add_widget_object(tplg, t); + case SND_TPLG_TYPE_DAPM_GRAPH: + return tplg_add_graph_object(tplg, t); + case SND_TPLG_TYPE_PCM: + return tplg_add_pcm_object(tplg, t); + case SND_TPLG_TYPE_DAI: + return tplg_add_dai_object(tplg, t); + case SND_TPLG_TYPE_LINK: + case SND_TPLG_TYPE_BE: + case SND_TPLG_TYPE_CC: + return tplg_add_link_object(tplg, t); + default: + SNDERR("error: invalid object type %d\n", t->type); + return -EINVAL; + }; +} + +int snd_tplg_build(snd_tplg_t *tplg, const char *outfile) +{ + int err; + + tplg->out_fd = + open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (tplg->out_fd < 0) { + SNDERR("error: failed to open %s err %d\n", + outfile, -errno); + return -errno; + } + + err = tplg_build_integ(tplg); + if (err < 0) { + SNDERR("error: failed to check topology integrity\n"); + goto out; + } + + err = tplg_write_data(tplg); + if (err < 0) { + SNDERR("error: failed to write data %d\n", err); + goto out; + } + +out: + close(tplg->out_fd); + return err; +} + +int snd_tplg_set_manifest_data(snd_tplg_t *tplg, const void *data, int len) +{ + if (len <= 0) + return 0; + + tplg->manifest.priv.size = len; + + tplg->manifest_pdata = malloc(len); + if (!tplg->manifest_pdata) + return -ENOMEM; + + memcpy(tplg->manifest_pdata, data, len); + return 0; +} + +int snd_tplg_set_version(snd_tplg_t *tplg, unsigned int version) +{ + tplg->version = version; + + return 0; +} + +void snd_tplg_verbose(snd_tplg_t *tplg, int verbose) +{ + tplg->verbose = verbose; +} + +static bool is_little_endian(void) +{ +#ifdef __BYTE_ORDER + #if __BYTE_ORDER == __LITTLE_ENDIAN + return true; + #endif +#endif + return false; +} + +snd_tplg_t *snd_tplg_new(void) +{ + snd_tplg_t *tplg; + + if (!is_little_endian()) { + SNDERR("error: cannot support big-endian machines\n"); + return NULL; + } + + tplg = calloc(1, sizeof(snd_tplg_t)); + if (!tplg) + return NULL; + + tplg->manifest.size = sizeof(struct snd_soc_tplg_manifest); + + INIT_LIST_HEAD(&tplg->tlv_list); + INIT_LIST_HEAD(&tplg->widget_list); + INIT_LIST_HEAD(&tplg->pcm_list); + INIT_LIST_HEAD(&tplg->dai_list); + INIT_LIST_HEAD(&tplg->be_list); + INIT_LIST_HEAD(&tplg->cc_list); + INIT_LIST_HEAD(&tplg->route_list); + INIT_LIST_HEAD(&tplg->pdata_list); + INIT_LIST_HEAD(&tplg->manifest_list); + INIT_LIST_HEAD(&tplg->text_list); + INIT_LIST_HEAD(&tplg->pcm_config_list); + INIT_LIST_HEAD(&tplg->pcm_caps_list); + INIT_LIST_HEAD(&tplg->mixer_list); + INIT_LIST_HEAD(&tplg->enum_list); + INIT_LIST_HEAD(&tplg->bytes_ext_list); + INIT_LIST_HEAD(&tplg->token_list); + INIT_LIST_HEAD(&tplg->tuple_list); + INIT_LIST_HEAD(&tplg->hw_cfg_list); + + return tplg; +} + +void snd_tplg_free(snd_tplg_t *tplg) +{ + if (tplg->manifest_pdata) + free(tplg->manifest_pdata); + + tplg_elem_free_list(&tplg->tlv_list); + tplg_elem_free_list(&tplg->widget_list); + tplg_elem_free_list(&tplg->pcm_list); + tplg_elem_free_list(&tplg->dai_list); + tplg_elem_free_list(&tplg->be_list); + tplg_elem_free_list(&tplg->cc_list); + tplg_elem_free_list(&tplg->route_list); + tplg_elem_free_list(&tplg->pdata_list); + tplg_elem_free_list(&tplg->manifest_list); + tplg_elem_free_list(&tplg->text_list); + tplg_elem_free_list(&tplg->pcm_config_list); + tplg_elem_free_list(&tplg->pcm_caps_list); + tplg_elem_free_list(&tplg->mixer_list); + tplg_elem_free_list(&tplg->enum_list); + tplg_elem_free_list(&tplg->bytes_ext_list); + tplg_elem_free_list(&tplg->token_list); + tplg_elem_free_list(&tplg->tuple_list); + tplg_elem_free_list(&tplg->hw_cfg_list); + + free(tplg); +} diff --git a/src/topology/pcm.c b/src/topology/pcm.c new file mode 100644 index 0000000..553fd82 --- /dev/null +++ b/src/topology/pcm.c @@ -0,0 +1,1587 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +#define RATE(v) [SND_PCM_RATE_##v] = #v + +static const char *const snd_pcm_rate_names[] = { + RATE(5512), + RATE(8000), + RATE(11025), + RATE(16000), + RATE(22050), + RATE(32000), + RATE(44100), + RATE(48000), + RATE(64000), + RATE(88200), + RATE(96000), + RATE(176400), + RATE(192000), + RATE(CONTINUOUS), + RATE(KNOT), +}; + +struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id) +{ + struct list_head *pos; + struct tplg_elem *elem; + struct snd_soc_tplg_pcm *pcm; + + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + if (elem->type != SND_TPLG_TYPE_PCM) + return NULL; + + pcm = elem->pcm; + + if (pcm && !strcmp(pcm->dai_name, id)) + return elem; + } + + return NULL; +} + +/* copy referenced caps to the parent (pcm or be dai) */ +static void copy_stream_caps(const char *id ATTRIBUTE_UNUSED, + struct snd_soc_tplg_stream_caps *caps, struct tplg_elem *ref_elem) +{ + struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps; + + tplg_dbg("Copy pcm caps (%ld bytes) from '%s' to '%s' \n", + sizeof(*caps), ref_elem->id, id); + + *caps = *ref_caps; +} + +/* find and copy the referenced stream caps */ +static int tplg_build_stream_caps(snd_tplg_t *tplg, + const char *id, int index, struct snd_soc_tplg_stream_caps *caps) +{ + struct tplg_elem *ref_elem = NULL; + unsigned int i; + + for (i = 0; i < 2; i++) { + ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list, + caps[i].name, SND_TPLG_TYPE_STREAM_CAPS, index); + + if (ref_elem != NULL) + copy_stream_caps(id, &caps[i], ref_elem); + } + + return 0; +} + +/* build a PCM (FE DAI & DAI link) element */ +static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err; + + err = tplg_build_stream_caps(tplg, elem->id, elem->index, + elem->pcm->caps); + if (err < 0) + return err; + + /* merge private data from the referenced data elements */ + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + if (!ref->elem) { + SNDERR("error: cannot find '%s' referenced by" + " PCM '%s'\n", ref->id, elem->id); + return -EINVAL; + } + } + + return 0; +} + +/* build all PCM (FE DAI & DAI link) elements */ +int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + int err = 0; + + base = &tplg->pcm_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + if (elem->type != type) { + SNDERR("error: invalid elem '%s'\n", elem->id); + return -EINVAL; + } + + err = build_pcm(tplg, elem); + if (err < 0) + return err; + + /* add PCM to manifest */ + tplg->manifest.pcm_elems++; + } + + return 0; +} + +/* build a physical DAI */ +static int tplg_build_dai(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct tplg_ref *ref; + struct list_head *base, *pos; + int err = 0; + + /* get playback & capture stream caps */ + err = tplg_build_stream_caps(tplg, elem->id, elem->index, + elem->dai->caps); + if (err < 0) + return err; + + /* get private data */ + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + if (ref->type == SND_TPLG_TYPE_DATA) { + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + } + } + + /* add DAI to manifest */ + tplg->manifest.dai_elems++; + + return 0; +} + +/* build physical DAIs*/ +int tplg_build_dais(snd_tplg_t *tplg, unsigned int type) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + int err = 0; + + base = &tplg->dai_list; + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + if (elem->type != type) { + SNDERR("error: invalid elem '%s'\n", elem->id); + return -EINVAL; + } + + err = tplg_build_dai(tplg, elem); + if (err < 0) + return err; + } + + return 0; +} + +static int tplg_build_stream_cfg(snd_tplg_t *tplg, + struct snd_soc_tplg_stream *stream, int num_streams, int index) +{ + struct snd_soc_tplg_stream *strm; + struct tplg_elem *ref_elem; + int i; + + for (i = 0; i < num_streams; i++) { + strm = stream + i; + ref_elem = tplg_elem_lookup(&tplg->pcm_config_list, + strm->name, SND_TPLG_TYPE_STREAM_CONFIG, index); + + if (ref_elem && ref_elem->stream_cfg) + *strm = *ref_elem->stream_cfg; + } + + return 0; +} + +static int build_link(snd_tplg_t *tplg, struct tplg_elem *elem) +{ + struct snd_soc_tplg_link_config *link = elem->link; + struct tplg_ref *ref; + struct list_head *base, *pos; + int num_hw_configs = 0, err = 0; + + err = tplg_build_stream_cfg(tplg, link->stream, + link->num_streams, elem->index); + if (err < 0) + return err; + + /* hw configs & private data */ + base = &elem->ref_list; + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); + + switch (ref->type) { + case SND_TPLG_TYPE_HW_CONFIG: + ref->elem = tplg_elem_lookup(&tplg->hw_cfg_list, + ref->id, SND_TPLG_TYPE_HW_CONFIG, elem->index); + if (!ref->elem) { + SNDERR("error: cannot find HW config '%s'" + " referenced by link '%s'\n", + ref->id, elem->id); + return -EINVAL; + } + + memcpy(&link->hw_config[num_hw_configs], + ref->elem->hw_cfg, + sizeof(struct snd_soc_tplg_hw_config)); + num_hw_configs++; + break; + + case SND_TPLG_TYPE_DATA: /* merge private data */ + err = tplg_copy_data(tplg, elem, ref); + if (err < 0) + return err; + break; + + default: + break; + } + } + + /* add link to manifest */ + tplg->manifest.dai_link_elems++; + + return 0; +} + +/* build physical DAI link configurations */ +int tplg_build_links(snd_tplg_t *tplg, unsigned int type) +{ + struct list_head *base, *pos; + struct tplg_elem *elem; + int err = 0; + + switch (type) { + case SND_TPLG_TYPE_LINK: + case SND_TPLG_TYPE_BE: + base = &tplg->be_list; + break; + case SND_TPLG_TYPE_CC: + base = &tplg->cc_list; + break; + default: + return -EINVAL; + } + + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + err = build_link(tplg, elem); + if (err < 0) + return err; + } + + return 0; +} + +static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str) +{ + char *s = NULL; + snd_pcm_format_t format; + int i = 0; + + s = strtok(str, ","); + while ((s != NULL) && (i < SND_SOC_TPLG_MAX_FORMATS)) { + format = snd_pcm_format_value(s); + if (format == SND_PCM_FORMAT_UNKNOWN) { + SNDERR("error: unsupported stream format %s\n", s); + return -EINVAL; + } + + caps->formats |= 1ull << format; + s = strtok(NULL, ", "); + i++; + } + + return 0; +} + +static int get_rate_value(const char* name) +{ + int rate; + for (rate = 0; rate <= SND_PCM_RATE_LAST; rate++) { + if (snd_pcm_rate_names[rate] && + strcasecmp(name, snd_pcm_rate_names[rate]) == 0) { + return rate; + } + } + + return SND_PCM_RATE_UNKNOWN; +} + +static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str) +{ + char *s = NULL; + snd_pcm_rates_t rate; + int i = 0; + + s = strtok(str, ","); + while (s) { + rate = get_rate_value(s); + + if (rate == SND_PCM_RATE_UNKNOWN) { + SNDERR("error: unsupported stream rate %s\n", s); + return -EINVAL; + } + + caps->rates |= 1 << rate; + s = strtok(NULL, ", "); + i++; + } + + return 0; +} + +/* Parse pcm stream capabilities */ +int tplg_parse_stream_caps(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_stream_caps *sc; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val; + char *s; + int err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CAPS); + if (!elem) + return -ENOMEM; + + sc = elem->stream_caps; + sc->size = elem->size; + snd_strlcpy(sc->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + tplg_dbg(" PCM Capabilities: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (strcmp(id, "formats") == 0) { + s = strdup(val); + if (s == NULL) + return -ENOMEM; + + err = split_format(sc, s); + free(s); + + if (err < 0) + return err; + + tplg_dbg("\t\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "rates") == 0) { + s = strdup(val); + if (!s) + return -ENOMEM; + + err = split_rate(sc, s); + free(s); + + if (err < 0) + return err; + + tplg_dbg("\t\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "rate_min") == 0) { + sc->rate_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->rate_min); + continue; + } + + if (strcmp(id, "rate_max") == 0) { + sc->rate_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->rate_max); + continue; + } + + if (strcmp(id, "channels_min") == 0) { + sc->channels_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->channels_min); + continue; + } + + if (strcmp(id, "channels_max") == 0) { + sc->channels_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->channels_max); + continue; + } + + if (strcmp(id, "periods_min") == 0) { + sc->periods_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->periods_min); + continue; + } + + if (strcmp(id, "periods_max") == 0) { + sc->periods_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->periods_max); + continue; + } + + if (strcmp(id, "period_size_min") == 0) { + sc->period_size_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->period_size_min); + continue; + } + + if (strcmp(id, "period_size_max") == 0) { + sc->period_size_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->period_size_max); + continue; + } + + if (strcmp(id, "buffer_size_min") == 0) { + sc->buffer_size_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->buffer_size_min); + continue; + } + + if (strcmp(id, "buffer_size_max") == 0) { + sc->buffer_size_max = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->buffer_size_max); + continue; + } + + if (strcmp(id, "sig_bits") == 0) { + sc->sig_bits = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->sig_bits); + continue; + } + + } + + return 0; +} + +/* Parse the caps and config of a pcm stream */ +static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + struct tplg_elem *elem = private; + struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_dai *dai; + unsigned int *playback, *capture; + struct snd_soc_tplg_stream_caps *caps; + const char *id, *value; + int stream; + + snd_config_get_id(cfg, &id); + + tplg_dbg("\t%s:\n", id); + + switch (elem->type) { + case SND_TPLG_TYPE_PCM: + pcm = elem->pcm; + playback = &pcm->playback; + capture = &pcm->capture; + caps = pcm->caps; + break; + + case SND_TPLG_TYPE_DAI: + dai = elem->dai; + playback = &dai->playback; + capture = &dai->capture; + caps = dai->caps; + break; + + default: + return -EINVAL; + } + + if (strcmp(id, "playback") == 0) { + stream = SND_SOC_TPLG_STREAM_PLAYBACK; + *playback = 1; + } else if (strcmp(id, "capture") == 0) { + stream = SND_SOC_TPLG_STREAM_CAPTURE; + *capture = 1; + } else + return -EINVAL; + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get id */ + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "capabilities") == 0) { + if (snd_config_get_string(n, &value) < 0) + continue; + /* store stream caps name, to find and merge + * the caps in building phase. + */ + snd_strlcpy(caps[stream].name, value, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + tplg_dbg("\t\t%s\n\t\t\t%s\n", id, value); + continue; + } + } + + return 0; +} + +/* Parse name and id of a front-end DAI (ie. cpu dai of a FE DAI link) */ +static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private) +{ + struct tplg_elem *elem = private; + struct snd_soc_tplg_pcm *pcm = elem->pcm; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *value = NULL; + unsigned long int id_val; + + snd_config_get_id(cfg, &id); + tplg_dbg("\t\tFE DAI %s:\n", id); + snd_strlcpy(pcm->dai_name, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + + /* get id */ + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &value) < 0) + continue; + errno = 0; + /* no support for negative value */ + id_val = strtoul(value, NULL, 0); + if ((errno == ERANGE && id_val == ULONG_MAX) + || (errno != 0 && id_val == 0) + || id_val > UINT_MAX) { + SNDERR("error: invalid fe dai ID\n"); + return -EINVAL; + } + + pcm->dai_id = (int) id_val; + tplg_dbg("\t\t\tindex: %d\n", pcm->dai_id); + } + } + + return 0; +} + +/* parse a flag bit of the given mask */ +static int parse_flag(snd_config_t *n, unsigned int mask_in, + unsigned int *mask, unsigned int *flags) +{ + int ret; + + ret = snd_config_get_bool(n); + if (ret < 0) + return ret; + + *mask |= mask_in; + if (ret) + *flags |= mask_in; + else + *flags &= ~mask_in; + + return 0; +} + +/* Parse PCM (for front end DAI & DAI link) in text conf file */ +int tplg_parse_pcm(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_pcm *pcm; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_PCM); + if (!elem) + return -ENOMEM; + + pcm = elem->pcm; + pcm->size = elem->size; + snd_strlcpy(pcm->pcm_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + tplg_dbg(" PCM: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + pcm->pcm_id = atoi(val); + tplg_dbg("\t%s: %d\n", id, pcm->pcm_id); + continue; + } + + if (strcmp(id, "pcm") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_streams, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "compress") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (strcmp(val, "true") == 0) + pcm->compress = 1; + + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "dai") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_fe_dai, elem); + if (err < 0) + return err; + continue; + } + + /* flags */ + if (strcmp(id, "symmetric_rates") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_channels") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_sample_bits") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS, + &pcm->flag_mask, &pcm->flags); + if (err < 0) + return err; + continue; + } + + /* private data */ + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + } + + return 0; +} + +/* Parse physical DAI */ +int tplg_parse_dai(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_dai *dai; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAI); + if (!elem) + return -ENOMEM; + + dai = elem->dai; + dai->size = elem->size; + snd_strlcpy(dai->dai_name, elem->id, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + tplg_dbg(" DAI: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + dai->dai_id = atoi(val); + tplg_dbg("\t%s: %d\n", id, dai->dai_id); + continue; + } + + if (strcmp(id, "playback") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + dai->playback = atoi(val); + tplg_dbg("\t%s: %d\n", id, dai->playback); + continue; + } + + + if (strcmp(id, "capture") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + dai->capture = atoi(val); + tplg_dbg("\t%s: %d\n", id, dai->capture); + continue; + } + + + /* stream capabilities */ + if (strcmp(id, "pcm") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_streams, elem); + if (err < 0) + return err; + continue; + } + + /* flags */ + if (strcmp(id, "symmetric_rates") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES, + &dai->flag_mask, &dai->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_channels") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS, + &dai->flag_mask, &dai->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_sample_bits") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS, + &dai->flag_mask, &dai->flags); + if (err < 0) + return err; + continue; + } + + /* private data */ + if (strcmp(id, "data") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + } + + return 0; +} + +/* parse physical link runtime supported HW configs in text conf file */ +static int parse_hw_config_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, + struct tplg_elem *elem) +{ + struct snd_soc_tplg_link_config *link = elem->link; + snd_config_type_t type; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + type = snd_config_get_type(cfg); + + /* refer to a single HW config */ + if (type == SND_CONFIG_TYPE_STRING) { + if (snd_config_get_string(cfg, &val) < 0) + return -EINVAL; + + link->num_hw_configs = 1; + return tplg_ref_add(elem, SND_TPLG_TYPE_HW_CONFIG, val); + } + + if (type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound type expected for %s", id); + return -EINVAL; + } + + /* refer to a list of HW configs */ + snd_config_for_each(i, next, cfg) { + const char *val; + int err; + + n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &val) < 0) + continue; + + if (link->num_hw_configs >= SND_SOC_TPLG_HW_CONFIG_MAX) { + SNDERR("error: exceed max hw configs for link %s", id); + return -EINVAL; + } + + link->num_hw_configs++; + err = tplg_ref_add(elem, SND_TPLG_TYPE_HW_CONFIG, val); + if (err < 0) + return err; + } + + return 0; +} + +/* Parse a physical link element in text conf file */ +int tplg_parse_link(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_link_config *link; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int err; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BE); + if (!elem) + return -ENOMEM; + + link = elem->link; + link->size = elem->size; + snd_strlcpy(link->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + tplg_dbg(" Link: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + link->id = atoi(val); + tplg_dbg("\t%s: %d\n", id, link->id); + continue; + } + + if (strcmp(id, "stream_name") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + snd_strlcpy(link->stream_name, val, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + tplg_dbg("\t%s: %s\n", id, val); + continue; + } + + if (strcmp(id, "hw_configs") == 0) { + err = parse_hw_config_refs(tplg, n, elem); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "default_hw_conf_id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + link->default_hw_config_id = atoi(val); + continue; + } + + /* flags */ + if (strcmp(id, "symmetric_rates") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_channels") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + if (strcmp(id, "symmetric_sample_bits") == 0) { + err = parse_flag(n, + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS, + &link->flag_mask, &link->flags); + if (err < 0) + return err; + continue; + } + + /* private data */ + if (strcmp(id, "data") == 0) { + err = tplg_parse_data_refs(n, elem); + if (err < 0) + return err; + continue; + } + } + + return 0; +} + +/* Parse cc */ +int tplg_parse_cc(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +{ + struct snd_soc_tplg_link_config *link; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_CC); + if (!elem) + return -ENOMEM; + + link = elem->link; + link->size = elem->size; + + tplg_dbg(" CC: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + link->id = atoi(val); + tplg_dbg("\t%s: %d\n", id, link->id); + continue; + } + + } + + return 0; +} + +static int get_audio_hw_format(const char *val) +{ + if (!strlen(val)) + return -EINVAL; + + if (!strcmp(val, "I2S")) + return SND_SOC_DAI_FORMAT_I2S; + + if (!strcmp(val, "RIGHT_J")) + return SND_SOC_DAI_FORMAT_RIGHT_J; + + if (!strcmp(val, "LEFT_J")) + return SND_SOC_DAI_FORMAT_LEFT_J; + + if (!strcmp(val, "DSP_A")) + return SND_SOC_DAI_FORMAT_DSP_A; + + if (!strcmp(val, "DSP_B")) + return SND_SOC_DAI_FORMAT_DSP_B; + + if (!strcmp(val, "AC97")) + return SND_SOC_DAI_FORMAT_AC97; + + if (!strcmp(val, "PDM")) + return SND_SOC_DAI_FORMAT_PDM; + + SNDERR("error: invalid audio HW format %s\n", val); + return -EINVAL; +} + +int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + + struct snd_soc_tplg_hw_config *hw_cfg; + struct tplg_elem *elem; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id, *val = NULL; + int ret; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG); + if (!elem) + return -ENOMEM; + + hw_cfg = elem->hw_cfg; + hw_cfg->size = elem->size; + + tplg_dbg(" Link HW config: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + + /* skip comments */ + if (strcmp(id, "comment") == 0) + continue; + if (id[0] == '#') + continue; + + if (strcmp(id, "id") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->id = atoi(val); + tplg_dbg("\t%s: %d\n", id, hw_cfg->id); + continue; + } + + if (strcmp(id, "format") == 0 || + strcmp(id, "fmt") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + ret = get_audio_hw_format(val); + if (ret < 0) + return ret; + hw_cfg->fmt = ret; + continue; + } + + if (strcmp(id, "bclk") == 0 || + strcmp(id, "bclk_master") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "master")) { + /* For backwards capability, + * "master" == "codec is slave" + */ + SNDERR("warning: deprecated bclk value '%s'\n", + val); + + hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; + } else if (!strcmp(val, "codec_slave")) { + hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; + } else if (!strcmp(val, "codec_master")) { + hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CM; + } + continue; + } + + if (strcmp(id, "bclk_freq") == 0 || + strcmp(id, "bclk_rate") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->bclk_rate = atoi(val); + continue; + } + + if (strcmp(id, "bclk_invert") == 0 || + strcmp(id, "invert_bclk") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "true")) + hw_cfg->invert_bclk = true; + continue; + } + + if (strcmp(id, "fsync") == 0 || + strcmp(id, "fsync_master") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "master")) { + /* For backwards capability, + * "master" == "codec is slave" + */ + SNDERR("warning: deprecated fsync value '%s'\n", + val); + + hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS; + } else if (!strcmp(val, "codec_slave")) { + hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS; + } else if (!strcmp(val, "codec_master")) { + hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CM; + } + continue; + } + + if (strcmp(id, "fsync_invert") == 0 || + strcmp(id, "invert_fsync") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "true")) + hw_cfg->invert_fsync = true; + continue; + } + + if (strcmp(id, "fsync_freq") == 0 || + strcmp(id, "fsync_rate") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->fsync_rate = atoi(val); + continue; + } + + if (strcmp(id, "mclk_freq") == 0 || + strcmp(id, "mclk_rate") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->mclk_rate = atoi(val); + continue; + } + + if (strcmp(id, "mclk") == 0 || + strcmp(id, "mclk_direction") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "master")) { + /* For backwards capability, + * "master" == "for codec, mclk is input" + */ + SNDERR("warning: deprecated mclk value '%s'\n", + val); + + hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CI; + } else if (!strcmp(val, "codec_mclk_in")) { + hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CI; + } else if (!strcmp(val, "codec_mclk_out")) { + hw_cfg->mclk_direction = SND_SOC_TPLG_MCLK_CO; + } + continue; + } + + if (strcmp(id, "pm_gate_clocks") == 0 || + strcmp(id, "clock_gated") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + if (!strcmp(val, "true")) + hw_cfg->clock_gated = + SND_SOC_TPLG_DAI_CLK_GATE_GATED; + else + hw_cfg->clock_gated = + SND_SOC_TPLG_DAI_CLK_GATE_CONT; + continue; + } + + if (strcmp(id, "tdm_slots") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tdm_slots = atoi(val); + continue; + } + + if (strcmp(id, "tdm_slot_width") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tdm_slot_width = atoi(val); + continue; + } + + if (strcmp(id, "tx_slots") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tx_slots = atoi(val); + continue; + } + + if (strcmp(id, "rx_slots") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->rx_slots = atoi(val); + continue; + } + + if (strcmp(id, "tx_channels") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->tx_channels = atoi(val); + continue; + } + + if (strcmp(id, "rx_channels") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + + hw_cfg->rx_channels = atoi(val); + continue; + } + + } + + return 0; +} + +/* copy stream object */ +static void tplg_add_stream_object(struct snd_soc_tplg_stream *strm, + struct snd_tplg_stream_template *strm_tpl) +{ + snd_strlcpy(strm->name, strm_tpl->name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + strm->format = strm_tpl->format; + strm->rate = strm_tpl->rate; + strm->period_bytes = strm_tpl->period_bytes; + strm->buffer_bytes = strm_tpl->buffer_bytes; + strm->channels = strm_tpl->channels; +} + +static void tplg_add_stream_caps(struct snd_soc_tplg_stream_caps *caps, + struct snd_tplg_stream_caps_template *caps_tpl) +{ + snd_strlcpy(caps->name, caps_tpl->name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + caps->formats = caps_tpl->formats; + caps->rates = caps_tpl->rates; + caps->rate_min = caps_tpl->rate_min; + caps->rate_max = caps_tpl->rate_max; + caps->channels_min = caps_tpl->channels_min; + caps->channels_max = caps_tpl->channels_max; + caps->periods_min = caps_tpl->periods_min; + caps->periods_max = caps_tpl->periods_max; + caps->period_size_min = caps_tpl->period_size_min; + caps->period_size_max = caps_tpl->period_size_max; + caps->buffer_size_min = caps_tpl->buffer_size_min; + caps->buffer_size_max = caps_tpl->buffer_size_max; + caps->sig_bits = caps_tpl->sig_bits; +} + +/* Add a PCM element (FE DAI & DAI link) from C API */ +int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_pcm_template *pcm_tpl = t->pcm; + struct snd_soc_tplg_pcm *pcm, *_pcm; + struct tplg_elem *elem; + int i; + + tplg_dbg("PCM: %s, DAI %s\n", pcm_tpl->pcm_name, pcm_tpl->dai_name); + + if (pcm_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) + return -EINVAL; + + elem = tplg_elem_new_common(tplg, NULL, pcm_tpl->pcm_name, + SND_TPLG_TYPE_PCM); + if (!elem) + return -ENOMEM; + + pcm = elem->pcm; + pcm->size = elem->size; + + snd_strlcpy(pcm->pcm_name, pcm_tpl->pcm_name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + snd_strlcpy(pcm->dai_name, pcm_tpl->dai_name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + pcm->pcm_id = pcm_tpl->pcm_id; + pcm->dai_id = pcm_tpl->dai_id; + pcm->playback = pcm_tpl->playback; + pcm->capture = pcm_tpl->capture; + pcm->compress = pcm_tpl->compress; + + for (i = 0; i < 2; i++) { + if (pcm_tpl->caps[i]) + tplg_add_stream_caps(&pcm->caps[i], pcm_tpl->caps[i]); + } + + pcm->flag_mask = pcm_tpl->flag_mask; + pcm->flags = pcm_tpl->flags; + + pcm->num_streams = pcm_tpl->num_streams; + for (i = 0; i < pcm_tpl->num_streams; i++) + tplg_add_stream_object(&pcm->stream[i], &pcm_tpl->stream[i]); + + /* private data */ + if (pcm_tpl->priv != NULL && pcm_tpl->priv->size) { + tplg_dbg("\t priv data size %d\n", pcm_tpl->priv->size); + _pcm = realloc(pcm, + elem->size + pcm_tpl->priv->size); + if (!_pcm) { + tplg_elem_free(elem); + return -ENOMEM; + } + + pcm = _pcm; + elem->pcm = pcm; + elem->size += pcm_tpl->priv->size; + + memcpy(pcm->priv.data, pcm_tpl->priv->data, + pcm_tpl->priv->size); + pcm->priv.size = pcm_tpl->priv->size; + } + + return 0; +} + +/* Set link HW config from C API template */ +static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg, + struct snd_tplg_hw_config_template *tpl) +{ + unsigned int i; + + cfg->size = sizeof(*cfg); + cfg->id = tpl->id; + + cfg->fmt = tpl->fmt; + cfg->clock_gated = tpl->clock_gated; + cfg->invert_bclk = tpl->invert_bclk; + cfg->invert_fsync = tpl->invert_fsync; + cfg->bclk_master = tpl->bclk_master; + cfg->fsync_master = tpl->fsync_master; + cfg->mclk_direction = tpl->mclk_direction; + cfg->reserved = tpl->reserved; + cfg->mclk_rate = tpl->mclk_rate; + cfg->bclk_rate = tpl->bclk_rate; + cfg->fsync_rate = tpl->fsync_rate; + + cfg->tdm_slots = tpl->tdm_slots; + cfg->tdm_slot_width = tpl->tdm_slot_width; + cfg->tx_slots = tpl->tx_slots; + cfg->rx_slots = tpl->rx_slots; + + if (cfg->tx_channels > SND_SOC_TPLG_MAX_CHAN + || cfg->rx_channels > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + cfg->tx_channels = tpl->tx_channels; + for (i = 0; i < cfg->tx_channels; i++) + cfg->tx_chanmap[i] = tpl->tx_chanmap[i]; + + cfg->rx_channels = tpl->rx_channels; + for (i = 0; i < cfg->rx_channels; i++) + cfg->rx_chanmap[i] = tpl->rx_chanmap[i]; + + return 0; +} + +/* Add a physical DAI link element from C API */ +int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_link_template *link_tpl = t->link; + struct snd_soc_tplg_link_config *link, *_link; + struct tplg_elem *elem; + unsigned int i; + + if (t->type != SND_TPLG_TYPE_LINK && t->type != SND_TPLG_TYPE_BE + && t->type != SND_TPLG_TYPE_CC) + return -EINVAL; + + elem = tplg_elem_new_common(tplg, NULL, link_tpl->name, t->type); + if (!elem) + return -ENOMEM; + + tplg_dbg("Link: %s", link_tpl->name); + + link = elem->link; + link->size = elem->size; + + /* ID and names */ + link->id = link_tpl->id; + snd_strlcpy(link->name, link_tpl->name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + snd_strlcpy(link->stream_name, link_tpl->stream_name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + /* stream configs */ + if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) + return -EINVAL; + link->num_streams = link_tpl->num_streams; + for (i = 0; i < link->num_streams; i++) + tplg_add_stream_object(&link->stream[i], &link_tpl->stream[i]); + + /* HW configs */ + if (link_tpl->num_hw_configs > SND_SOC_TPLG_HW_CONFIG_MAX) + return -EINVAL; + link->num_hw_configs = link_tpl->num_hw_configs; + link->default_hw_config_id = link_tpl->default_hw_config_id; + for (i = 0; i < link->num_hw_configs; i++) + set_link_hw_config(&link->hw_config[i], &link_tpl->hw_config[i]); + + /* flags */ + link->flag_mask = link_tpl->flag_mask; + link->flags = link_tpl->flags; + + /* private data */ + if (link_tpl->priv != NULL && link_tpl->priv->size) { + _link = realloc(link, + elem->size + link_tpl->priv->size); + if (!_link) { + tplg_elem_free(elem); + return -ENOMEM; + } + + link = _link; + elem->link = link; + elem->size += link_tpl->priv->size; + + memcpy(link->priv.data, link_tpl->priv->data, + link_tpl->priv->size); + link->priv.size = link_tpl->priv->size; + } + + return 0; +} + +int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_dai_template *dai_tpl = t->dai; + struct snd_soc_tplg_dai *dai, *_dai; + struct tplg_elem *elem; + int i; + + tplg_dbg("DAI %s\n", dai_tpl->dai_name); + + elem = tplg_elem_new_common(tplg, NULL, dai_tpl->dai_name, + SND_TPLG_TYPE_DAI); + if (!elem) + return -ENOMEM; + + dai = elem->dai; + dai->size = elem->size; + + snd_strlcpy(dai->dai_name, dai_tpl->dai_name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + dai->dai_id = dai_tpl->dai_id; + + /* stream caps */ + dai->playback = dai_tpl->playback; + dai->capture = dai_tpl->capture; + + for (i = 0; i < 2; i++) { + if (dai_tpl->caps[i]) + tplg_add_stream_caps(&dai->caps[i], dai_tpl->caps[i]); + } + + /* flags */ + dai->flag_mask = dai_tpl->flag_mask; + dai->flags = dai_tpl->flags; + + /* private data */ + if (dai_tpl->priv != NULL) { + _dai = realloc(dai, + elem->size + dai_tpl->priv->size); + if (!_dai) { + tplg_elem_free(elem); + return -ENOMEM; + } + + dai = _dai; + dai->priv.size = dai_tpl->priv->size; + + elem->dai = dai; + elem->size += dai->priv.size; + memcpy(dai->priv.data, dai_tpl->priv->data, + dai->priv.size); + } + + return 0; +} diff --git a/src/topology/text.c b/src/topology/text.c new file mode 100644 index 0000000..72647fe --- /dev/null +++ b/src/topology/text.c @@ -0,0 +1,91 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + 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. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood + +*/ + +#include "list.h" +#include "tplg_local.h" + +#define TEXT_SIZE_MAX \ + (SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + +static int parse_text_values(snd_config_t *cfg, struct tplg_elem *elem) +{ + struct tplg_texts *texts = elem->texts; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *value = NULL; + int j = 0; + + tplg_dbg(" Text Values: %s\n", elem->id); + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + if (j == SND_SOC_TPLG_NUM_TEXTS) { + tplg_dbg("error: text string number exceeds %d\n", j); + return -ENOMEM; + } + + /* get value */ + if (snd_config_get_string(n, &value) < 0) + continue; + + snd_strlcpy(&texts->items[j][0], value, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + tplg_dbg("\t%s\n", &texts->items[j][0]); + + j++; + } + + texts->num_items = j; + return 0; +} + +/* Parse Text data */ +int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + int err = 0; + struct tplg_elem *elem; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TEXT); + if (!elem) + return -ENOMEM; + + 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, "values") == 0) { + err = parse_text_values(n, elem); + if (err < 0) { + SNDERR("error: failed to parse text values"); + return err; + } + continue; + } + } + + return err; +} diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h new file mode 100644 index 0000000..c32267d --- /dev/null +++ b/src/topology/tplg_local.h @@ -0,0 +1,316 @@ +/* + * 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. + */ + +#include +#include +#include + +#include "local.h" +#include "list.h" +#include "topology.h" + +#define __packed __attribute__((__packed__)) + +#include +#include +#include + +#ifdef TPLG_DEBUG +#define tplg_dbg SNDERR +#else +#define tplg_dbg(fmt, arg...) do { } while (0) +#endif + +#define MAX_FILE 256 +#define TPLG_MAX_PRIV_SIZE (1024 * 128) + +/** The name of the environment variable containing the tplg directory */ +#define ALSA_CONFIG_TPLG_VAR "ALSA_CONFIG_TPLG" + +struct tplg_ref; +struct tplg_elem; + +typedef enum _snd_pcm_rates { + SND_PCM_RATE_UNKNOWN = -1, + SND_PCM_RATE_5512 = 0, + SND_PCM_RATE_8000, + SND_PCM_RATE_11025, + SND_PCM_RATE_16000, + SND_PCM_RATE_22050, + SND_PCM_RATE_32000, + SND_PCM_RATE_44100, + SND_PCM_RATE_48000, + SND_PCM_RATE_64000, + SND_PCM_RATE_88200, + SND_PCM_RATE_96000, + SND_PCM_RATE_176400, + SND_PCM_RATE_192000, + SND_PCM_RATE_CONTINUOUS = 30, + SND_PCM_RATE_KNOT = 31, + SND_PCM_RATE_LAST = SND_PCM_RATE_KNOT, +} snd_pcm_rates_t; + +struct snd_tplg { + + /* opaque vendor data */ + int vendor_fd; + char *vendor_name; + + /* out file */ + int out_fd; + + int verbose; + unsigned int version; + + /* runtime state */ + unsigned int next_hdr_pos; + int index; + int channel_idx; + + /* manifest */ + struct snd_soc_tplg_manifest manifest; + void *manifest_pdata; /* copied by builder at file write */ + + /* list of each element type */ + struct list_head tlv_list; + struct list_head widget_list; + struct list_head pcm_list; + struct list_head dai_list; + struct list_head be_list; + struct list_head cc_list; + struct list_head route_list; + struct list_head text_list; + struct list_head pdata_list; + struct list_head token_list; + struct list_head tuple_list; + struct list_head manifest_list; + struct list_head pcm_config_list; + struct list_head pcm_caps_list; + struct list_head hw_cfg_list; + + /* type-specific control lists */ + struct list_head mixer_list; + struct list_head enum_list; + struct list_head bytes_ext_list; +}; + +/* object text references */ +struct tplg_ref { + unsigned int type; + struct tplg_elem *elem; + char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + struct list_head list; +}; + +struct tplg_texts { + unsigned int num_items; + char items[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +}; + +/* element for vendor tokens */ +struct tplg_token { + char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + unsigned int value; +}; + +struct tplg_vendor_tokens { + unsigned int num_tokens; + struct tplg_token token[0]; +}; + +/* element for vendor tuples */ +struct tplg_tuple { + char token[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + union { + char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + unsigned char uuid[16]; + unsigned int value; + }; +}; + +struct tplg_tuple_set { + unsigned int type; /* uuid, bool, byte, short, word, string*/ + unsigned int num_tuples; + struct tplg_tuple tuple[0]; +}; + +struct tplg_vendor_tuples { + unsigned int num_sets; + struct tplg_tuple_set **set; +}; + +/* topology element */ +struct tplg_elem { + + char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + int index; + enum snd_tplg_type type; + + int size; /* total size of this object inc pdata and ref objects */ + int compound_elem; /* dont write this element as individual elem */ + int vendor_type; /* vendor type for private data */ + + /* UAPI object for this elem */ + union { + void *obj; + struct snd_soc_tplg_mixer_control *mixer_ctrl; + struct snd_soc_tplg_enum_control *enum_ctrl; + struct snd_soc_tplg_bytes_control *bytes_ext; + struct snd_soc_tplg_dapm_widget *widget; + struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_dai *dai; + struct snd_soc_tplg_link_config *link;/* physical link */ + struct snd_soc_tplg_dapm_graph_elem *route; + struct snd_soc_tplg_stream *stream_cfg; + struct snd_soc_tplg_stream_caps *stream_caps; + struct snd_soc_tplg_hw_config *hw_cfg; + + /* these do not map to UAPI structs but are internal only */ + struct snd_soc_tplg_ctl_tlv *tlv; + struct tplg_texts *texts; + struct snd_soc_tplg_private *data; + struct tplg_vendor_tokens *tokens; + struct tplg_vendor_tuples *tuples; + struct snd_soc_tplg_manifest *manifest; + }; + + /* an element may refer to other elements: + * a mixer control may refer to a tlv, + * a widget may refer to a mixer control array, + * a graph may refer to some widgets. + */ + struct list_head ref_list; + struct list_head list; /* list of all elements with same type */ + + void (*free)(void *obj); +}; + +struct map_elem { + const char *name; + int id; +}; + +int tplg_parse_compound(snd_tplg_t *tplg, snd_config_t *cfg, + int (*fcn)(snd_tplg_t *, snd_config_t *, void *), + void *private); + +int tplg_write_data(snd_tplg_t *tplg); + +int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +void tplg_free_tuples(void *obj); + +int tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_control_bytes(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_control_mixer(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_dapm_widget(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_stream_caps(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_pcm(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_parse_link(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_cc(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED); + +int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + void *private ATTRIBUTE_UNUSED); + +int tplg_build_data(snd_tplg_t *tplg); +int tplg_build_manifest_data(snd_tplg_t *tplg); +int tplg_build_controls(snd_tplg_t *tplg); +int tplg_build_widgets(snd_tplg_t *tplg); +int tplg_build_routes(snd_tplg_t *tplg); +int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type); + +int tplg_copy_data(snd_tplg_t *tplg, struct tplg_elem *elem, + struct tplg_ref *ref); + +int tplg_parse_data_refs(snd_config_t *cfg, struct tplg_elem *elem); + +int tplg_ref_add(struct tplg_elem *elem, int type, const char* id); +int tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref); + +struct tplg_elem *tplg_elem_new(void); +void tplg_elem_free(struct tplg_elem *elem); +void tplg_elem_free_list(struct list_head *base); +struct tplg_elem *tplg_elem_lookup(struct list_head *base, + const char* id, + unsigned int type, + int index); +struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, + snd_config_t *cfg, const char *name, enum snd_tplg_type type); + +int tplg_parse_channel(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private); + +int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private); +int tplg_parse_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, void *private); + +struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, + const char* id); + +int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_graph_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); + +int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer, + struct tplg_elem **e); +int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl, + struct tplg_elem **e); +int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl, + struct tplg_elem **e); + +int tplg_build_pcms(snd_tplg_t *tplg, unsigned int type); +int tplg_build_dais(snd_tplg_t *tplg, unsigned int type); +int tplg_build_links(snd_tplg_t *tplg, unsigned int type); +int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); diff --git a/src/ucm/Makefile.am b/src/ucm/Makefile.am new file mode 100644 index 0000000..41a679c --- /dev/null +++ b/src/ucm/Makefile.am @@ -0,0 +1,10 @@ +EXTRA_LTLIBRARIES = libucm.la + +libucm_la_SOURCES = utils.c parser.c ucm_cond.c ucm_subs.c main.c + +noinst_HEADERS = ucm_local.h + +all: libucm.la + + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/src/ucm/Makefile.in b/src/ucm/Makefile.in new file mode 100644 index 0000000..9de5377 --- /dev/null +++ b/src/ucm/Makefile.in @@ -0,0 +1,616 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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 ucm_cond.lo ucm_subs.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 +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/main.Plo ./$(DEPDIR)/parser.Plo \ + ./$(DEPDIR)/ucm_cond.Plo ./$(DEPDIR)/ucm_subs.Plo \ + ./$(DEPDIR)/utils.Plo +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_CC_1 = +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_CCLD_1 = +SOURCES = $(libucm_la_SOURCES) +DIST_SOURCES = $(libucm_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 ucm_cond.c ucm_subs.c main.c +noinst_HEADERS = ucm_local.h +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucm_cond.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucm_subs.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 -f ./$(DEPDIR)/main.Plo + -rm -f ./$(DEPDIR)/parser.Plo + -rm -f ./$(DEPDIR)/ucm_cond.Plo + -rm -f ./$(DEPDIR)/ucm_subs.Plo + -rm -f ./$(DEPDIR)/utils.Plo + -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 -f ./$(DEPDIR)/main.Plo + -rm -f ./$(DEPDIR)/parser.Plo + -rm -f ./$(DEPDIR)/ucm_cond.Plo + -rm -f ./$(DEPDIR)/ucm_subs.Plo + -rm -f ./$(DEPDIR)/utils.Plo + -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 TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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 tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +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/main.c b/src/ucm/main.c new file mode 100644 index 0000000..b0b6ffb --- /dev/null +++ b/src/ucm/main.c @@ -0,0 +1,1970 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 +#include +#include +#include + +/* + * misc + */ + +static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, + struct list_head *value_list, const char *identifier); +static int get_value3(snd_use_case_mgr_t *uc_mgr, + char **value, + const char *identifier, + struct list_head *value_list1, + struct list_head *value_list2, + struct list_head *value_list3); + +static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, + struct component_sequence *cmpt_seq, + struct list_head *value_list1, + struct list_head *value_list2, + struct list_head *value_list3, + char *cdev); + +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 read_tlv_file(unsigned int **res, + const char *filepath) +{ + int err = 0; + int fd; + struct stat st; + size_t sz; + ssize_t sz_read; + struct snd_ctl_tlv *tlv; + + fd = open(filepath, O_RDONLY); + if (fd < 0) { + err = -errno; + return err; + } + if (fstat(fd, &st) == -1) { + err = -errno; + goto __fail; + } + sz = st.st_size; + if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) { + uc_error("File size should be less than 16 MB " + "and multiple of 4"); + err = -EINVAL; + goto __fail; + } + *res = malloc(sz); + if (res == NULL) { + err = -ENOMEM; + goto __fail; + } + sz_read = read(fd, *res, sz); + if (sz_read < 0 || (size_t)sz_read != sz) { + err = -EIO; + free(*res); + *res = NULL; + } + /* Check if the tlv file specifies valid size. */ + tlv = (struct snd_ctl_tlv *)(*res); + if (tlv->length + 2 * sizeof(unsigned int) != sz) { + uc_error("Invalid tlv size: %d", tlv->length); + err = -EINVAL; + free(*res); + *res = NULL; + } + +__fail: + close(fd); + return err; +} + +static int binary_file_parse(snd_ctl_elem_value_t *dst, + snd_ctl_elem_info_t *info, + const char *filepath) +{ + int err = 0; + int fd; + struct stat st; + size_t sz; + ssize_t sz_read; + char *res; + snd_ctl_elem_type_t type; + unsigned int idx, count; + + type = snd_ctl_elem_info_get_type(info); + if (type != SND_CTL_ELEM_TYPE_BYTES) { + uc_error("only support byte type!"); + err = -EINVAL; + return err; + } + fd = open(filepath, O_RDONLY); + if (fd < 0) { + err = -errno; + return err; + } + if (stat(filepath, &st) == -1) { + err = -errno; + goto __fail; + } + sz = st.st_size; + count = snd_ctl_elem_info_get_count(info); + if (sz != count || sz > sizeof(dst->value.bytes)) { + uc_error("invalid parameter size %d!", sz); + err = -EINVAL; + goto __fail; + } + res = malloc(sz); + if (res == NULL) { + err = -ENOMEM; + goto __fail; + } + sz_read = read(fd, res, sz); + if (sz_read < 0 || (size_t)sz_read != sz) { + err = -errno; + goto __fail_read; + } + for (idx = 0; idx < sz; idx++) + snd_ctl_elem_value_set_byte(dst, idx, *(res + idx)); + __fail_read: + free(res); + __fail: + close(fd); + return err; +} + +extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, + const char *str, + const char **ret_ptr); + +static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) +{ + const char *pos; + int err; + snd_ctl_elem_id_t *id; + snd_ctl_elem_value_t *value; + snd_ctl_elem_info_t *info; + unsigned int *res = NULL; + + snd_ctl_elem_id_malloc(&id); + snd_ctl_elem_value_malloc(&value); + snd_ctl_elem_info_malloc(&info); + + err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); + if (err < 0) + goto __fail; + while (*pos && isspace(*pos)) + pos++; + if (!*pos) { + uc_error("undefined value for cset >%s<", cset); + err = -EINVAL; + goto __fail; + } + snd_ctl_elem_info_set_id(info, id); + err = snd_ctl_elem_info(ctl, info); + if (err < 0) + goto __fail; + if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) { + if (!snd_ctl_elem_info_is_tlv_writable(info)) { + err = -EINVAL; + goto __fail; + } + err = read_tlv_file(&res, pos); + if (err < 0) + goto __fail; + err = snd_ctl_elem_tlv_write(ctl, id, res); + if (err < 0) + goto __fail; + } else { + snd_ctl_elem_value_set_id(value, id); + err = snd_ctl_elem_read(ctl, value); + if (err < 0) + goto __fail; + if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE) + err = binary_file_parse(value, info, pos); + else + err = snd_ctl_ascii_value_parse(ctl, value, info, pos); + if (err < 0) + goto __fail; + err = snd_ctl_elem_write(ctl, value); + if (err < 0) + goto __fail; + } + err = 0; + __fail: + if (id != NULL) + free(id); + if (value != NULL) + free(value); + if (info != NULL) + free(info); + if (res != NULL) + free(res); + + 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: + case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE: + case SEQUENCE_ELEMENT_TYPE_CSET_TLV: + if (cdev == NULL && uc_mgr->in_component_domain) { + /* For sequence of a component device, use + * its parent's cdev stored by ucm manager. + */ + if (uc_mgr->cdev == NULL) { + uc_error("cdev is not defined!"); + return err; + } + + cdev = strndup(uc_mgr->cdev, PATH_MAX); + if (!cdev) + return -ENOMEM; + } else if (cdev == NULL) { + char *playback_ctl = NULL; + char *capture_ctl = NULL; + + err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL", + value_list1, + value_list2, + value_list3); + if (err < 0 && err != -ENOENT) { + uc_error("cdev is not defined!"); + return err; + } + err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL", + value_list1, + value_list2, + value_list3); + if (err < 0 && err != -ENOENT) { + free(playback_ctl); + uc_error("cdev is not defined!"); + return err; + } + if (playback_ctl == NULL && + capture_ctl == NULL) { + uc_error("cdev is not defined!"); + return -EINVAL; + } + if (playback_ctl != NULL && + capture_ctl != NULL && + strcmp(playback_ctl, capture_ctl) != 0) { + free(playback_ctl); + free(capture_ctl); + uc_error("cdev is not equal for playback and capture!"); + return -EINVAL; + } + if (playback_ctl != NULL) { + cdev = playback_ctl; + free(capture_ctl); + } else { + cdev = capture_ctl; + } + } + if (ctl == NULL) { + err = uc_mgr_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, s->type); + if (err < 0) { + uc_error("unable to execute cset '%s'", 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; + case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ: + /* Execute enable or disable sequence of a component + * device. Pass the cdev defined by the machine device. + */ + err = execute_component_seq(uc_mgr, + &s->data.cmpt_seq, + value_list1, + value_list2, + value_list3, + cdev); + 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; + +} + +/* Execute enable or disable sequence of a component device. + * + * For a component device (a codec or embedded DSP), its sequence doesn't + * specify the sound card device 'cdev', because a component can be reused + * by different sound cards (machines). So when executing its sequence, a + * parameter 'cdev' is used to pass cdev defined by the sequence of its + * parent, the machine device. UCM manger will store the cdev when entering + * the component domain. + */ +static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, + struct component_sequence *cmpt_seq, + struct list_head *value_list1 ATTRIBUTE_UNUSED, + struct list_head *value_list2 ATTRIBUTE_UNUSED, + struct list_head *value_list3 ATTRIBUTE_UNUSED, + char *cdev) +{ + struct use_case_device *device = cmpt_seq->device; + struct list_head *seq; + int err; + + /* enter component domain and store cdev for the component */ + uc_mgr->in_component_domain = 1; + uc_mgr->cdev = cdev; + + /* choose enable or disable sequence of the component device */ + if (cmpt_seq->enable) + seq = &device->enable_list; + else + seq = &device->disable_list; + + /* excecute the sequence of the component dev */ + err = execute_sequence(uc_mgr, seq, + &device->value_list, + &uc_mgr->active_verb->value_list, + &uc_mgr->value_list); + + /* exit component domain and clear cdev */ + uc_mgr->in_component_domain = 0; + uc_mgr->cdev = NULL; + + return err; +} + +static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value) +{ + char *s; + int err; + + err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key); + if (err == -ENOENT) { + s = strdup(value); + if (s == NULL) + return -ENOMEM; + return uc_mgr_add_value(&uc_mgr->value_list, key, s); + } else if (err < 0) { + return err; + } + free(value); + return 0; +} + +static int add_auto_values(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + const char *id; + char buf[40]; + int err; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list) { + id = snd_ctl_card_info_get_id(ctl_list->ctl_info); + snprintf(buf, sizeof(buf), "hw:%s", id); + err = add_auto_value(uc_mgr, "PlaybackCTL", buf); + if (err < 0) + return err; + err = add_auto_value(uc_mgr, "CaptureCTL", buf); + if (err < 0) + return err; + } + return 0; +} + +/** + * \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 = add_auto_values(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) { + *result = NULL; + 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) { + *result = NULL; + 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; +} + +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 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 (modifier_status(uc_mgr, modifier->name) == enable) + return 0; + + 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 (device_status(uc_mgr, device->name) == enable) + return 0; + + 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 **uc_mgr, + const char *card_name) +{ + snd_use_case_mgr_t *mgr; + int err; + + /* create a new UCM */ + mgr = calloc(1, sizeof(snd_use_case_mgr_t)); + if (mgr == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&mgr->verb_list); + INIT_LIST_HEAD(&mgr->default_list); + INIT_LIST_HEAD(&mgr->value_list); + INIT_LIST_HEAD(&mgr->active_modifiers); + INIT_LIST_HEAD(&mgr->active_devices); + INIT_LIST_HEAD(&mgr->ctl_list); + pthread_mutex_init(&mgr->mutex, NULL); + + mgr->card_name = strdup(card_name); + if (mgr->card_name == NULL) { + free(mgr); + return -ENOMEM; + } + + /* get info on use_cases and verify against card */ + err = import_master_config(mgr); + if (err < 0) { + uc_error("error: failed to import %s use case configuration %d", + card_name, err); + goto err; + } + + *uc_mgr = mgr; + return 0; + +err: + uc_mgr_free(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"); + 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); +} + +#ifndef DOC_HIDDEN +struct myvalue { + struct list_head list; + char *value; +}; +#endif + +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(snd_use_case_mgr_t *uc_mgr, 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)) { + if (uc_mgr->conf_format < 2) { + *value = strdup(val->data); + if (*value == NULL) + return -ENOMEM; + return 0; + } + return uc_mgr_get_substituted_value(uc_mgr, value, val->data); + } + } + return -ENOENT; +} + +static int get_value3(snd_use_case_mgr_t *uc_mgr, + 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(uc_mgr, value, value_list1, identifier); + if (err >= 0 || err != -ENOENT) + return err; + err = get_value1(uc_mgr, value, value_list2, identifier); + if (err >= 0 || err != -ENOENT) + return err; + err = get_value1(uc_mgr, 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, + 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(uc_mgr, 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(uc_mgr, value, + &dev->value_list, + identifier); + if (err >= 0 || err != -ENOENT) + return err; + } + + if (exact) + return -ENOENT; + } + + err = get_value1(uc_mgr, value, &verb->value_list, identifier); + if (err >= 0 || err != -ENOENT) + return err; + } + + if (exact) + return -ENOENT; + } + + err = get_value1(uc_mgr, 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 (strcmp(identifier, "_file") == 0) { + /* get the conf file name of the opened card */ + if ((uc_mgr->card_name == NULL) + || (uc_mgr->conf_file_name[0] == '\0')) { + err = -ENOENT; + goto __end; + } + *value = strndup(uc_mgr->conf_file_name, MAX_FILE); + 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, (char **)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; +} + + +/** + * \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")) { + if (!str) { + err = -EINVAL; + goto __end; + } + err = device_status(uc_mgr, str); + if (err >= 0) { + *value = err; + err = 0; + } + } else if (check_identifier(identifier, "_modstatus")) { + if (!str) { + err = -EINVAL; + goto __end; + } + 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 = 0; + + 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 = 0; + + 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 { + err = -EINVAL; + goto __end; + } + 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; +} + +/** + * \brief Parse control element identifier + * \param elem_id Element identifier + * \param ucm_id Use case identifier + * \param value String value to be parsed + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst, + const char *ucm_id, + const char *value) +{ + snd_ctl_elem_iface_t iface; + int jack_control; + + jack_control = strcmp(ucm_id, "JackControl") == 0; + if (!jack_control && + strcmp(ucm_id, "PlaybackVolume") && + strcmp(ucm_id, "PlaybackSwitch") && + strcmp(ucm_id, "CaptureVolume") && + strcmp(ucm_id, "CaptureSwitch")) + return -EINVAL; + snd_ctl_elem_id_clear(dst); + if (strcasestr(ucm_id, "name=")) + return __snd_ctl_ascii_elem_id_parse(dst, value, NULL); + iface = SND_CTL_ELEM_IFACE_MIXER; + if (jack_control) + iface = SND_CTL_ELEM_IFACE_CARD; + snd_ctl_elem_id_set_interface(dst, iface); + snd_ctl_elem_id_set_name(dst, value); + return 0; +} + +/** + * \brief Parse mixer element identifier + * \param dst Simple mixer element identifier + * \param ucm_id Use case identifier + * \param value String value to be parsed + * \return Zero if success, otherwise a negative error code + */ +int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, + const char *ucm_id, + const char *value) +{ + if (strcmp(ucm_id, "PlaybackMixerId") == 0 || + strcmp(ucm_id, "CaptureMixerId") == 0) + return snd_mixer_selem_id_parse(dst, value); + return -EINVAL; +} diff --git a/src/ucm/parser.c b/src/ucm/parser.c new file mode 100644 index 0000000..ba50027 --- /dev/null +++ b/src/ucm/parser.c @@ -0,0 +1,1839 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 + +/* Directories to store UCM configuration files for components, like + * off-soc codecs or embedded DSPs. Components can define their own + * devices and sequences, to be reused by sound cards/machines. UCM + * manager should not scan these component directories. + * Machine use case files can include component configratuation files + * via alsaconf syntax: + * and . + * Alsaconf will import the included files automatically. After including + * a component file, a machine device's sequence can enable or disable + * a component device via syntax: + * enadev "component_device_name" + * disdev "component_device_name" + */ +static const char * const component_dir[] = { + "codecs", /* for off-soc codecs */ + "dsps", /* for DSPs embedded in SoC */ + "platforms", /* for common platform implementations */ + NULL, /* terminator */ +}; + +static int filename_filter(const struct dirent *dirent); +static int is_component_directory(const char *dir); + +static int parse_sequence(snd_use_case_mgr_t *uc_mgr, + struct list_head *base, + snd_config_t *cfg); + +/* + * compose configuration file + */ +static void configuration_filename2(char *fn, size_t fn_len, int format, + const char *dir, const char *file, + const char *suffix) +{ + snprintf(fn, fn_len, "%s/ucm%s/%s/%s%s", + snd_config_topdir(), format >= 2 ? "2" : "", + dir, file, suffix); +} + +static void configuration_filename(snd_use_case_mgr_t *uc_mgr, + char *fn, size_t fn_len, + const char *dir, const char *file, + const char *suffix) +{ + const char *env; + + if (uc_mgr->conf_format > 0) { + /* known format */ + env = getenv(uc_mgr->conf_format >= 2 ? ALSA_CONFIG_UCM2_VAR : + ALSA_CONFIG_UCM_VAR); + } else { + /* auto-detect */ + env = getenv(ALSA_CONFIG_UCM2_VAR); + if (env == NULL) { + env = getenv(ALSA_CONFIG_UCM_VAR); + } else { + uc_mgr->conf_format = 2; + } + } + if (env) { + snprintf(fn, fn_len, "%s/%s/%s%s", env, dir, file, suffix); + return; + } + + if (uc_mgr->conf_format > 0) { + configuration_filename2(fn, fn_len, uc_mgr->conf_format, + dir, file, suffix); + return; + } + + configuration_filename2(fn, fn_len, 2, dir, file, suffix); + if (access(fn, R_OK) == 0) { + /* Found an ucm2 file, only look in the ucm2 dir from now on */ + uc_mgr->conf_format = 2; + return; + } + + configuration_filename2(fn, fn_len, 0, dir, file, suffix); + if (access(fn, R_OK) == 0) { + /* Found an ucm1 file, only look in the ucm dir from now on */ + uc_mgr->conf_format = 1; + return; + } + + /* make sure that the error message refers to the new path */ + configuration_filename2(fn, fn_len, 2, dir, file, suffix); +} + +/* + * 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; +} + +/* + * Evaluate condition (in-place) + */ +static int evaluate_condition(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cfg) +{ + snd_config_t *n; + int err; + + err = snd_config_search(cfg, "If", &n); + if (err == -ENOENT) + return 0; + if (err < 0) + return err; + + err = uc_mgr_evaluate_condition(uc_mgr, cfg, n); + snd_config_delete(n); + return err; +} + +/* + * 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; +} + +/* Find a component device by its name, and remove it from machine device + * list. + * + * Component devices are defined by machine components (usually off-soc + * codes or DSP embeded in SoC). Since alsaconf imports their configuration + * files automatically, we don't know which devices are component devices + * until they are referenced by a machine device sequence. So here when we + * find a referenced device, we move it from the machine device list to the + * component device list. Component devices will not be exposed to applications + * by the original API to list devices for backward compatibility. So sound + * servers can only see the machine devices. + */ +struct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr, + const char *name) +{ + struct list_head *pos, *posdev, *_posdev; + struct use_case_verb *verb; + struct use_case_device *dev; + + list_for_each(pos, &uc_mgr->verb_list) { + verb = list_entry(pos, struct use_case_verb, list); + + /* search in the component device list */ + list_for_each(posdev, &verb->cmpt_device_list) { + dev = list_entry(posdev, struct use_case_device, list); + if (!strcmp(dev->name, name)) + return dev; + } + + /* search the machine device list */ + list_for_each_safe(posdev, _posdev, &verb->device_list) { + dev = list_entry(posdev, struct use_case_device, list); + if (!strcmp(dev->name, name)) { + /* find the component device, move it from the + * machine device list to the component device + * list. + */ + list_del(&dev->list); + list_add_tail(&dev->list, + &verb->cmpt_device_list); + return dev; + } + } + } + + return NULL; +} + +/* parse sequence of a component device + * + * This function will find the component device and mark if its enable or + * disable sequence is needed by its parenet device. + */ +static int parse_component_seq(snd_use_case_mgr_t *uc_mgr, + snd_config_t *n, int enable, + struct component_sequence *cmpt_seq) +{ + const char *val; + int err; + + err = snd_config_get_string(n, &val); + if (err < 0) + return err; + + cmpt_seq->device = find_component_dev(uc_mgr, val); + if (!cmpt_seq->device) { + uc_error("error: Cannot find component device %s", val); + return -EINVAL; + } + + /* Parent needs its enable or disable sequence */ + cmpt_seq->enable = enable; + + 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" + * enadev "component device name" + * disdev "component device name" + * + * e.g. + * cset "name='Master Playback Switch' 0,0" + * cset "iface=PCM,name='Disable HDMI',index=1 0" + * enadev "rt286:Headphones" + * disdev "rt286:Speaker" + */ +static int parse_sequence(snd_use_case_mgr_t *uc_mgr, + 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, "enadev") == 0) { + /* need to enable a component device */ + curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ; + err = parse_component_seq(uc_mgr, n, 1, + &curr->data.cmpt_seq); + if (err < 0) { + uc_error("error: enadev requires a valid device!"); + return err; + } + continue; + } + + if (strcmp(cmd, "disdev") == 0) { + /* need to disable a component device */ + curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ; + err = parse_component_seq(uc_mgr, n, 0, + &curr->data.cmpt_seq); + if (err < 0) { + uc_error("error: disdev requires a valid device!"); + return err; + } + continue; + } + + if (strcmp(cmd, "cset-bin-file") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE; + err = parse_string(n, &curr->data.cset); + if (err < 0) { + uc_error("error: cset-bin-file requires a string!"); + return err; + } + continue; + } + + if (strcmp(cmd, "cset-tlv") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV; + err = parse_string(n, &curr->data.cset); + if (err < 0) { + uc_error("error: cset-tlv 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; +} + +/* + * + */ +int uc_mgr_add_value(struct list_head *base, const char *key, char *val) +{ + struct ucm_value *curr; + + curr = calloc(1, sizeof(struct ucm_value)); + if (curr == NULL) + return -ENOMEM; + curr->name = strdup(key); + if (curr->name == NULL) { + free(curr); + return -ENOMEM; + } + list_add_tail(&curr->list, base); + curr->data = val; + 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) +{ + snd_config_iterator_t i, next; + snd_config_t *n; + char *s; + 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; + } + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + return err; + + 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; + + type = snd_config_get_type(n); + switch (type) { + case SND_CONFIG_TYPE_INTEGER: + case SND_CONFIG_TYPE_INTEGER64: + case SND_CONFIG_TYPE_REAL: + err = snd_config_get_ascii(n, &s); + if (err < 0) { + uc_error("error: unable to parse value for id '%s': %s!", id, snd_strerror(err)); + return err; + } + break; + case SND_CONFIG_TYPE_STRING: + err = parse_string(n, &s); + 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 '%s'", type, id); + return -EINVAL; + } + err = uc_mgr_add_value(base, id, s); + if (err < 0) { + free(s); + return err; + } + } + + 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); + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + return err; + + 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); + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + return err; + + 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; + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + return 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]; + 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->cmpt_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 */ + configuration_filename(uc_mgr, filename, sizeof(filename), + uc_mgr->conf_file_name, file, ""); + err = uc_mgr_config_load(uc_mgr->conf_format, filename, &cfg); + if (err < 0) { + uc_error("error: failed to open verb file %s : %d", + filename, -errno); + return err; + } + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + 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); + goto _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); + goto _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); + goto _err; + } + continue; + } + } + + snd_config_delete(cfg); + + /* 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; + + _err: + snd_config_delete(cfg); + return err; +} + +/* + * 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; + } + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + 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; + + /* 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; + long l; + int err; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for master file"); + return -EINVAL; + } + + if (uc_mgr->conf_format >= 2) { + err = snd_config_search(cfg, "Syntax", &n); + if (err < 0) { + uc_error("Syntax field not found in %s", uc_mgr->conf_file_name); + return -EINVAL; + } + err = snd_config_get_integer(n, &l); + if (err < 0) { + uc_error("Syntax field is invalid in %s", uc_mgr->conf_file_name); + return err; + } + if (l < 2 || l > SYNTAX_VERSION_MAX) { + uc_error("Incompatible syntax %d in %s", l, uc_mgr->conf_file_name); + return -EINVAL; + } + /* delete this field to avoid strcmp() call in the loop */ + snd_config_delete(n); + } + + /* in-place condition evaluation */ + err = evaluate_condition(uc_mgr, cfg); + if (err < 0) + return err; + + /* 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; +} + +/* get the card info */ +static int get_card_info(snd_use_case_mgr_t *mgr, + const char *ctl_name, + snd_ctl_t **_handle, + snd_ctl_card_info_t *info) +{ + snd_ctl_t *handle; + int err; + + *_handle = NULL; + + err = uc_mgr_open_ctl(mgr, &handle, ctl_name); + if (err < 0) + return err; + + err = snd_ctl_card_info(handle, info); + if (err < 0) { + uc_error("control hardware info (%s): %s", ctl_name, snd_strerror(err)); + } else { + *_handle = handle; + } + + return err; +} + +/* find the card in the local machine and store the card long name */ +static int get_card_long_name(snd_use_case_mgr_t *mgr, char *longname) +{ + const char *card_name = mgr->card_name; + int card, err; + snd_ctl_t *ctl; + snd_ctl_card_info_t *info; + const char *_name, *_long_name; + + snd_ctl_card_info_alloca(&info); + + card = -1; + if (snd_card_next(&card) < 0 || card < 0) { + uc_error("no soundcards found..."); + return -1; + } + + while (card >= 0) { + char name[32]; + + /* most probably, we do not need to cache all CTL devices here */ + uc_mgr_free_ctl_list(mgr); + + sprintf(name, "hw:%d", card); + err = get_card_info(mgr, name, &ctl, info); + + if (err == 0) { + _name = snd_ctl_card_info_get_name(info); + _long_name = snd_ctl_card_info_get_longname(info); + if (!strcmp(card_name, _name) || + !strcmp(card_name, _long_name)) { + snd_strlcpy(longname, _long_name, MAX_CARD_LONG_NAME); + return 0; + } + } + + if (snd_card_next(&card) < 0) { + uc_error("snd_card_next"); + break; + } + } + + uc_mgr_free_ctl_list(mgr); + + return -1; +} + +/* set the driver name and long name by the card ctl name */ +static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name, char *longname) +{ + snd_ctl_t *ctl; + snd_ctl_card_info_t *info; + const char *_name, *_long_name; + int err; + + snd_ctl_card_info_alloca(&info); + + err = get_card_info(mgr, ctl_name, &ctl, info); + if (err) + return err; + + _name = snd_ctl_card_info_get_name(info); + _long_name = snd_ctl_card_info_get_longname(info); + snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name)); + snd_strlcpy(longname, _long_name, MAX_CARD_LONG_NAME); + + return 0; +} + +static int load_master_config(snd_use_case_mgr_t *uc_mgr, + const char *card_name, snd_config_t **cfg, int longname) +{ + char filename[MAX_FILE]; + int err; + + if (strnlen(card_name, MAX_CARD_LONG_NAME) == MAX_CARD_LONG_NAME) { + uc_error("error: invalid card name %s (at most %d chars)", + card_name, MAX_CARD_LONG_NAME - 1); + return -EINVAL; + } + + uc_mgr->conf_format = 0; + if (longname) { + if (getenv(ALSA_CONFIG_UCM2_VAR) || !getenv(ALSA_CONFIG_UCM_VAR)) { + uc_mgr->conf_format = 2; + configuration_filename(uc_mgr, filename, sizeof(filename), + uc_mgr->conf_file_name, card_name, ".conf"); + if (access(filename, R_OK) == 0) + goto __load; + } + /* try the old ucm directory */ + uc_mgr->conf_format = 1; + configuration_filename(uc_mgr, filename, sizeof(filename), + card_name, card_name, ".conf"); + if (access(filename, R_OK) != 0) + return -ENOENT; + } else { + configuration_filename(uc_mgr, filename, sizeof(filename), + card_name, card_name, ".conf"); + } + +__load: + err = uc_mgr_config_load(uc_mgr->conf_format, 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 + * + * The same ASoC machine driver can be shared by many different devices. + * For user space to differentiate them and get the best device-specific + * configuration, ASoC machine drivers may use the DMI info + * (vendor-product-version-board) as the card long name. And user space can + * define configuration files like longnamei/longname.conf for a specific device. + * + * This function will try to find the card in the local machine and get its + * long name, then load the file longname/longname.conf to get the best + * device-specific configuration. If the card is not found in the local + * machine or the device-specific file is not available, fall back to load + * the default configuration file name/name.conf. + */ +int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) +{ + snd_config_t *cfg; + const char *name = uc_mgr->card_name; + char longname[MAX_CARD_LONG_NAME]; + int err; + + snd_strlcpy(uc_mgr->conf_file_name, uc_mgr->card_name, sizeof(uc_mgr->conf_file_name)); + + if (strncmp(name, "hw:", 3) == 0) { + err = get_by_card(uc_mgr, name, longname); + if (err == 0) + goto __longname; + uc_error("card '%s' is not valid", name); + goto __error; + } else if (strncmp(name, "strict:", 7)) { + err = get_card_long_name(uc_mgr, longname); + if (err == 0) { /* load file that matches the card long name */ +__longname: + err = load_master_config(uc_mgr, longname, &cfg, 1); + } + + if (err == 0) { + /* got device-specific file that matches the card long name */ + snd_strlcpy(uc_mgr->conf_file_name, longname, sizeof(uc_mgr->conf_file_name)); + goto __parse; + } + } + + /* standard path */ + err = load_master_config(uc_mgr, uc_mgr->conf_file_name, &cfg, 0); + if (err < 0) + goto __error; + +__parse: + err = parse_master_file(uc_mgr, cfg); + snd_config_delete(cfg); + if (err < 0) { + uc_mgr_free_ctl_list(uc_mgr); + uc_mgr_free_verb(uc_mgr); + } + + return err; + +__error: + uc_mgr_free_ctl_list(uc_mgr); + uc_mgr->conf_file_name[0] = '\0'; + 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; +} + +/* whether input dir is a predefined component directory */ +static int is_component_directory(const char *dir) +{ + int i = 0; + + while (component_dir[i]) { + if (!strncmp(dir, component_dir[i], PATH_MAX)) + return 1; + i++; + }; + + return 0; +} + +/* scan all cards and comments + * + * Cards are defined by machines. Each card/machine installs its UCM + * configuration files in a subdirectory with the same name as the sound + * card under /usr/share/alsa/ucm2. This function will scan all the card + * directories and skip the component directories defined in the array + * component_dir. + */ +int uc_mgr_scan_master_configs(const char **_list[]) +{ + char filename[MAX_FILE], dfl[MAX_FILE]; + char *env = getenv(ALSA_CONFIG_UCM2_VAR); + const char **list, *d_name; + snd_config_t *cfg, *c; + int i, j, cnt, err; + long l; + ssize_t ss; + struct dirent **namelist; + + if (env) + snprintf(filename, sizeof(filename), "%s", env); + else + snprintf(filename, sizeof(filename), "%s/ucm2", + snd_config_topdir()); + +#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID) +#define SORTFUNC versionsort +#else +#define SORTFUNC alphasort +#endif + err = scandir(filename, &namelist, filename_filter, SORTFUNC); + 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 = j = 0; i < cnt; i++) { + + d_name = namelist[i]->d_name; + + /* Skip the directories for component devices */ + if (is_component_directory(d_name)) + continue; + + configuration_filename2(filename, sizeof(filename), 2, + d_name, d_name, ".conf"); + err = uc_mgr_config_load(2, filename, &cfg); + if (err < 0) + goto __err; + err = snd_config_search(cfg, "Syntax", &c); + if (err < 0) { + uc_error("Syntax field not found in %s", d_name); + snd_config_delete(cfg); + continue; + } + err = snd_config_get_integer(c, &l); + if (err < 0) { + uc_error("Syntax field is invalid in %s", d_name); + snd_config_delete(cfg); + goto __err; + } + if (l < 2 || l > SYNTAX_VERSION_MAX) { + uc_error("Incompatible syntax %d in %s", l, d_name); + snd_config_delete(cfg); + goto __err; + } + err = snd_config_search(cfg, "Comment", &c); + if (err >= 0) { + err = parse_string(c, (char **)&list[j+1]); + if (err < 0) { + snd_config_delete(cfg); + goto __err; + } + } + snd_config_delete(cfg); + list[j] = strdup(d_name); + if (list[j] == NULL) { + err = -ENOMEM; + goto __err; + } + if (strcmp(dfl, list[j]) == 0) { + /* default to top */ + const char *save1 = list[j]; + const char *save2 = list[j + 1]; + memmove(list + 2, list, j * sizeof(char *)); + list[0] = save1; + list[1] = save2; + } + j += 2; + } + err = j; + + __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; + } else { + free(list); + } + + return err; +} diff --git a/src/ucm/ucm_cond.c b/src/ucm/ucm_cond.c new file mode 100644 index 0000000..22b418d --- /dev/null +++ b/src/ucm/ucm_cond.c @@ -0,0 +1,480 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) 2019 Red Hat Inc. + * Authors: Jaroslav Kysela + */ + +#include "ucm_local.h" +#include + +static int get_string(snd_config_t *compound, const char *key, const char **str) +{ + snd_config_t *node; + int err; + + err = snd_config_search(compound, key, &node); + if (err < 0) + return err; + return snd_config_get_string(node, str); +} + +static int if_eval_string(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval) +{ + const char *string1 = NULL, *string2 = NULL; + char *s1, *s2; + int err; + + err = get_string(eval, "String1", &string1); + if (err < 0 && err != -ENOENT) { + uc_error("String error (If.Condition.String1)"); + return -EINVAL; + } + + err = get_string(eval, "String2", &string2); + if (err < 0 && err != -ENOENT) { + uc_error("String error (If.Condition.String2)"); + return -EINVAL; + } + + if (string1 || string2) { + if (string1 == NULL) { + uc_error("If.Condition.String1 not defined"); + return -EINVAL; + } + if (string2 == NULL) { + uc_error("If.Condition.String2 not defined"); + return -EINVAL; + } + err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1); + if (err < 0) + return err; + err = uc_mgr_get_substituted_value(uc_mgr, &s2, string2); + if (err < 0) { + free(s1); + return err; + } + err = strcasecmp(s1, s2) == 0; + free(s2); + free(s1); + return err; + } + + err = get_string(eval, "Haystack", &string1); + if (err < 0 && err != -ENOENT) { + uc_error("String error (If.Condition.Haystack)"); + return -EINVAL; + } + + err = get_string(eval, "Needle", &string2); + if (err < 0 && err != -ENOENT) { + uc_error("String error (If.Condition.Needle)"); + return -EINVAL; + } + + if (string1 || string2) { + if (string1 == NULL) { + uc_error("If.Condition.Haystack not defined"); + return -EINVAL; + } + if (string2 == NULL) { + uc_error("If.Condition.Needle not defined"); + return -EINVAL; + } + err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1); + if (err < 0) + return err; + err = uc_mgr_get_substituted_value(uc_mgr, &s2, string2); + if (err < 0) { + free(s1); + return err; + } + err = strstr(s1, s2) != NULL; + free(s2); + free(s1); + return err; + } + + uc_error("Unknown String condition arguments"); + return -EINVAL; +} + +static int if_eval_regex_match(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval) +{ + const char *string, *regex_string; + char *s; + regex_t re; + int options = REG_EXTENDED | REG_ICASE; + regmatch_t match[1]; + int err; + + err = get_string(eval, "String", &string); + if (err < 0) { + uc_error("RegexMatch error (If.Condition.String)"); + return -EINVAL; + } + + err = get_string(eval, "Regex", ®ex_string); + if (err < 0) { + uc_error("RegexMatch error (If.Condition.Regex)"); + return -EINVAL; + } + + err = uc_mgr_get_substituted_value(uc_mgr, &s, regex_string); + if (err < 0) + return err; + err = regcomp(&re, s, options); + free(s); + if (err) { + uc_error("Regex '%s' compilation failed (code %d)", err); + return -EINVAL; + } + + err = uc_mgr_get_substituted_value(uc_mgr, &s, string); + if (err < 0) { + regfree(&re); + return err; + } + err = regexec(&re, s, ARRAY_SIZE(match), match, 0); + free(s); + regfree(&re); + return err == 0; +} + +static int if_eval_control_exists(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval) +{ + snd_ctl_t *ctl; + const char *device = NULL, *ctldef, *enumval = NULL, *name; + snd_ctl_elem_id_t *elem_id; + snd_ctl_elem_info_t *elem_info; + snd_ctl_elem_type_t type; + char *s; + int err, i, items; + + snd_ctl_elem_id_alloca(&elem_id); + snd_ctl_elem_info_alloca(&elem_info); + + err = get_string(eval, "Device", &device); + if (err < 0 && err != -ENOENT) { + uc_error("ControlExists error (If.Condition.Device)"); + return -EINVAL; + } + + err = get_string(eval, "Control", &ctldef); + if (err < 0) { + uc_error("ControlExists error (If.Condition.Control)"); + return -EINVAL; + } + + err = get_string(eval, "ControlEnum", &enumval); + if (err < 0 && err != -ENOENT) { + uc_error("ControlExists error (If.Condition.ControlEnum)"); + return -EINVAL; + } + + err = uc_mgr_get_substituted_value(uc_mgr, &s, ctldef); + if (err < 0) + return err; + err = snd_ctl_ascii_elem_id_parse(elem_id, s); + free(s); + if (err < 0) { + uc_error("unable to parse element identificator (%s)", ctldef); + return -EINVAL; + } + + if (device == NULL) { + ctl = uc_mgr_get_ctl(uc_mgr); + if (ctl == NULL) { + uc_error("cannot determine control device"); + return -EINVAL; + } + } else { + err = uc_mgr_get_substituted_value(uc_mgr, &s, device); + if (err < 0) + return err; + err = uc_mgr_open_ctl(uc_mgr, &ctl, s); + free(s); + if (err < 0) + return err; + } + + snd_ctl_elem_info_set_id(elem_info, elem_id); + err = snd_ctl_elem_info(ctl, elem_info); + if (err < 0) + return 0; + + if (enumval) { + type = snd_ctl_elem_info_get_type(elem_info); + if (type != SND_CTL_ELEM_TYPE_ENUMERATED) + return 0; + err = uc_mgr_get_substituted_value(uc_mgr, &s, enumval); + if (err < 0) + return err; + items = snd_ctl_elem_info_get_items(elem_info); + for (i = 0; i < items; i++) { + snd_ctl_elem_info_set_item(elem_info, i); + err = snd_ctl_elem_info(ctl, elem_info); + if (err < 0) { + free(s); + return err; + } + name = snd_ctl_elem_info_get_item_name(elem_info); + if (strcasecmp(name, s) == 0) { + free(s); + return 1; + } + } + free(s); + return 0; + } + + return 1; +} + +static int if_eval(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval) +{ + const char *type; + int err; + + if (snd_config_get_type(eval) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for If.Condition"); + return -EINVAL; + } + + err = get_string(eval, "Type", &type); + if (err < 0) { + uc_error("type block error (If.Condition)"); + return -EINVAL; + } + + if (strcmp(type, "ControlExists") == 0) + return if_eval_control_exists(uc_mgr, eval); + + if (strcmp(type, "String") == 0) + return if_eval_string(uc_mgr, eval); + + if (strcmp(type, "RegexMatch") == 0) + return if_eval_regex_match(uc_mgr, eval); + + uc_error("unknown If.Condition.Type"); + return -EINVAL; +} + +static int if_eval_one(snd_use_case_mgr_t *uc_mgr, + snd_config_t *cond, + snd_config_t **result, + snd_config_t **before, + snd_config_t **after) +{ + snd_config_t *expr, *_true = NULL, *_false = NULL; + int err; + + *result = NULL; + + if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for If.1"); + return -EINVAL; + } + + if (snd_config_search(cond, "Condition", &expr) < 0) { + uc_error("condition block expected (If)"); + return -EINVAL; + } + + err = snd_config_search(cond, "True", &_true); + if (err < 0 && err != -ENOENT) { + uc_error("true block error (If)"); + return -EINVAL; + } + + err = snd_config_search(cond, "False", &_false); + if (err < 0 && err != -ENOENT) { + uc_error("false block error (If)"); + return -EINVAL; + } + + err = snd_config_search(cond, "Before", before); + if (err < 0 && err != -ENOENT) { + uc_error("before block identifier error"); + return -EINVAL; + } + + err = snd_config_search(cond, "After", after); + if (err < 0 && err != -ENOENT) { + uc_error("before block identifier error"); + return -EINVAL; + } + + err = if_eval(uc_mgr, expr); + if (err > 0) { + *result = _true; + return 0; + } else if (err == 0) { + *result = _false; + return 0; + } else { + return err; + } +} + +#if 0 +static void config_dump(snd_config_t *cfg) +{ + snd_output_t *out; + snd_output_stdio_attach(&out, stderr, 0); + snd_output_printf(out, "-----\n"); + snd_config_save(cfg, out); + snd_output_close(out); +} +#endif + +static int compound_merge(const char *id, + snd_config_t *dst, snd_config_t *src, + snd_config_t *before, snd_config_t *after) +{ + snd_config_iterator_t i, next; + snd_config_t *n, *_before = NULL, *_after = NULL; + const char *s; + int err; + + if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for If True/False block"); + return -EINVAL; + } + + if (before) { + err = get_string(before, id, &s); + if (err < 0 && err != -ENOENT) + return err; + if (err == 0) { + err = snd_config_search(dst, s, &_before); + if (err < 0 && err != -ENOENT) + return err; + } + } + if (after) { + err = get_string(after, id, &s); + if (err < 0 && err != -ENOENT) + return err; + if (err == 0) { + err = snd_config_search(dst, s, &_after); + if (err < 0 && err != -ENOENT) + return err; + } + } + + if (_before && _after) { + uc_error("defined both before and after identifiers in the If block"); + return -EINVAL; + } + + snd_config_for_each(i, next, src) { + n = snd_config_iterator_entry(i); + err = snd_config_remove(n); + if (err < 0) + return err; + if (_before) { + err = snd_config_add_before(_before, n); + if (err < 0) + return err; + _before = NULL; + _after = n; + } else if (_after) { + err = snd_config_add_after(_after, n); + if (err < 0) + return err; + _after = n; + } else { + err = snd_config_add(dst, n); + if (err < 0) + return err; + } + } + + return 0; +} + +/* + * put back the result from all conditions to the parent + */ +int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr, + snd_config_t *parent, + snd_config_t *cond) +{ + snd_config_iterator_t i, i2, next, next2; + snd_config_t *a, *n, *n2, *parent2, *before, *after; + const char *id; + int err; + + if (uc_mgr->conf_format < 2) { + uc_error("conditions are not supported for v1 syntax"); + return -EINVAL; + } + + if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for If"); + return -EINVAL; + } + + snd_config_for_each(i, next, cond) { + n = snd_config_iterator_entry(i); + before = after = NULL; + err = if_eval_one(uc_mgr, n, &a, &before, &after); + if (err < 0) + return err; + if (a == NULL) + continue; + err = snd_config_search(a, "If", &n2); + if (err < 0 && err != -ENOENT) { + uc_error("If block error (If)"); + return -EINVAL; + } else if (err == 0) { + err = uc_mgr_evaluate_condition(uc_mgr, a, n2); + if (err < 0) + return err; + snd_config_delete(n2); + } + snd_config_for_each(i2, next2, a) { + n2 = snd_config_iterator_entry(i2); + err = snd_config_remove(n2); + if (err < 0) + return err; + err = snd_config_get_id(n2, &id); + if (err < 0) { +__add: + err = snd_config_add(parent, n2); + if (err < 0) + return err; + continue; + } else { + err = snd_config_search(parent, id, &parent2); + if (err == -ENOENT) + goto __add; + err = compound_merge(id, parent2, n2, before, after); + if (err < 0) + return err; + } + snd_config_delete(n2); + } + } + return 0; +} diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h new file mode 100644 index 0000000..ba96150 --- /dev/null +++ b/src/ucm/ucm_local.h @@ -0,0 +1,283 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 +#include "use-case.h" + +#define SYNTAX_VERSION_MAX 2 + +#define MAX_FILE 256 +#define MAX_CARD_SHORT_NAME 32 +#define MAX_CARD_LONG_NAME 80 + +#define SEQUENCE_ELEMENT_TYPE_CDEV 1 +#define SEQUENCE_ELEMENT_TYPE_CSET 2 +#define SEQUENCE_ELEMENT_TYPE_SLEEP 3 +#define SEQUENCE_ELEMENT_TYPE_EXEC 4 +#define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE 5 +#define SEQUENCE_ELEMENT_TYPE_CSET_TLV 6 +#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 7 + +struct ucm_value { + struct list_head list; + char *name; + char *data; +}; + +/* sequence of a component device */ +struct component_sequence { + struct use_case_device *device; /* component device */ + int enable; /* flag to choose enable or disable list of the device */ +}; + +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; + struct component_sequence cmpt_seq; /* component sequence */ + } 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; +}; + +struct ctl_dev { + struct list_head list; + char *device; +}; + +struct ctl_list { + struct list_head list; + struct list_head dev_list; + snd_ctl_t *ctl; + snd_ctl_card_info_t *ctl_info; +}; + +/* + * 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; + + /* component device list */ + struct list_head cmpt_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 conf_file_name[MAX_CARD_LONG_NAME]; + char *comment; + int conf_format; + + /* 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; + + /* list of opened control devices */ + struct list_head ctl_list; + + /* Components don't define cdev, the card device. When executing + * a sequence of a component device, ucm manager enters component + * domain and needs to provide cdev to the component. This cdev + * should be defined by the machine, parent of the component. + */ + int in_component_domain; + char *cdev; +}; + +#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(int format, 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); + +int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr, + snd_ctl_t **ctl, + const char *device); + +struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr); +snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr); +void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr); + +int uc_mgr_add_value(struct list_head *base, const char *key, char *val); + +int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, + char **_rvalue, + const char *value); + +int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr, + snd_config_t *parent, + snd_config_t *cond); + +/** The name of the environment variable containing the UCM directory */ +#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" + +/** The name of the environment variable containing the UCM directory (new syntax) */ +#define ALSA_CONFIG_UCM2_VAR "ALSA_CONFIG_UCM2" diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c new file mode 100644 index 0000000..00afa9e --- /dev/null +++ b/src/ucm/ucm_subs.c @@ -0,0 +1,248 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) 2019 Red Hat Inc. + * Authors: Jaroslav Kysela + */ + +#include "ucm_local.h" +#include +#include + +static char *rval_conf_name(snd_use_case_mgr_t *uc_mgr) +{ + if (uc_mgr->conf_file_name[0]) + return strdup(uc_mgr->conf_file_name); + return NULL; +} + +static char *rval_card_id(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list == NULL) + return NULL; + return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info)); +} + +static char *rval_card_driver(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list == NULL) + return NULL; + return strdup(snd_ctl_card_info_get_driver(ctl_list->ctl_info)); +} + +static char *rval_card_name(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list == NULL) + return NULL; + return strdup(snd_ctl_card_info_get_name(ctl_list->ctl_info)); +} + +static char *rval_card_longname(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list == NULL) + return NULL; + return strdup(snd_ctl_card_info_get_longname(ctl_list->ctl_info)); +} + +static char *rval_card_components(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list == NULL) + return NULL; + return strdup(snd_ctl_card_info_get_components(ctl_list->ctl_info)); +} + +static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id) +{ + char *e; + + e = getenv(id); + if (e) + return strdup(e); + return NULL; +} + +static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id) +{ + char path[PATH_MAX], link[PATH_MAX + 1]; + struct stat sb; + ssize_t len; + char *e; + int fd; + + e = getenv("SYSFS_PATH"); + if (e == NULL) + e = "/sys"; + if (id[0] == '/') + id++; + snprintf(path, sizeof(path), "%s/%s", e, id); + if (lstat(path, &sb) != 0) + return NULL; + if (S_ISLNK(sb.st_mode)) { + len = readlink(path, link, sizeof(link) - 1); + if (len <= 0) { + uc_error("sysfs: cannot read link '%s' (%d)", path, errno); + return NULL; + } + link[len] = '\0'; + e = strrchr(link, '/'); + if (e) + return strdup(e + 1); + return NULL; + } + if (S_ISDIR(sb.st_mode)) + return NULL; + if ((sb.st_mode & S_IRUSR) == 0) + return NULL; + + fd = open(path, O_RDONLY); + if (fd < 0) { + uc_error("sysfs open failed for '%s' (%d)", path, errno); + return NULL; + } + len = read(fd, path, sizeof(path)-1); + close(fd); + if (len < 0) { + uc_error("sysfs unable to read value '%s' (%d)", path, errno); + return NULL; + } + while (len > 0 && path[len-1] == '\n') + len--; + path[len] = '\0'; + return strdup(path); +} + +#define MATCH_VARIABLE(name, id, fcn) \ + if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ + rval = fcn(uc_mgr); \ + idsize = sizeof(id) - 1; \ + goto __rval; \ + } + +#define MATCH_VARIABLE2(name, id, fcn) \ + if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ + idsize = sizeof(id) - 1; \ + tmp = strchr(value + idsize, '}'); \ + if (tmp) { \ + rvalsize = tmp - (value + idsize); \ + if (rvalsize > sizeof(v2)) { \ + err = -ENOMEM; \ + goto __error; \ + } \ + strncpy(v2, value + idsize, rvalsize); \ + v2[rvalsize] = '\0'; \ + idsize += rvalsize + 1; \ + rval = fcn(uc_mgr, v2); \ + goto __rval; \ + } \ + } + +int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, + char **_rvalue, + const char *value) +{ + size_t size, nsize, idsize, rvalsize, dpos = 0; + const char *tmp; + char *r, *nr, *rval, v2[32]; + int err; + + if (value == NULL) + return -ENOENT; + + size = strlen(value) + 1; + r = malloc(size); + if (r == NULL) + return -ENOMEM; + + while (*value) { + if (*value == '$' && *(value+1) == '{') { + MATCH_VARIABLE(value, "${ConfName}", rval_conf_name); + MATCH_VARIABLE(value, "${CardId}", rval_card_id); + MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver); + MATCH_VARIABLE(value, "${CardName}", rval_card_name); + MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname); + MATCH_VARIABLE(value, "${CardComponents}", rval_card_components); + MATCH_VARIABLE2(value, "${env:", rval_env); + MATCH_VARIABLE2(value, "${sys:", rval_sysfs); + err = -EINVAL; + tmp = strchr(value, '}'); + if (tmp) { + strncpy(r, value, tmp + 1 - value); + r[tmp + 1 - value] = '\0'; + uc_error("variable '%s' is not known!", r); + } else { + uc_error("variable reference '%s' is not complete", value); + } + goto __error; +__rval: + if (rval == NULL || rval[0] == '\0') { + free(rval); + strncpy(r, value, idsize); + r[idsize] = '\0'; + uc_error("variable '%s' is not defined in this context!", r); + err = -EINVAL; + goto __error; + } + value += idsize; + rvalsize = strlen(rval); + nsize = size + rvalsize - idsize; + if (nsize > size) { + nr = realloc(r, nsize); + if (nr == NULL) { + free(rval); + err = -ENOMEM; + goto __error; + } + size = nsize; + r = nr; + } + strcpy(r + dpos, rval); + dpos += rvalsize; + free(rval); + } else { + r[dpos++] = *value; + value++; + } + } + r[dpos] = '\0'; + + *_rvalue = r; + return 0; + +__error: + free(r); + return err; +} diff --git a/src/ucm/utils.c b/src/ucm/utils.c new file mode 100644 index 0000000..cde1d67 --- /dev/null +++ b/src/ucm/utils.c @@ -0,0 +1,456 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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); +} + +struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr) +{ + struct list_head *pos; + struct ctl_list *ctl_list = NULL; + + list_for_each(pos, &uc_mgr->ctl_list) { + if (ctl_list) { + uc_error("multiple control device names were found!"); + return NULL; + } + ctl_list = list_entry(pos, struct ctl_list, list); + } + return ctl_list; +} + +snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr) +{ + struct ctl_list *ctl_list; + + ctl_list = uc_mgr_get_one_ctl(uc_mgr); + if (ctl_list) + return ctl_list->ctl; + return NULL; +} + +static void uc_mgr_free_ctl(struct ctl_list *ctl_list) +{ + struct list_head *pos, *npos; + struct ctl_dev *ctl_dev; + + list_for_each_safe(pos, npos, &ctl_list->dev_list) { + ctl_dev = list_entry(pos, struct ctl_dev, list); + free(ctl_dev->device); + free(ctl_dev); + } + snd_ctl_card_info_free(ctl_list->ctl_info); + free(ctl_list); +} + +void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr) +{ + struct list_head *pos, *npos; + struct ctl_list *ctl_list; + + list_for_each_safe(pos, npos, &uc_mgr->ctl_list) { + ctl_list = list_entry(pos, struct ctl_list, list); + snd_ctl_close(ctl_list->ctl); + list_del(&ctl_list->list); + uc_mgr_free_ctl(ctl_list); + } +} + +static int uc_mgr_ctl_add_dev(struct ctl_list *ctl_list, const char *device) +{ + struct list_head *pos; + struct ctl_dev *ctl_dev; + + /* skip duplicates */ + list_for_each(pos, &ctl_list->dev_list) { + ctl_dev = list_entry(pos, struct ctl_dev, list); + if (strcmp(ctl_dev->device, device) == 0) + return 0; + } + + /* allocate new device name */ + ctl_dev = malloc(sizeof(*ctl_dev)); + if (ctl_dev == NULL) + return -ENOMEM; + ctl_dev->device = strdup(device); + if (ctl_dev->device == NULL) { + free(ctl_dev); + return -ENOMEM; + } + list_add_tail(&ctl_dev->list, &ctl_list->dev_list); + return 0; +} + +static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr, + struct ctl_list *ctl_list, + snd_ctl_t *ctl, int card, + snd_ctl_card_info_t *info, + const char *device) +{ + struct ctl_list *cl = NULL; + const char *id = snd_ctl_card_info_get_id(info); + char dev[MAX_CARD_LONG_NAME]; + int err, hit = 0; + + if (id == NULL || id[0] == '\0') + return -ENOENT; + if (!ctl_list) { + cl = malloc(sizeof(*cl)); + if (cl == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&cl->dev_list); + cl->ctl = ctl; + if (snd_ctl_card_info_malloc(&cl->ctl_info) < 0) { + free(cl); + return -ENOMEM; + } + snd_ctl_card_info_copy(cl->ctl_info, info); + ctl_list = cl; + } + if (card >= 0) { + snprintf(dev, sizeof(dev), "hw:%d", card); + hit |= !!(device && (strcmp(dev, device) == 0)); + err = uc_mgr_ctl_add_dev(ctl_list, dev); + if (err < 0) + goto __nomem; + } + snprintf(dev, sizeof(dev), "hw:%s", id); + hit |= !!(device && (strcmp(dev, device) == 0)); + err = uc_mgr_ctl_add_dev(ctl_list, dev); + if (err < 0) + goto __nomem; + /* the UCM name not based on the card name / id */ + if (!hit && device) { + err = uc_mgr_ctl_add_dev(ctl_list, device); + if (err < 0) + goto __nomem; + } + + list_add_tail(&ctl_list->list, &uc_mgr->ctl_list); + return 0; + +__nomem: + if (ctl_list == cl) + uc_mgr_free_ctl(cl); + return -ENOMEM; +} + +int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr, + snd_ctl_t **ctl, + const char *device) +{ + struct list_head *pos1, *pos2; + struct ctl_list *ctl_list; + struct ctl_dev *ctl_dev; + snd_ctl_card_info_t *info; + const char *id; + int err, card; + + snd_ctl_card_info_alloca(&info); + + /* cache lookup */ + list_for_each(pos1, &uc_mgr->ctl_list) { + ctl_list = list_entry(pos1, struct ctl_list, list); + list_for_each(pos2, &ctl_list->dev_list) { + ctl_dev = list_entry(pos2, struct ctl_dev, list); + if (strcmp(ctl_dev->device, device) == 0) { + *ctl = ctl_list->ctl; + return 0; + } + } + } + + err = snd_ctl_open(ctl, device, 0); + if (err < 0) + return err; + + id = NULL; + err = snd_ctl_card_info(*ctl, info); + if (err == 0) + id = snd_ctl_card_info_get_id(info); + if (err < 0 || id == NULL || id[0] == '\0') { + uc_error("control hardware info (%s): %s", device, snd_strerror(err)); + snd_ctl_close(*ctl); + *ctl = NULL; + return err; + } + + /* insert to cache, if just name differs */ + list_for_each(pos1, &uc_mgr->ctl_list) { + ctl_list = list_entry(pos1, struct ctl_list, list); + if (strcmp(id, snd_ctl_card_info_get_id(ctl_list->ctl_info)) == 0) { + card = snd_card_get_index(id); + err = uc_mgr_ctl_add(uc_mgr, ctl_list, *ctl, card, info, device); + if (err < 0) + goto __nomem; + snd_ctl_close(*ctl); + *ctl = ctl_list->ctl; + return 0; + } + } + + err = uc_mgr_ctl_add(uc_mgr, NULL, *ctl, -1, info, device); + if (err < 0) + goto __nomem; + + return 0; + +__nomem: + snd_ctl_close(*ctl); + *ctl = NULL; + return -ENOMEM; +} + +int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg) +{ + FILE *fp; + snd_input_t *in; + snd_config_t *top; + const char *path, *default_paths[2]; + int err; + + fp = fopen(file, "r"); + if (!fp) { + err = -errno; + __err0: + uc_error("could not open configuration file %s", file); + return err; + } + err = snd_input_stdio_attach(&in, fp, 1); + if (err < 0) + goto __err0; + err = snd_config_top(&top); + if (err < 0) + goto __err1; + + if (format >= 2) { + path = getenv(ALSA_CONFIG_UCM2_VAR); + if (!path || path[0] == '\0') + path = ALSA_CONFIG_DIR "/ucm2"; + } else { + path = getenv(ALSA_CONFIG_UCM_VAR); + if (!path || path[0] == '\0') + path = ALSA_CONFIG_DIR "/ucm"; + } + + default_paths[0] = path; + default_paths[1] = NULL; + err = _snd_config_load_with_include(top, in, 0, default_paths); + if (err < 0) { + uc_error("could not load configuration file %s", file); + goto __err2; + } + err = snd_input_close(in); + if (err < 0) { + in = NULL; + goto __err2; + } + *cfg = top; + return 0; + + __err2: + snd_config_delete(top); + __err1: + if (in) + snd_input_close(in); + return err; +} + +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_CDEV: + free(seq->data.cdev); + break; + case SEQUENCE_ELEMENT_TYPE_CSET: + case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE: + case SEQUENCE_ELEMENT_TYPE_CSET_TLV: + free(seq->data.cset); + break; + 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_device(&verb->cmpt_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); +} + +void uc_mgr_free(snd_use_case_mgr_t *uc_mgr) +{ + uc_mgr_free_verb(uc_mgr); + uc_mgr_free_ctl_list(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..4a74083 --- /dev/null +++ b/src/userfile.c @@ -0,0 +1,122 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#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 +#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: + wordfree(&we); + return -ENOMEM; + case 0: + if (we.we_wordc == 1) + break; + wordfree(&we); + /* fall thru */ + default: + return -EINVAL; + } + *result = strdup(we.we_wordv[0]); + wordfree(&we); + if (*result == NULL) + return -ENOMEM; + return 0; +} + +#else /* !HAVE_WORDEX */ + +#include +#include +#include +#include +#include + +int snd_user_file(const char *file, char **result) +{ + int err; + size_t len; + char *buf = NULL; + + assert(file && result); + *result = NULL; + + /* expand ~/ if needed */ + if (file[0] == '~' && file[1] == '/') { + const char *home = getenv("HOME"); + if (home == NULL) { + struct passwd pwent, *p = NULL; + uid_t id = getuid(); + size_t bufsize = 1024; + + buf = malloc(bufsize); + if (buf == NULL) + goto out; + + while ((err = getpwuid_r(id, &pwent, buf, bufsize, &p)) == ERANGE) { + char *newbuf; + bufsize += 1024; + if (bufsize < 1024) + break; + newbuf = realloc(buf, bufsize); + if (newbuf == NULL) + goto out; + buf = newbuf; + } + home = err ? "" : pwent.pw_dir; + } + len = strlen(home) + strlen(&file[2]) + 2; + *result = malloc(len); + if (*result) + snprintf(*result, len, "%s/%s", home, &file[2]); + } else { + *result = strdup(file); + } + +out: + if (buf) + free(buf); + + if (*result == NULL) + return -ENOMEM; + return 0; +} + +#endif /* HAVE_WORDEXP */ diff --git a/test-driver b/test-driver new file mode 100755 index 0000000..b8521a4 --- /dev/null +++ b/test-driver @@ -0,0 +1,148 @@ +#! /bin/sh +# test-driver - basic testsuite driver script. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 2011-2018 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. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +# Make unconditional expansion of undefined variables an error. This +# helps a lot in preventing typo-related bugs. +set -u + +usage_error () +{ + echo "$0: $*" >&2 + print_usage >&2 + exit 2 +} + +print_usage () +{ + cat <$log_file 2>&1 +estatus=$? + +if test $enable_hard_errors = no && test $estatus -eq 99; then + tweaked_estatus=1 +else + tweaked_estatus=$estatus +fi + +case $tweaked_estatus:$expect_failure in + 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; + 0:*) col=$grn res=PASS recheck=no gcopy=no;; + 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; + 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; + *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; + *:*) col=$red res=FAIL recheck=yes gcopy=yes;; +esac + +# Report the test outcome and exit status in the logs, so that one can +# know whether the test passed or failed simply by looking at the '.log' +# file, without the need of also peaking into the corresponding '.trs' +# file (automake bug#11814). +echo "$res $test_name (exit status: $estatus)" >>$log_file + +# Report outcome to console. +echo "${col}${res}${std}: $test_name" + +# Register the test result, and other relevant metadata. +echo ":test-result: $res" > $trs_file +echo ":global-test-result: $res" >> $trs_file +echo ":recheck: $recheck" >> $trs_file +echo ":copy-in-global-log: $gcopy" >> $trs_file + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..99c2c4f --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,34 @@ +SUBDIRS=. lsb + +check_PROGRAMS=control pcm pcm_min latency seq \ + playmidi1 timer rawmidi midiloop \ + oldapi queue_timer namehint client_event_filter \ + chmap audio_time user-ctl-element-set pcm-multi-thread + +control_LDADD=../src/libasound.la +pcm_LDADD=../src/libasound.la +pcm_LDFLAGS= -lm +pcm_min_LDADD=../src/libasound.la +latency_LDADD=../src/libasound.la +latency_LDFLAGS= -lm +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 +mixtest_CFLAGS=-Wall -pipe -g -O2 +chmap_LDADD=../src/libasound.la +audio_time_LDADD=../src/libasound.la +pcm_multi_thread_LDADD=../src/libasound.la +pcm_multi_thread_LDFLAGS=-lpthread +user_ctl_element_set_LDADD=../src/libasound.la +user_ctl_element_set_CFLAGS=-Wall -g + +AM_CPPFLAGS=-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..d096226 --- /dev/null +++ b/test/Makefile.in @@ -0,0 +1,956 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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) chmap$(EXEEXT) \ + audio_time$(EXEEXT) user-ctl-element-set$(EXEEXT) \ + pcm-multi-thread$(EXEEXT) +subdir = test +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +audio_time_SOURCES = audio_time.c +audio_time_OBJECTS = audio_time.$(OBJEXT) +audio_time_DEPENDENCIES = ../src/libasound.la +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +chmap_SOURCES = chmap.c +chmap_OBJECTS = chmap.$(OBJEXT) +chmap_DEPENDENCIES = ../src/libasound.la +client_event_filter_SOURCES = client_event_filter.c +client_event_filter_OBJECTS = client_event_filter.$(OBJEXT) +client_event_filter_DEPENDENCIES = ../src/libasound.la +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 +latency_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(latency_LDFLAGS) $(LDFLAGS) -o $@ +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_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(pcm_LDFLAGS) $(LDFLAGS) -o $@ +pcm_multi_thread_SOURCES = pcm-multi-thread.c +pcm_multi_thread_OBJECTS = pcm-multi-thread.$(OBJEXT) +pcm_multi_thread_DEPENDENCIES = ../src/libasound.la +pcm_multi_thread_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(pcm_multi_thread_LDFLAGS) $(LDFLAGS) \ + -o $@ +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 +user_ctl_element_set_SOURCES = user-ctl-element-set.c +user_ctl_element_set_OBJECTS = \ + user_ctl_element_set-user-ctl-element-set.$(OBJEXT) +user_ctl_element_set_DEPENDENCIES = ../src/libasound.la +user_ctl_element_set_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(user_ctl_element_set_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/audio_time.Po ./$(DEPDIR)/chmap.Po \ + ./$(DEPDIR)/client_event_filter.Po ./$(DEPDIR)/control.Po \ + ./$(DEPDIR)/latency.Po ./$(DEPDIR)/midiloop.Po \ + ./$(DEPDIR)/namehint.Po ./$(DEPDIR)/oldapi.Po \ + ./$(DEPDIR)/pcm-multi-thread.Po ./$(DEPDIR)/pcm.Po \ + ./$(DEPDIR)/pcm_min.Po ./$(DEPDIR)/playmidi1.Po \ + ./$(DEPDIR)/queue_timer.Po ./$(DEPDIR)/rawmidi.Po \ + ./$(DEPDIR)/seq.Po ./$(DEPDIR)/timer.Po \ + ./$(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Po +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_CC_1 = +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_CCLD_1 = +SOURCES = audio_time.c chmap.c client_event_filter.c control.c \ + latency.c midiloop.c namehint.c oldapi.c pcm.c \ + pcm-multi-thread.c pcm_min.c playmidi1.c queue_timer.c \ + rawmidi.c seq.c timer.c user-ctl-element-set.c +DIST_SOURCES = audio_time.c chmap.c client_event_filter.c control.c \ + latency.c midiloop.c namehint.c oldapi.c pcm.c \ + pcm-multi-thread.c pcm_min.c playmidi1.c queue_timer.c \ + rawmidi.c seq.c timer.c user-ctl-element-set.c +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-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 \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +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_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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_LDFLAGS = -lm +pcm_min_LDADD = ../src/libasound.la +latency_LDADD = ../src/libasound.la +latency_LDFLAGS = -lm +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 +mixtest_CFLAGS = -Wall -pipe -g -O2 +chmap_LDADD = ../src/libasound.la +audio_time_LDADD = ../src/libasound.la +pcm_multi_thread_LDADD = ../src/libasound.la +pcm_multi_thread_LDFLAGS = -lpthread +user_ctl_element_set_LDADD = ../src/libasound.la +user_ctl_element_set_CFLAGS = -Wall -g +AM_CPPFLAGS = -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: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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 + +audio_time$(EXEEXT): $(audio_time_OBJECTS) $(audio_time_DEPENDENCIES) $(EXTRA_audio_time_DEPENDENCIES) + @rm -f audio_time$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(audio_time_OBJECTS) $(audio_time_LDADD) $(LIBS) + +chmap$(EXEEXT): $(chmap_OBJECTS) $(chmap_DEPENDENCIES) $(EXTRA_chmap_DEPENDENCIES) + @rm -f chmap$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(chmap_OBJECTS) $(chmap_LDADD) $(LIBS) + +client_event_filter$(EXEEXT): $(client_event_filter_OBJECTS) $(client_event_filter_DEPENDENCIES) $(EXTRA_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) $(EXTRA_control_DEPENDENCIES) + @rm -f control$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(control_OBJECTS) $(control_LDADD) $(LIBS) + +latency$(EXEEXT): $(latency_OBJECTS) $(latency_DEPENDENCIES) $(EXTRA_latency_DEPENDENCIES) + @rm -f latency$(EXEEXT) + $(AM_V_CCLD)$(latency_LINK) $(latency_OBJECTS) $(latency_LDADD) $(LIBS) + +midiloop$(EXEEXT): $(midiloop_OBJECTS) $(midiloop_DEPENDENCIES) $(EXTRA_midiloop_DEPENDENCIES) + @rm -f midiloop$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(midiloop_OBJECTS) $(midiloop_LDADD) $(LIBS) + +namehint$(EXEEXT): $(namehint_OBJECTS) $(namehint_DEPENDENCIES) $(EXTRA_namehint_DEPENDENCIES) + @rm -f namehint$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(namehint_OBJECTS) $(namehint_LDADD) $(LIBS) + +oldapi$(EXEEXT): $(oldapi_OBJECTS) $(oldapi_DEPENDENCIES) $(EXTRA_oldapi_DEPENDENCIES) + @rm -f oldapi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(oldapi_OBJECTS) $(oldapi_LDADD) $(LIBS) + +pcm$(EXEEXT): $(pcm_OBJECTS) $(pcm_DEPENDENCIES) $(EXTRA_pcm_DEPENDENCIES) + @rm -f pcm$(EXEEXT) + $(AM_V_CCLD)$(pcm_LINK) $(pcm_OBJECTS) $(pcm_LDADD) $(LIBS) + +pcm-multi-thread$(EXEEXT): $(pcm_multi_thread_OBJECTS) $(pcm_multi_thread_DEPENDENCIES) $(EXTRA_pcm_multi_thread_DEPENDENCIES) + @rm -f pcm-multi-thread$(EXEEXT) + $(AM_V_CCLD)$(pcm_multi_thread_LINK) $(pcm_multi_thread_OBJECTS) $(pcm_multi_thread_LDADD) $(LIBS) + +pcm_min$(EXEEXT): $(pcm_min_OBJECTS) $(pcm_min_DEPENDENCIES) $(EXTRA_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) $(EXTRA_playmidi1_DEPENDENCIES) + @rm -f playmidi1$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(playmidi1_OBJECTS) $(playmidi1_LDADD) $(LIBS) + +queue_timer$(EXEEXT): $(queue_timer_OBJECTS) $(queue_timer_DEPENDENCIES) $(EXTRA_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) $(EXTRA_rawmidi_DEPENDENCIES) + @rm -f rawmidi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(rawmidi_OBJECTS) $(rawmidi_LDADD) $(LIBS) + +seq$(EXEEXT): $(seq_OBJECTS) $(seq_DEPENDENCIES) $(EXTRA_seq_DEPENDENCIES) + @rm -f seq$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(seq_OBJECTS) $(seq_LDADD) $(LIBS) + +timer$(EXEEXT): $(timer_OBJECTS) $(timer_DEPENDENCIES) $(EXTRA_timer_DEPENDENCIES) + @rm -f timer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(timer_OBJECTS) $(timer_LDADD) $(LIBS) + +user-ctl-element-set$(EXEEXT): $(user_ctl_element_set_OBJECTS) $(user_ctl_element_set_DEPENDENCIES) $(EXTRA_user_ctl_element_set_DEPENDENCIES) + @rm -f user-ctl-element-set$(EXEEXT) + $(AM_V_CCLD)$(user_ctl_element_set_LINK) $(user_ctl_element_set_OBJECTS) $(user_ctl_element_set_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio_time.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chmap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client_event_filter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/latency.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midiloop.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namehint.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oldapi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm-multi-thread.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcm_min.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playmidi1.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/queue_timer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawmidi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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 $@ $< + +user_ctl_element_set-user-ctl-element-set.o: user-ctl-element-set.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(user_ctl_element_set_CFLAGS) $(CFLAGS) -MT user_ctl_element_set-user-ctl-element-set.o -MD -MP -MF $(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Tpo -c -o user_ctl_element_set-user-ctl-element-set.o `test -f 'user-ctl-element-set.c' || echo '$(srcdir)/'`user-ctl-element-set.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Tpo $(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='user-ctl-element-set.c' object='user_ctl_element_set-user-ctl-element-set.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(user_ctl_element_set_CFLAGS) $(CFLAGS) -c -o user_ctl_element_set-user-ctl-element-set.o `test -f 'user-ctl-element-set.c' || echo '$(srcdir)/'`user-ctl-element-set.c + +user_ctl_element_set-user-ctl-element-set.obj: user-ctl-element-set.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(user_ctl_element_set_CFLAGS) $(CFLAGS) -MT user_ctl_element_set-user-ctl-element-set.obj -MD -MP -MF $(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Tpo -c -o user_ctl_element_set-user-ctl-element-set.obj `if test -f 'user-ctl-element-set.c'; then $(CYGPATH_W) 'user-ctl-element-set.c'; else $(CYGPATH_W) '$(srcdir)/user-ctl-element-set.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Tpo $(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='user-ctl-element-set.c' object='user_ctl_element_set-user-ctl-element-set.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(user_ctl_element_set_CFLAGS) $(CFLAGS) -c -o user_ctl_element_set-user-ctl-element-set.obj `if test -f 'user-ctl-element-set.c'; then $(CYGPATH_W) 'user-ctl-element-set.c'; else $(CYGPATH_W) '$(srcdir)/user-ctl-element-set.c'; fi` + +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. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + 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" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + 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; \ + $(am__define_uniq_tagged_files); \ + 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-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + 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: + 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-recursive + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/audio_time.Po + -rm -f ./$(DEPDIR)/chmap.Po + -rm -f ./$(DEPDIR)/client_event_filter.Po + -rm -f ./$(DEPDIR)/control.Po + -rm -f ./$(DEPDIR)/latency.Po + -rm -f ./$(DEPDIR)/midiloop.Po + -rm -f ./$(DEPDIR)/namehint.Po + -rm -f ./$(DEPDIR)/oldapi.Po + -rm -f ./$(DEPDIR)/pcm-multi-thread.Po + -rm -f ./$(DEPDIR)/pcm.Po + -rm -f ./$(DEPDIR)/pcm_min.Po + -rm -f ./$(DEPDIR)/playmidi1.Po + -rm -f ./$(DEPDIR)/queue_timer.Po + -rm -f ./$(DEPDIR)/rawmidi.Po + -rm -f ./$(DEPDIR)/seq.Po + -rm -f ./$(DEPDIR)/timer.Po + -rm -f ./$(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Po + -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 -f ./$(DEPDIR)/audio_time.Po + -rm -f ./$(DEPDIR)/chmap.Po + -rm -f ./$(DEPDIR)/client_event_filter.Po + -rm -f ./$(DEPDIR)/control.Po + -rm -f ./$(DEPDIR)/latency.Po + -rm -f ./$(DEPDIR)/midiloop.Po + -rm -f ./$(DEPDIR)/namehint.Po + -rm -f ./$(DEPDIR)/oldapi.Po + -rm -f ./$(DEPDIR)/pcm-multi-thread.Po + -rm -f ./$(DEPDIR)/pcm.Po + -rm -f ./$(DEPDIR)/pcm_min.Po + -rm -f ./$(DEPDIR)/playmidi1.Po + -rm -f ./$(DEPDIR)/queue_timer.Po + -rm -f ./$(DEPDIR)/rawmidi.Po + -rm -f ./$(DEPDIR)/seq.Po + -rm -f ./$(DEPDIR)/timer.Po + -rm -f ./$(DEPDIR)/user_ctl_element_set-user-ctl-element-set.Po + -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: $(am__recursive_targets) check-am install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-checkPROGRAMS \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + 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-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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/audio_time.c b/test/audio_time.c new file mode 100644 index 0000000..530922d --- /dev/null +++ b/test/audio_time.c @@ -0,0 +1,451 @@ +/* + * This program only tracks the difference between system time + * and audio time, as reported in snd_pcm_status(). It should be + * helpful to verify the information reported by drivers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/asoundlib.h" + +static char *command; +static char *pcm_name = "hw:0"; +snd_output_t *output = NULL; + +static void usage(char *command) +{ + printf("Usage: %s [OPTION]... \n" + "\n" + "-h, --help help\n" + "-c, --capture capture tstamps \n" + "-d, --delay add delay \n" + "-D, --device=NAME select PCM by name \n" + "-p, --playback playback tstamps \n" + "-t, --ts_type=TYPE Default(0),link(1),link_estimated(2),synchronized(3) \n" + "-r, --report show audio timestamp and accuracy validity\n" + , command); +} + + +long long timestamp2ns(snd_htimestamp_t t) +{ + long long nsec; + + nsec = t.tv_sec * 1000000000; + nsec += t.tv_nsec; + + return nsec; +} + +long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2) +{ + long long nsec1, nsec2; + + nsec1 = timestamp2ns(t1); + nsec2 = timestamp2ns(t2); + + return nsec1 - nsec2; +} + +void _gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp, + snd_htimestamp_t *trigger_timestamp, + snd_htimestamp_t *audio_timestamp, + snd_pcm_audio_tstamp_config_t *audio_tstamp_config, + snd_pcm_audio_tstamp_report_t *audio_tstamp_report, + snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay) +{ + int err; + snd_pcm_status_t *status; + + snd_pcm_status_alloca(&status); + + snd_pcm_status_set_audio_htstamp_config(status, audio_tstamp_config); + + if ((err = snd_pcm_status(handle, status)) < 0) { + printf("Stream status error: %s\n", snd_strerror(err)); + exit(0); + } + snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp); + snd_pcm_status_get_htstamp(status, timestamp); + snd_pcm_status_get_audio_htstamp(status, audio_timestamp); + snd_pcm_status_get_audio_htstamp_report(status, audio_tstamp_report); + *avail = snd_pcm_status_get_avail(status); + *delay = snd_pcm_status_get_delay(status); +} + +#define TIMESTAMP_FREQ 8 /* Hz */ +#define SAMPLE_FREQ 48000 +#define PERIOD (SAMPLE_FREQ/TIMESTAMP_FREQ) +#define PCM_LINK /* sync start for playback and capture */ +#define TRACK_CAPTURE /* dump capture timing info */ +#define TRACK_PLAYBACK /* dump playback timing info */ +/*#define TRACK_SAMPLE_COUNTS */ /* show difference between sample counters and audiotimestamps returned by driver */ +#define PLAYBACK_BUFFERS 4 +#define TSTAMP_TYPE SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW + + +int main(int argc, char *argv[]) +{ + int c; + int err; + unsigned int i; + snd_pcm_t *handle_p = NULL; + snd_pcm_t *handle_c = NULL; + snd_pcm_sframes_t frames; + snd_htimestamp_t tstamp_c, tstamp_p; + snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p; + snd_htimestamp_t audio_tstamp_c, audio_tstamp_p; + unsigned char buffer_p[PERIOD*4*4]; + unsigned char buffer_c[PERIOD*4*4]; + + snd_pcm_hw_params_t *hwparams_p; + snd_pcm_hw_params_t *hwparams_c; + + snd_pcm_sw_params_t *swparams_p; + snd_pcm_sw_params_t *swparams_c; + + snd_pcm_uframes_t frame_count_c = 0; + snd_pcm_uframes_t frame_count_p = 0; + + snd_pcm_sframes_t delay_p, delay_c; + snd_pcm_uframes_t avail_p, avail_c; + + snd_pcm_audio_tstamp_config_t audio_tstamp_config_p; + snd_pcm_audio_tstamp_config_t audio_tstamp_config_c; + snd_pcm_audio_tstamp_report_t audio_tstamp_report_p; + snd_pcm_audio_tstamp_report_t audio_tstamp_report_c; + + int option_index; + static const char short_options[] = "hcpdrD:t:"; + + static const struct option long_options[] = { + {"capture", 0, 0, 'c'}, + {"delay", 0, 0, 'd'}, + {"device", required_argument, 0, 'D'}, + {"help", no_argument, 0, 'h'}, + {"playback", 0, 0, 'p'}, + {"ts_type", required_argument, 0, 't'}, + {"report", 0, 0, 'r'}, + {0, 0, 0, 0} + }; + + int do_delay = 0; + int do_playback = 0; + int do_capture = 0; + int type = 0; + int do_report = 0; + + while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) { + switch (c) { + case 'h': + usage(command); + return 0; + case 'p': + do_playback = 1; + break; + case 'c': + do_capture = 1; + break; + case 'd': + do_delay = 1; + break; + case 'D': + pcm_name = optarg; + break; + case 't': + type = atoi(optarg); + break; + case 'r': + do_report = 1; + } + } + + memset(&audio_tstamp_config_p, 0, sizeof(snd_pcm_audio_tstamp_config_t)); + memset(&audio_tstamp_config_c, 0, sizeof(snd_pcm_audio_tstamp_config_t)); + memset(&audio_tstamp_report_p, 0, sizeof(snd_pcm_audio_tstamp_report_t)); + memset(&audio_tstamp_report_c, 0, sizeof(snd_pcm_audio_tstamp_report_t)); + + if (do_playback) { + if ((err = snd_pcm_open(&handle_p, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + printf("Playback open error: %s\n", snd_strerror(err)); + goto _exit; + } + + if ((err = snd_pcm_set_params(handle_p, + SND_PCM_FORMAT_S16, + SND_PCM_ACCESS_RW_INTERLEAVED, + 2, + SAMPLE_FREQ, + 0, + 4*1000000/TIMESTAMP_FREQ)) < 0) { + printf("Playback open error: %s\n", snd_strerror(err)); + goto _exit; + } + + snd_pcm_hw_params_alloca(&hwparams_p); +/* get the current hwparams */ + err = snd_pcm_hw_params_current(handle_p, hwparams_p); + if (err < 0) { + printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err)); + goto _exit; + } + + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 0)) + printf("Playback supports audio compat timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 1)) + printf("Playback supports audio default timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 2)) + printf("Playback supports audio link timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 3)) + printf("Playback supports audio link absolute timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 4)) + printf("Playback supports audio link estimated timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 5)) + printf("Playback supports audio link synchronized timestamps\n"); + + snd_pcm_sw_params_alloca(&swparams_p); + /* get the current swparams */ + err = snd_pcm_sw_params_current(handle_p, swparams_p); + if (err < 0) { + printf("Unable to determine current swparams_p: %s\n", snd_strerror(err)); + goto _exit; + } + + /* enable tstamp */ + err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE); + if (err < 0) { + printf("Unable to set tstamp mode : %s\n", snd_strerror(err)); + goto _exit; + } + + err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE); + if (err < 0) { + printf("Unable to set tstamp type : %s\n", snd_strerror(err)); + goto _exit; + } + + /* write the sw parameters */ + err = snd_pcm_sw_params(handle_p, swparams_p); + if (err < 0) { + printf("Unable to set swparams_p : %s\n", snd_strerror(err)); + goto _exit; + } + + } + + if (do_capture) { + + if ((err = snd_pcm_open(&handle_c, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { + printf("Capture open error: %s\n", snd_strerror(err)); + goto _exit; + } + if ((err = snd_pcm_set_params(handle_c, + SND_PCM_FORMAT_S16, + SND_PCM_ACCESS_RW_INTERLEAVED, + 2, + SAMPLE_FREQ, + 0, + 4*1000000/TIMESTAMP_FREQ)) < 0) { + printf("Capture open error: %s\n", snd_strerror(err)); + goto _exit; + } + + snd_pcm_hw_params_alloca(&hwparams_c); + /* get the current hwparams */ + err = snd_pcm_hw_params_current(handle_c, hwparams_c); + if (err < 0) { + printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err)); + goto _exit; + } + + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 0)) + printf("Capture supports audio compat timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 1)) + printf("Capture supports audio default timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 2)) + printf("Capture supports audio link timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 3)) + printf("Capture supports audio link absolute timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 4)) + printf("Capture supports audio link estimated timestamps\n"); + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 5)) + printf("Capture supports audio link synchronized timestamps\n"); + + snd_pcm_sw_params_alloca(&swparams_c); + /* get the current swparams */ + err = snd_pcm_sw_params_current(handle_c, swparams_c); + if (err < 0) { + printf("Unable to determine current swparams_c: %s\n", snd_strerror(err)); + goto _exit; + } + + /* enable tstamp */ + err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE); + if (err < 0) { + printf("Unable to set tstamp mode : %s\n", snd_strerror(err)); + goto _exit; + } + + err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE); + if (err < 0) { + printf("Unable to set tstamp type : %s\n", snd_strerror(err)); + goto _exit; + } + + /* write the sw parameters */ + err = snd_pcm_sw_params(handle_c, swparams_c); + if (err < 0) { + printf("Unable to set swparams_c : %s\n", snd_strerror(err)); + goto _exit; + } + } + + if (do_playback && do_capture) { +#ifdef PCM_LINK + if ((err = snd_pcm_link(handle_c, handle_p)) < 0) { + printf("Streams link error: %s\n", snd_strerror(err)); + exit(0); + } +#endif + } + + if (do_playback) { + i = PLAYBACK_BUFFERS; + while (i--) { + frames = snd_pcm_writei(handle_p, buffer_p, PERIOD); + if (frames < 0) { + printf("snd_pcm_writei failed: %s\n", snd_strerror(frames)); + goto _exit; + } + frame_count_p += frames; + } + + if (PLAYBACK_BUFFERS != 4) + snd_pcm_start(handle_p); + } + + if (do_capture) { +#ifndef PCM_LINK + /* need to start capture explicitly */ + snd_pcm_start(handle_c); +#else + if (!do_playback) + /* need to start capture explicitly */ + snd_pcm_start(handle_c); +#endif + } + + while (1) { + + if (do_capture) { + + frames = snd_pcm_wait(handle_c, -1); + if (frames < 0) { + printf("snd_pcm_wait failed: %s\n", snd_strerror(frames)); + goto _exit; + } + + frames = snd_pcm_readi(handle_c, buffer_c, PERIOD); + if (frames < 0) { + printf("snd_pcm_readi failed: %s\n", snd_strerror(frames)); + goto _exit; + } + frame_count_c += frames; + +#if defined(TRACK_CAPTURE) + audio_tstamp_config_c.type_requested = type; + audio_tstamp_config_c.report_delay = do_delay; + _gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, + &audio_tstamp_c, &audio_tstamp_config_c, &audio_tstamp_report_c, + &avail_c, &delay_c); +#if defined(TRACK_SAMPLE_COUNTS) + curr_count_c = frame_count_c + delay_c; /* read plus queued */ + + + printf("capture: curr_count %lli driver count %lli, delta %lli\n", + (long long)curr_count_c * 1000000000LL / SAMPLE_FREQ , + timestamp2ns(audio_tstamp_c), + (long long)curr_count_c * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_c) + ); +#endif + if (do_report) { + if (audio_tstamp_report_c.valid == 0) + printf("Audio capture timestamp report invalid - "); + if (audio_tstamp_report_c.accuracy_report == 0) + printf("Audio capture timestamp accuracy report invalid"); + printf("\n"); + } + + + printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli \t resolution %d ns \n", + timediff(tstamp_c, trigger_tstamp_c), + timestamp2ns(audio_tstamp_c), + timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c), audio_tstamp_report_c.accuracy + ); +#endif + } + + if (do_playback) { + frames = snd_pcm_writei(handle_p, buffer_p, PERIOD); + if (frames < 0) { + printf("snd_pcm_writei failed: %s\n", snd_strerror(frames)); + goto _exit; + } + + frame_count_p += frames; + +#if defined(TRACK_PLAYBACK) + + audio_tstamp_config_p.type_requested = type; + audio_tstamp_config_p.report_delay = do_delay; + _gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, + &audio_tstamp_p, &audio_tstamp_config_p, &audio_tstamp_report_p, + &avail_p, &delay_p); + +#if defined(TRACK_SAMPLE_COUNTS) + curr_count_p = frame_count_p - delay_p; /* written minus queued */ + + printf("playback: curr_count %lli driver count %lli, delta %lli\n", + (long long)curr_count_p * 1000000000LL / SAMPLE_FREQ , + timestamp2ns(audio_tstamp_p), + (long long)curr_count_p * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_p) + ); +#endif + if (do_report) { + if (audio_tstamp_report_p.valid == 0) + printf("Audio playback timestamp report invalid - "); + if (audio_tstamp_report_p.accuracy_report == 0) + printf("Audio playback timestamp accuracy report invalid"); + printf("\n"); + } + + printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli resolution %d ns\n", + timediff(tstamp_p, trigger_tstamp_p), + timestamp2ns(audio_tstamp_p), + timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p), audio_tstamp_report_p.accuracy + ); +#endif + } + + + } /* while(1) */ + +_exit: + if (handle_p) + snd_pcm_close(handle_p); + if (handle_c) + snd_pcm_close(handle_c); + + return 0; +} diff --git a/test/chmap.c b/test/chmap.c new file mode 100644 index 0000000..ad3b305 --- /dev/null +++ b/test/chmap.c @@ -0,0 +1,214 @@ +/* + * channel mapping API test program + */ + +#include +#include +#include +#include +#include +#include "../include/asoundlib.h" + +static void usage(void) +{ + printf("usage: chmap [options] query\n" + " chmap [options] get\n" + " chmap [options] set CH0 CH1 CH2...\n" + "options:\n" + " -D device Specify PCM device to handle\n" + " -s stream Specify PCM stream direction (playback/capture)\n" + " -f format PCM format\n" + " -c channels Channels\n" + " -r rate Sample rate\n"); +} + +static void print_channels(const snd_pcm_chmap_t *map) +{ + char tmp[128]; + if (snd_pcm_chmap_print(map, sizeof(tmp), tmp) > 0) + printf(" %s\n", tmp); +} + +static int query_chmaps(snd_pcm_t *pcm) +{ + snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps(pcm); + snd_pcm_chmap_query_t **p, *v; + + if (!maps) { + printf("Cannot query maps\n"); + return 1; + } + for (p = maps; (v = *p) != NULL; p++) { + printf("Type = %s, Channels = %d\n", + snd_pcm_chmap_type_name(v->type), + v->map.channels); + print_channels(&v->map); + } + snd_pcm_free_chmaps(maps); + return 0; +} + +static int setup_pcm(snd_pcm_t *pcm, int format, int channels, int rate) +{ + snd_pcm_hw_params_t *params; + + snd_pcm_hw_params_alloca(¶ms); + if (snd_pcm_hw_params_any(pcm, params) < 0) { + printf("Cannot init hw_params\n"); + return -1; + } + if (format != SND_PCM_FORMAT_UNKNOWN) { + if (snd_pcm_hw_params_set_format(pcm, params, format) < 0) { + printf("Cannot set format %s\n", + snd_pcm_format_name(format)); + return -1; + } + } + if (channels > 0) { + if (snd_pcm_hw_params_set_channels(pcm, params, channels) < 0) { + printf("Cannot set channels %d\n", channels); + return -1; + } + } + if (rate > 0) { + if (snd_pcm_hw_params_set_rate_near(pcm, params, (unsigned int *)&rate, 0) < 0) { + printf("Cannot set rate %d\n", rate); + return -1; + } + } + if (snd_pcm_hw_params(pcm, params) < 0) { + printf("Cannot set hw_params\n"); + return -1; + } + return 0; +} + +static int get_chmap(snd_pcm_t *pcm, int format, int channels, int rate) +{ + snd_pcm_chmap_t *map; + + if (setup_pcm(pcm, format, channels, rate)) + return 1; + map = snd_pcm_get_chmap(pcm); + if (!map) { + printf("Cannot get chmap\n"); + return 1; + } + printf("Channels = %d\n", map->channels); + print_channels(map); + free(map); + return 0; +} + +static int set_chmap(snd_pcm_t *pcm, int format, int channels, int rate, + int nargs, char **arg) +{ + int i; + snd_pcm_chmap_t *map; + + if (channels && channels != nargs) { + printf("Inconsistent channels %d vs %d\n", channels, nargs); + return 1; + } + if (!channels) { + if (!nargs) { + printf("No channels are given\n"); + return 1; + } + channels = nargs; + } + if (setup_pcm(pcm, format, channels, rate)) + return 1; + map = malloc(sizeof(int) * (channels + 1)); + if (!map) { + printf("cannot malloc\n"); + return 1; + } + map->channels = channels; + for (i = 0; i < channels; i++) { + int val = snd_pcm_chmap_from_string(arg[i]); + if (val < 0) + val = SND_CHMAP_UNKNOWN; + map->pos[i] = val; + } + if (snd_pcm_set_chmap(pcm, map) < 0) { + printf("Cannot set chmap\n"); + return 1; + } + free(map); + + map = snd_pcm_get_chmap(pcm); + if (!map) { + printf("Cannot get chmap\n"); + return 1; + } + printf("Get channels = %d\n", map->channels); + print_channels(map); + free(map); + return 0; +} + +int main(int argc, char **argv) +{ + char *device = NULL; + int stream = SND_PCM_STREAM_PLAYBACK; + int format = SND_PCM_FORMAT_UNKNOWN; + int channels = 0; + int rate = 0; + snd_pcm_t *pcm; + int c; + + while ((c = getopt(argc, argv, "D:s:f:c:r:")) != -1) { + switch (c) { + case 'D': + device = optarg; + break; + case 's': + if (*optarg == 'c' || *optarg == 'C') + stream = SND_PCM_STREAM_CAPTURE; + else + stream = SND_PCM_STREAM_PLAYBACK; + break; + case 'f': + format = snd_pcm_format_value(optarg); + break; + case 'c': + channels = atoi(optarg); + break; + case 'r': + rate = atoi(optarg); + break; + default: + usage(); + return 1; + } + } + + if (argc <= optind) { + usage(); + return 1; + } + + if (!device) { + printf("No device is specified\n"); + return 1; + } + + if (snd_pcm_open(&pcm, device, stream, SND_PCM_NONBLOCK) < 0) { + printf("Cannot open PCM stream %s for %s\n", device, + snd_pcm_stream_name(stream)); + return 1; + } + + switch (*argv[optind]) { + case 'q': + return query_chmaps(pcm); + case 'g': + return get_chmap(pcm, format, channels, rate); + case 's': + return set_chmap(pcm, format, channels, rate, + argc - optind - 1, argv + optind + 1); + } + usage(); + return 1; +} 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..298bab8 --- /dev/null +++ b/test/latency.c @@ -0,0 +1,702 @@ +/* + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; + unsigned int val; + + 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) { + snd_pcm_hw_params_get_periods_min(p_params, &val, NULL); + if (val > 2) { + printf("playback device does not support 2 periods per buffer\n"); + exit(0); + } + goto __again; + } + snd_pcm_hw_params_get_buffer_size(c_params, &c_size); + if (c_psize * 2 < c_size) { + snd_pcm_hw_params_get_periods_min(c_params, &val, NULL); + if (val > 2 ) { + printf("capture device does not support 2 periods per buffer\n"); + exit(0); + } + 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; + int frame_bytes = (snd_pcm_format_width(format) / 8) * channels; + + 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 * frame_bytes; + 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 %lu 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 == c_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..40f27a5 --- /dev/null +++ b/test/lsb/Makefile.in @@ -0,0 +1,1004 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +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_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +midi_event_SOURCES = midi_event.c +midi_event_OBJECTS = midi_event.$(OBJEXT) +midi_event_LDADD = $(LDADD) +midi_event_DEPENDENCIES = ../../src/libasound.la +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/config.Po ./$(DEPDIR)/midi_event.Po +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_CC_1 = +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_CCLD_1 = +SOURCES = config.c midi_event.c +DIST_SOURCES = config.c midi_event.c +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ + $(top_srcdir)/test-driver +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 .log .o .obj .test .test$(EXEEXT) .trs +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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) $(EXTRA_config_DEPENDENCIES) + @rm -f config$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(config_OBJECTS) $(config_LDADD) $(LIBS) + +midi_event$(EXEEXT): $(midi_event_OBJECTS) $(midi_event_DEPENDENCIES) $(EXTRA_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@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midi_event.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.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 -o $@ $< + +.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 -o $@ `$(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: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: $(check_PROGRAMS) + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all $(check_PROGRAMS) + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +config.log: config$(EXEEXT) + @p='config$(EXEEXT)'; \ + b='config'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +midi_event.log: midi_event$(EXEEXT) + @p='midi_event$(EXEEXT)'; \ + b='midi_event'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +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 -f ./$(DEPDIR)/config.Po + -rm -f ./$(DEPDIR)/midi_event.Po + -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 -f ./$(DEPDIR)/config.Po + -rm -f ./$(DEPDIR)/midi_event.Po + -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 TAGS all all-am am--depfiles check check-TESTS \ + check-am clean clean-checkPROGRAMS clean-generic clean-libtool \ + cscopelist-am ctags ctags-am 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 \ + recheck tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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..3d72b9f --- /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 %lu, old_tempo %lu]\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 %lu, new_tempo %lu]\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 %lu - old %lu, div %d, tempo %lu) = %.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=%lu ticks ( = %lu 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 %lu - old %lu, div %d, tempo %lu) = %.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=%lu ticks ( = %lu 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..d6548b5 --- /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 = %zi\n", snd_rawmidi_status_get_avail(istat)); + printf("input.status.xruns = %zi\n", snd_rawmidi_status_get_xruns(istat)); + printf("output.status.avail = %zi\n", snd_rawmidi_status_get_avail(ostat)); + printf("output.status.xruns = %zi\n", snd_rawmidi_status_get_xruns(ostat)); + + diff = timediff(end, start); + printf("Time diff: %lliusec (%lli 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..7abc98e --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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-multi-thread.c b/test/pcm-multi-thread.c new file mode 100644 index 0000000..da1b87c --- /dev/null +++ b/test/pcm-multi-thread.c @@ -0,0 +1,263 @@ +/* + * simple multi-thread stress test for PCM + * + * The main thread simply feeds or reads the sample data with the + * random size continuously. Meanwhile, the worker threads call some + * update function depending on the given mode, and show the thread + * number of the read value. + * + * The function for the worker thread is specified via -m option. + * When the random mode ('r') is set, the update function is chosen + * randomly in the loop. + * + * When the -v option is passed, this tries to show some obtained value + * from the function. Without -v, as default, it shows the thread number + * (0-9). In addition, it puts the mode suffix ('a' for avail, 'd' for + * delay, etc) for the random mode, as well as the suffix '!' indicating + * the error from the called function. + */ + +#include +#include +#include +#include "../include/asoundlib.h" + +#define MAX_THREADS 10 + +enum { + MODE_AVAIL_UPDATE, + MODE_STATUS, + MODE_HWSYNC, + MODE_TIMESTAMP, + MODE_DELAY, + MODE_RANDOM +}; + +static char mode_suffix[] = { + 'a', 's', 'h', 't', 'd', 'r' +}; + +static const char *devname = "default"; +static int stream = SND_PCM_STREAM_PLAYBACK; +static int num_threads = 1; +static int periodsize = 16 * 1024; +static int bufsize = 16 * 1024 * 4; +static int channels = 2; +static int rate = 48000; +static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; + +static int running_mode = MODE_AVAIL_UPDATE; +static int show_value = 0; +static int quiet = 0; + +static pthread_t peeper_threads[MAX_THREADS]; +static int running = 1; +static snd_pcm_t *pcm; + +static void *peeper(void *data) +{ + int thread_no = (long)data; + snd_pcm_sframes_t val; + snd_pcm_status_t *stat; + snd_htimestamp_t tstamp; + int mode = running_mode, err; + + snd_pcm_status_alloca(&stat); + + while (running) { + if (running_mode == MODE_RANDOM) + mode = rand() % MODE_RANDOM; + switch (mode) { + case MODE_AVAIL_UPDATE: + val = snd_pcm_avail_update(pcm); + err = 0; + break; + case MODE_STATUS: + err = snd_pcm_status(pcm, stat); + val = snd_pcm_status_get_avail(stat); + break; + case MODE_HWSYNC: + err = snd_pcm_hwsync(pcm); + break; + case MODE_TIMESTAMP: + err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val, + &tstamp); + break; + default: + err = snd_pcm_delay(pcm, &val); + break; + } + + if (quiet) + continue; + if (running_mode == MODE_RANDOM) { + fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode], + err ? "!" : ""); + } else { + if (show_value && mode != MODE_HWSYNC) + fprintf(stderr, "\r%d ", (int)val); + else + fprintf(stderr, "%d%s", thread_no, + err ? "!" : ""); + } + } + return NULL; +} + +static void usage(void) +{ + fprintf(stderr, "usage: multi-thread [-options]\n"); + fprintf(stderr, " -D str Set device name\n"); + fprintf(stderr, " -r val Set sample rate\n"); + fprintf(stderr, " -p val Set period size (in frame)\n"); + fprintf(stderr, " -b val Set buffer size (in frame)\n"); + fprintf(stderr, " -c val Set number of channels\n"); + fprintf(stderr, " -f str Set PCM format\n"); + fprintf(stderr, " -s str Set stream direction (playback or capture)\n"); + fprintf(stderr, " -t val Set number of threads\n"); + fprintf(stderr, " -m str Running mode (avail, status, hwsync, timestamp, delay, random)\n"); + fprintf(stderr, " -v Show value\n"); + fprintf(stderr, " -q Quiet mode\n"); +} + +static int parse_options(int argc, char **argv) +{ + int c, i; + + while ((c = getopt(argc, argv, "D:r:f:p:b:s:t:m:vq")) >= 0) { + switch (c) { + case 'D': + devname = optarg; + break; + case 'r': + rate = atoi(optarg); + break; + case 'p': + periodsize = atoi(optarg); + break; + case 'b': + bufsize = atoi(optarg); + break; + case 'c': + channels = atoi(optarg); + break; + case 'f': + format = snd_pcm_format_value(optarg); + break; + case 's': + if (*optarg == 'p' || *optarg == 'P') + stream = SND_PCM_STREAM_PLAYBACK; + else if (*optarg == 'c' || *optarg == 'C') + stream = SND_PCM_STREAM_CAPTURE; + else { + fprintf(stderr, "invalid stream direction\n"); + return 1; + } + break; + case 't': + num_threads = atoi(optarg); + if (num_threads < 1 || num_threads > MAX_THREADS) { + fprintf(stderr, "invalid number of threads\n"); + return 1; + } + break; + case 'm': + for (i = 0; i <= MODE_RANDOM; i++) + if (mode_suffix[i] == *optarg) + break; + if (i > MODE_RANDOM) { + fprintf(stderr, "invalid mode type\n"); + return 1; + } + running_mode = i; + break; + case 'v': + show_value = 1; + break; + case 'q': + quiet = 1; + break; + default: + usage(); + return 1; + } + } + return 0; +} + +static int setup_params(void) +{ + snd_pcm_hw_params_t *hw; + + /* FIXME: more finer error checks */ + snd_pcm_hw_params_alloca(&hw); + snd_pcm_hw_params_any(pcm, hw); + snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_format(pcm, hw, format); + snd_pcm_hw_params_set_channels(pcm, hw, channels); + snd_pcm_hw_params_set_rate(pcm, hw, rate, 0); + snd_pcm_hw_params_set_period_size(pcm, hw, periodsize, 0); + snd_pcm_hw_params_set_buffer_size(pcm, hw, bufsize); + if (snd_pcm_hw_params(pcm, hw) < 0) { + fprintf(stderr, "snd_pcm_hw_params error\n"); + return 1; + } + return 0; +} + +int main(int argc, char **argv) +{ + char *buf; + int i, err; + + if (parse_options(argc, argv)) + return 1; + + err = snd_pcm_open(&pcm, devname, stream, 0); + if (err < 0) { + fprintf(stderr, "cannot open pcm %s\n", devname); + return 1; + } + + if (setup_params()) + return 1; + + buf = calloc(1, snd_pcm_format_size(format, bufsize) * channels); + if (!buf) { + fprintf(stderr, "cannot alloc buffer\n"); + return 1; + } + + for (i = 0; i < num_threads; i++) { + if (pthread_create(&peeper_threads[i], NULL, peeper, (void *)(long)i)) { + fprintf(stderr, "pthread_create error\n"); + return 1; + } + } + + if (stream == SND_PCM_STREAM_CAPTURE) + snd_pcm_start(pcm); + for (;;) { + int size = rand() % (bufsize / 2); + if (stream == SND_PCM_STREAM_PLAYBACK) + err = snd_pcm_writei(pcm, buf, size); + else + err = snd_pcm_readi(pcm, buf, size); + if (err < 0) { + fprintf(stderr, "read/write error %d\n", err); + err = snd_pcm_recover(pcm, err, 0); + if (err < 0) + break; + if (stream == SND_PCM_STREAM_CAPTURE) + snd_pcm_start(pcm); + } + } + + running = 0; + for (i = 0; i < num_threads; i++) + pthread_cancel(peeper_threads[i]); + for (i = 0; i < num_threads; i++) + pthread_join(peeper_threads[i], NULL); + + return 1; +} diff --git a/test/pcm.c b/test/pcm.c new file mode 100644 index 0000000..b8d4fe6 --- /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[%u].first == %u, 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[%u].step == %u, 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); + 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 (%u) 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 %uHz not available for playback: %s\n", rate, snd_strerror(err)); + return err; + } + if (rrate != rate) { + printf("Rate doesn't match (requested %uHz, 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 %u 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 %u 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 %uHz, %s, %u 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..7462a45 --- /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(frames)); + 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..f178279 --- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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("%lu: 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("%lu: 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("%lu: 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("%lu: 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("%lu: 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("%lu: 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("%lu: 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("%lu: 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); + + /* Enable timestamping for events sent by external subscribers. */ + snd_seq_port_info_set_timestamping(pinfo, 1); + snd_seq_port_info_set_timestamp_real(pinfo, 1); + snd_seq_port_info_set_timestamp_queue(pinfo, queue); + + 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/test/user-ctl-element-set.c b/test/user-ctl-element-set.c new file mode 100644 index 0000000..fee130e --- /dev/null +++ b/test/user-ctl-element-set.c @@ -0,0 +1,898 @@ +/* + * user-control-element-set.c - a program to test in-kernel implementation of + * user-defined control element set. + * + * Copyright (c) 2015-2016 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "../include/asoundlib.h" +#include +#include + +struct elem_set_trial { + snd_ctl_t *handle; + + snd_ctl_elem_type_t type; + unsigned int member_count; + unsigned int element_count; + + snd_ctl_elem_id_t *id; + + int (*add_elem_set)(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info); + int (*check_elem_props)(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info); + void (*change_elem_members)(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data); + int (*allocate_elem_set_tlv)(struct elem_set_trial *trial, + unsigned int **tlv); + + bool tlv_readable; +}; + +struct chmap_entry { + unsigned int type; + unsigned int length; + unsigned int maps[0]; +}; + +/* + * History of TLV feature: + * + * 2016/09/15: 398fa4db6c69 ("ALSA: control: move layout of TLV payload to UAPI + * header") + * 2012/07/21: 2d3391ec0ecc ("ALSA: PCM: channel mapping API implementation") + * 2011/11/20: bf1d1c9b6179 ("ALSA: tlv: add DECLARE_TLV_DB_RANGE()") + * 2009/07/16: 085f30654175 ("ALSA: Add new TLV types for dBwith min/max") + * 2006/09/06: 55a29af5ed5d ("[ALSA] Add definition of TLV dB range compound") + * 2006/08/28: 063a40d9111c ("Add the definition of linear volume TLV") + * 2006/08/28: 42750b04c5ba ("[ALSA] Control API - TLV implementation for + * additional information like dB scale") + */ + +/* Operations for elements in an element set with boolean type. */ +static int add_bool_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + return snd_ctl_add_boolean_elem_set(trial->handle, info, + trial->element_count, trial->member_count); +} + +static void change_bool_elem_members(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data) +{ + int val; + unsigned int i; + + for (i = 0; i < trial->member_count; ++i) { + val = snd_ctl_elem_value_get_boolean(elem_data, i); + snd_ctl_elem_value_set_boolean(elem_data, i, !val); + } +} + +static int allocate_bool_elem_set_tlv(struct elem_set_trial *trial, + unsigned int **tlv) +{ + /* + * Performs like a toggle switch for attenuation, because they're bool + * elements. + */ + static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(range, -10000, 0); + + *tlv = malloc(sizeof(range)); + if (*tlv == NULL) + return -ENOMEM; + memcpy(*tlv, range, sizeof(range)); + + return 0; +} + +/* Operations for elements in an element set with integer type. */ +static int add_int_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + return snd_ctl_add_integer_elem_set(trial->handle, info, + trial->element_count, trial->member_count, + 0, 25, 1); +} + +static int check_int_elem_props(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + if (snd_ctl_elem_info_get_min(info) != 0) + return -EIO; + if (snd_ctl_elem_info_get_max(info) != 25) + return -EIO; + if (snd_ctl_elem_info_get_step(info) != 1) + return -EIO; + + return 0; +} + +static void change_int_elem_members(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data) +{ + long val; + unsigned int i; + + for (i = 0; i < trial->member_count; ++i) { + val = snd_ctl_elem_value_get_integer(elem_data, i); + snd_ctl_elem_value_set_integer(elem_data, i, ++val); + } +} + +static int allocate_int_elem_set_tlv(struct elem_set_trial *trial, + unsigned int **tlv) +{ + unsigned int count, pos; + unsigned int i, j; + struct chmap_entry *entry; + + /* Calculate size of TLV packet for channel-mapping information. */ + count = 0; + for (i = 1; i <= 25; ++i) { + count += 2; /* sizeof(struct chmap_entry). */ + count += i; /* struct chmap_entry.maps. */ + } + + *tlv = malloc((2 + count) * sizeof(unsigned int)); + if (!*tlv) + return -ENOMEM; + + /* + * Emulate channel-mapping information in in-kernel implementation. + * Here, 25 entries are for each different channel. + */ + (*tlv)[0] = SNDRV_CTL_TLVT_CONTAINER; + (*tlv)[1] = count * sizeof(unsigned int); + pos = 2; + + for (i = 1; i <= 25 && pos < count; ++i) { + entry = (struct chmap_entry *)&(*tlv)[pos]; + + entry->type = SNDRV_CTL_TLVT_CHMAP_FIXED; + entry->length = i * sizeof(unsigned int); + pos += 2; + + for (j = 0; j < i; ++j) + entry->maps[j] = SND_CHMAP_MONO + j; + pos += i; + } + + return 0; +} + +/* Operations for elements in an element set with enumerated type. */ +static const char *const labels[] = { + "trusty", + "utopic", + "vivid", + "willy", + "xenial", +}; + +static int add_enum_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + return snd_ctl_add_enumerated_elem_set(trial->handle, info, + trial->element_count, trial->member_count, + sizeof(labels) / sizeof(labels[0]), + labels); +} + +static int check_enum_elem_props(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + unsigned int items; + unsigned int i; + const char *label; + int err; + + items = snd_ctl_elem_info_get_items(info); + if (items != sizeof(labels) / sizeof(labels[0])) + return -EIO; + + /* Enumerate and validate all of labels registered to this element. */ + for (i = 0; i < items; ++i) { + snd_ctl_elem_info_set_item(info, i); + err = snd_ctl_elem_info(trial->handle, info); + if (err < 0) + return err; + + label = snd_ctl_elem_info_get_item_name(info); + if (strncmp(label, labels[i], strlen(labels[i])) != 0) + return -EIO; + } + + return 0; +} + +static void change_enum_elem_members(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data) +{ + unsigned int val; + unsigned int i; + + for (i = 0; i < trial->member_count; ++i) { + val = snd_ctl_elem_value_get_enumerated(elem_data, i); + snd_ctl_elem_value_set_enumerated(elem_data, i, ++val); + } +} + +/* Operations for elements in an element set with bytes type. */ +static int add_bytes_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + return snd_ctl_add_bytes_elem_set(trial->handle, info, + trial->element_count, trial->member_count); +} + +static void change_bytes_elem_members(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data) +{ + unsigned char val; + unsigned int i; + + for (i = 0; i < trial->member_count; ++i) { + val = snd_ctl_elem_value_get_byte(elem_data, i); + snd_ctl_elem_value_set_byte(elem_data, i, ++val); + } +} + +static int allocate_bytes_elem_set_tlv(struct elem_set_trial *trial, + unsigned int **tlv) +{ + /* + * Emulate AK4396. + * 20 * log10(x/255) (dB) + * Here, x is written value. + */ + static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(range, -4813, 0); + + *tlv = malloc(sizeof(range)); + if (*tlv == NULL) + return -ENOMEM; + memcpy(*tlv, range, sizeof(range)); + + return 0; +} + +/* Operations for elements in an element set with iec958 type. */ +static int add_iec958_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + int err; + + snd_ctl_elem_info_get_id(info, trial->id); + + err = snd_ctl_elem_add_iec958(trial->handle, trial->id); + if (err < 0) + return err; + + /* + * In historical reason, the above API is not allowed to fill all of + * fields in identification data. + */ + return snd_ctl_elem_info(trial->handle, info); +} + +static void change_iec958_elem_members(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data) +{ + snd_aes_iec958_t data; + + /* To suppress GCC warnings. */ + trial->element_count = 1; + + snd_ctl_elem_value_get_iec958(elem_data, &data); + /* This is an arbitrary number. */ + data.pad = 10; + snd_ctl_elem_value_set_iec958(elem_data, &data); +} + +/* Operations for elements in an element set with integer64 type. */ +static int add_int64_elem_set(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + return snd_ctl_add_integer64_elem_set(trial->handle, info, + trial->element_count, trial->member_count, + 0, 10000, 1); +} + +static int check_int64_elem_props(struct elem_set_trial *trial, + snd_ctl_elem_info_t *info) +{ + if (snd_ctl_elem_info_get_min64(info) != 0) + return -EIO; + if (snd_ctl_elem_info_get_max64(info) != 10000) + return -EIO; + if (snd_ctl_elem_info_get_step64(info) != 1) + return -EIO; + + return 0; +} + +static void change_int64_elem_members(struct elem_set_trial *trial, + snd_ctl_elem_value_t *elem_data) +{ + long long val; + unsigned int i; + + for (i = 0; i < trial->member_count; ++i) { + val = snd_ctl_elem_value_get_integer64(elem_data, i); + snd_ctl_elem_value_set_integer64(elem_data, i, ++val); + } +} + +static int allocate_int64_elem_set_tlv(struct elem_set_trial *trial, + unsigned int **tlv) +{ + /* + * Use this fomula between linear/dB value: + * + * Linear: dB range (coeff) + * 0<-> 4: -59.40<->-56.36 (44) + * 4<->22: -56.36<->-45.56 (60) + * 22<->33: -45.56<->-40.72 (76) + * 33<->37: -40.72<->-38.32 (44) + * 37<->48: -38.32<->-29.96 (76) + * 48<->66: -29.96<->-22.04 (60) + * 66<->84: -22.04<-> -8.36 (44) + * 84<->95: -8.36<-> -1.76 (60) + * 95<->99: -1.76<-> 0.00 (76) + * 100<->..: 0.0 + */ + static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(range, + 0, 4, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5940, 44, 1), + 4, 22, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5636, 60, 0), + 22, 33, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4556, 76, 0), + 33, 37, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4072, 44, 0), + 37, 48, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-3832, 76, 0), + 48, 66, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2996, 60, 0), + 66, 84, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2204, 44, 0), + 84, 95, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -836, 60, 0), + 95, 99, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -176, 76, 0), + 100, 10000, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0), + ); + + *tlv = malloc(sizeof(range)); + if (*tlv == NULL) + return -ENOMEM; + memcpy(*tlv, range, sizeof(range)); + + return 0; +} + +/* Common operations. */ +static int add_elem_set(struct elem_set_trial *trial) +{ + snd_ctl_elem_info_t *info; + char name[64] = {0}; + int err; + + snprintf(name, 64, "userspace-control-element-%s", + snd_ctl_elem_type_name(trial->type)); + + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_info_set_interface(info, SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_info_set_name(info, name); + + err = trial->add_elem_set(trial, info); + if (err >= 0) + snd_ctl_elem_info_get_id(info, trial->id); + + return err; +} + +static int check_event(struct elem_set_trial *trial, unsigned int mask, + unsigned int expected_count) +{ + struct pollfd pfds; + int count; + unsigned short revents; + snd_ctl_event_t *event; + int err; + + snd_ctl_event_alloca(&event); + + if (snd_ctl_poll_descriptors_count(trial->handle) != 1) + return -ENXIO; + + if (snd_ctl_poll_descriptors(trial->handle, &pfds, 1) != 1) + return -ENXIO; + + while (expected_count > 0) { + count = poll(&pfds, 1, 1000); + if (count < 0) + return errno; + /* Some events are already supplied. */ + if (count == 0) + return -ETIMEDOUT; + + err = snd_ctl_poll_descriptors_revents(trial->handle, &pfds, + count, &revents); + if (err < 0) + return err; + if (revents & POLLERR) + return -EIO; + if (!(revents & POLLIN)) + continue; + + err = snd_ctl_read(trial->handle, event); + if (err < 0) + return err; + if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) + continue; + /* + * I expect each event is generated separately to the same + * element or several events are generated at once. + */ + if ((snd_ctl_event_elem_get_mask(event) & mask) != mask) + continue; + --expected_count; + } + + if (expected_count != 0) + return -EIO; + + return 0; +} + +static int check_elem_list(struct elem_set_trial *trial) +{ + snd_ctl_elem_list_t *list; + snd_ctl_elem_id_t *id; + int e; + unsigned int i; + int err; + + snd_ctl_elem_list_alloca(&list); + snd_ctl_elem_id_alloca(&id); + + err = snd_ctl_elem_list(trial->handle, list); + if (err < 0) + return err; + + /* Certainly some elements are already added. */ + if (snd_ctl_elem_list_get_count(list) == 0) + return -EIO; + + err = snd_ctl_elem_list_alloc_space(list, + snd_ctl_elem_list_get_count(list)); + if (err < 0) + return err; + + err = snd_ctl_elem_list(trial->handle, list); + if (err < 0) + goto end; + + if (trial->element_count > snd_ctl_elem_list_get_count(list)) { + err = -EIO; + goto end; + } + + i = 0; + for (e = 0; e < snd_ctl_elem_list_get_count(list); ++e) { + snd_ctl_elem_list_get_id(list, e, id); + + if (strcmp(snd_ctl_elem_id_get_name(id), + snd_ctl_elem_id_get_name(trial->id)) != 0) + continue; + if (snd_ctl_elem_id_get_interface(id) != + snd_ctl_elem_id_get_interface(trial->id)) + continue; + if (snd_ctl_elem_id_get_device(id) != + snd_ctl_elem_id_get_device(trial->id)) + continue; + if (snd_ctl_elem_id_get_subdevice(id) != + snd_ctl_elem_id_get_subdevice(trial->id)) + continue; + + /* + * Here, I expect the list includes element ID data in numerical + * order. Actually, it does. + */ + if (snd_ctl_elem_id_get_numid(id) != + snd_ctl_elem_id_get_numid(trial->id) + i) + continue; + if (snd_ctl_elem_id_get_index(id) != + snd_ctl_elem_id_get_index(trial->id) + i) + continue; + + ++i; + } + + if (i != trial->element_count) + err = -EIO; +end: + snd_ctl_elem_list_free_space(list); + + return err; +} + +static int check_elem_set_props(struct elem_set_trial *trial) +{ + snd_ctl_elem_id_t *id; + snd_ctl_elem_info_t *info; + unsigned int numid; + unsigned int index; + unsigned int i; + unsigned int j; + int err; + + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_info_alloca(&info); + + snd_ctl_elem_info_set_id(info, trial->id); + numid = snd_ctl_elem_id_get_numid(trial->id); + index = snd_ctl_elem_id_get_index(trial->id); + + for (i = 0; i < trial->element_count; ++i) { + snd_ctl_elem_info_set_index(info, index + i); + + /* + * In Linux 4.0 or former, ioctl(SNDRV_CTL_IOCTL_ELEM_ADD) + * doesn't fill all of fields for identification. + */ + if (numid > 0) + snd_ctl_elem_info_set_numid(info, numid + i); + + err = snd_ctl_elem_info(trial->handle, info); + if (err < 0) + return err; + + /* Check some common properties. */ + if (snd_ctl_elem_info_get_type(info) != trial->type) + return -EIO; + if (snd_ctl_elem_info_get_count(info) != trial->member_count) + return -EIO; + + /* + * In a case of IPC, this is the others. But in this case, + * it's myself. + */ + if (snd_ctl_elem_info_get_owner(info) != getpid()) + return -EIO; + + /* + * Just adding an element set by userspace applications, + * included elements are initially locked. + */ + if (!snd_ctl_elem_info_is_locked(info)) + return -EIO; + + /* + * In initial state, any application can register TLV data for + * user-defined element set except for IEC 958 type, thus + * elements in any user-defined set should allow any write + * operation. + */ + if (trial->type != SND_CTL_ELEM_TYPE_IEC958 && + !snd_ctl_elem_info_is_tlv_writable(info)) + return -EIO; + + /* Check type-specific properties. */ + if (trial->check_elem_props != NULL) { + err = trial->check_elem_props(trial, info); + if (err < 0) + return err; + } + + snd_ctl_elem_info_get_id(info, id); + err = snd_ctl_elem_unlock(trial->handle, id); + if (err < 0) + return err; + + /* + * Till kernel v4.14, ALSA control core allows elements in any + * user-defined set to have TLV_READ flag even if they have no + * TLV data in their initial state. In this case, any read + * operation for TLV data should return -ENXIO. + */ + if (snd_ctl_elem_info_is_tlv_readable(info)) { + unsigned int data[32]; + err = snd_ctl_elem_tlv_read(trial->handle, trial->id, + data, sizeof(data)); + if (err >= 0) + return -EIO; + if (err != -ENXIO) + return err; + + trial->tlv_readable = true; + } + + } + + return 0; +} + +static int check_elems(struct elem_set_trial *trial) +{ + snd_ctl_elem_value_t *data; + unsigned int numid; + unsigned int index; + unsigned int i; + int err; + + snd_ctl_elem_value_alloca(&data); + + snd_ctl_elem_value_set_id(data, trial->id); + numid = snd_ctl_elem_id_get_numid(trial->id); + index = snd_ctl_elem_id_get_index(trial->id); + + for (i = 0; i < trial->element_count; ++i) { + snd_ctl_elem_value_set_index(data, index + i); + + /* + * In Linux 4.0 or former, ioctl(SNDRV_CTL_IOCTL_ELEM_ADD) + * doesn't fill all of fields for identification. + */ + if (numid > 0) + snd_ctl_elem_value_set_numid(data, numid + i); + + err = snd_ctl_elem_read(trial->handle, data); + if (err < 0) + return err; + + /* Change members of an element in this element set. */ + trial->change_elem_members(trial, data); + + err = snd_ctl_elem_write(trial->handle, data); + if (err < 0) + return err; + } + + return 0; +} + +static int check_tlv(struct elem_set_trial *trial) +{ + unsigned int *tlv; + int mask; + unsigned int count; + unsigned int len; + unsigned int *curr; + int err; + + err = trial->allocate_elem_set_tlv(trial, &tlv); + if (err < 0) + return err; + + len = tlv[SNDRV_CTL_TLVO_LEN] + sizeof(unsigned int) * 2; + curr = malloc(len); + if (curr == NULL) { + free(tlv); + return -ENOMEM; + } + + /* + * In in-kernel implementation, write and command operations are the + * same for an element set added by userspace applications. Here, I + * use write. + */ + err = snd_ctl_elem_tlv_write(trial->handle, trial->id, + (const unsigned int *)tlv); + if (err < 0) + goto end; + + /* + * Since kernel v4.14, any write operation to an element in user-defined + * set can change state of the other elements in the same set. In this + * case, any TLV data is firstly available after the operation. + */ + if (!trial->tlv_readable) { + mask = SND_CTL_EVENT_MASK_INFO | SND_CTL_EVENT_MASK_TLV; + count = trial->element_count; + } else { + mask = SND_CTL_EVENT_MASK_TLV; + count = 1; + } + err = check_event(trial, mask, count); + if (err < 0) + goto end; + if (!trial->tlv_readable) { + snd_ctl_elem_info_t *info; + snd_ctl_elem_info_alloca(&info); + + snd_ctl_elem_info_set_id(info, trial->id); + err = snd_ctl_elem_info(trial->handle, info); + if (err < 0) + return err; + if (!snd_ctl_elem_info_is_tlv_readable(info)) + return -EIO; + + /* Now TLV data is available for this element set. */ + trial->tlv_readable = true; + } + + err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, len); + if (err < 0) + goto end; + + if (memcmp(curr, tlv, len) != 0) + err = -EIO; +end: + free(tlv); + free(curr); + return 0; +} + +int main(void) +{ + struct elem_set_trial trial = {0}; + unsigned int i; + int err; + + snd_ctl_elem_id_alloca(&trial.id); + + err = snd_ctl_open(&trial.handle, "hw:0", 0); + if (err < 0) + return EXIT_FAILURE; + + err = snd_ctl_subscribe_events(trial.handle, 1); + if (err < 0) + return EXIT_FAILURE; + + /* Test all of types. */ + for (i = 0; i < SND_CTL_ELEM_TYPE_LAST; ++i) { + trial.type = i + 1; + + /* Assign type-dependent operations. */ + switch (trial.type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + trial.element_count = 900; + trial.member_count = 128; + trial.add_elem_set = add_bool_elem_set; + trial.check_elem_props = NULL; + trial.change_elem_members = change_bool_elem_members; + trial.allocate_elem_set_tlv = + allocate_bool_elem_set_tlv; + trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_INTEGER: + trial.element_count = 900; + trial.member_count = 128; + trial.add_elem_set = add_int_elem_set; + trial.check_elem_props = check_int_elem_props; + trial.change_elem_members = change_int_elem_members; + trial.allocate_elem_set_tlv = + allocate_int_elem_set_tlv; + trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + trial.element_count = 900; + trial.member_count = 128; + trial.add_elem_set = add_enum_elem_set; + trial.check_elem_props = check_enum_elem_props; + trial.change_elem_members = change_enum_elem_members; + trial.allocate_elem_set_tlv = NULL; + trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_BYTES: + trial.element_count = 900; + trial.member_count = 512; + trial.add_elem_set = add_bytes_elem_set; + trial.check_elem_props = NULL; + trial.change_elem_members = change_bytes_elem_members; + trial.allocate_elem_set_tlv = + allocate_bytes_elem_set_tlv; + trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_IEC958: + trial.element_count = 1; + trial.member_count = 1; + trial.add_elem_set = add_iec958_elem_set; + trial.check_elem_props = NULL; + trial.change_elem_members = change_iec958_elem_members; + trial.allocate_elem_set_tlv = NULL; + trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + default: + trial.element_count = 900; + trial.member_count = 64; + trial.add_elem_set = add_int64_elem_set; + trial.check_elem_props = check_int64_elem_props; + trial.change_elem_members = change_int64_elem_members; + trial.allocate_elem_set_tlv = + allocate_int64_elem_set_tlv; + trial.tlv_readable = false; + break; + } + + /* Test an operation to add an element set. */ + err = add_elem_set(&trial); + if (err < 0) { + printf("Fail to add an element set with %s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + err = check_event(&trial, SND_CTL_EVENT_MASK_ADD, + trial.element_count); + if (err < 0) { + printf("Fail to check some events to add elements with " + "%s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + + /* Check added elements are retrieved in a list. */ + err = check_elem_list(&trial); + if (err < 0) { + printf("Fail to list each element with %s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + + /* Check properties of each element in this element set. */ + err = check_elem_set_props(&trial); + if (err < 0) { + printf("Fail to check properties of each element with " + "%s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + + /* + * Test operations to change the state of members in each + * element in the element set. + */ + err = check_elems(&trial); + if (err < 0) { + printf("Fail to change status of each element with %s " + "type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + err = check_event(&trial, SND_CTL_EVENT_MASK_VALUE, + trial.element_count); + if (err < 0) { + printf("Fail to check some events to change status of " + "each elements with %s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + + /* + * Test an operation to change TLV data of this element set, + * except for enumerated and IEC958 type. + */ + if (trial.allocate_elem_set_tlv != NULL) { + err = check_tlv(&trial); + if (err < 0) { + printf("Fail to change TLV data of an element " + "set with %s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + } + + /* Test an operation to remove elements in this element set. */ + err = snd_ctl_elem_remove(trial.handle, trial.id); + if (err < 0) { + printf("Fail to remove elements with %s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + err = check_event(&trial, SND_CTL_EVENT_MASK_REMOVE, + trial.element_count); + if (err < 0) { + printf("Fail to check some events to remove each " + "element with %s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; + } + } + + if (err < 0) { + printf("%s\n", snd_strerror(err)); + + /* To ensure. */ + snd_ctl_elem_remove(trial.handle, trial.id); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 0000000..94a7105 --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,14 @@ +if INSTALL_M4 +aclocaldir=$(datadir)/aclocal +aclocal_DATA=alsa.m4 +endif +EXTRA_DIST=alsa.m4 buildrpm alsa.pc.in + +alsapkgconfdir = @ALSA_PKGCONF_DIR@ +pkgconfigdir = $(alsapkgconfdir) +pkgconfig_DATA = alsa.pc alsa-topology.pc + +rpm: buildrpm alsa-lib.spec + VERSION=$(VERSION) $(srcdir)/buildrpm + +AM_CPPFLAGS=-I$(top_srcdir)/include diff --git a/utils/Makefile.in b/utils/Makefile.in new file mode 100644 index 0000000..14dafbb --- /dev/null +++ b/utils/Makefile.in @@ -0,0 +1,547 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +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.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = alsa-lib.spec alsa.pc alsa-topology.pc +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(aclocaldir)" \ + "$(DESTDIR)$(pkgconfigdir)" +DATA = $(aclocal_DATA) $(pkgconfig_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/alsa-lib.spec.in \ + $(srcdir)/alsa-topology.pc.in $(srcdir)/alsa.pc.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_PKGCONF_DIR = @ALSA_PKGCONF_DIR@ +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@ +DLLTOOL = @DLLTOOL@ +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@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +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_AR = @ac_ct_AR@ +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@ +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 +alsapkgconfdir = @ALSA_PKGCONF_DIR@ +pkgconfigdir = $(alsapkgconfdir) +pkgconfig_DATA = alsa.pc alsa-topology.pc +AM_CPPFLAGS = -I$(top_srcdir)/include +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 +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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(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)/$@ +alsa-topology.pc: $(top_builddir)/config.status $(srcdir)/alsa-topology.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) + @list='$(aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(aclocaldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(aclocaldir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(aclocaldir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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: + 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 -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 \ + cscopelist-am ctags-am 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 tags-am uninstall \ + uninstall-aclocalDATA uninstall-am uninstall-pkgconfigDATA + +.PRECIOUS: Makefile + + +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-topology.pc.in b/utils/alsa-topology.pc.in new file mode 100644 index 0000000..f5a3b81 --- /dev/null +++ b/utils/alsa-topology.pc.in @@ -0,0 +1,5 @@ +Name: alsa-topology +Description: Advanced Linux Sound Architecture (ALSA) - Topology Library +Version: @VERSION@ +Requires: alsa >= @VERSION@ +Libs: -latopology diff --git a/utils/alsa.m4 b/utils/alsa.m4 new file mode 100644 index 0000000..4c457f0 --- /dev/null +++ b/utils/alsa.m4 @@ -0,0 +1,195 @@ +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 +dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for libasound, and define ALSA_CFLAGS, ALSA_LIBS and +dnl ALSA_TOPOLOGY_LIBS as appropriate. +dnl +dnl enables arguments --with-alsa-prefix= +dnl --with-alsa-inc-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, + AS_HELP_STRING([--with-alsa-prefix=PFX], [Prefix where Alsa library is installed(optional)]), + [alsa_prefix="$withval"], [alsa_prefix=""]) + +AC_ARG_WITH(alsa-inc-prefix, + AS_HELP_STRING([--with-alsa-inc-prefix=PFX], [Prefix where include libraries are (optional)]), + [alsa_inc_prefix="$withval"], [alsa_inc_prefix=""]) + +AC_ARG_ENABLE(alsa-topology, + AS_HELP_STRING([--enable-alsatopology], [Force to use the Alsa topology library]), + [enable_atopology="$enableval"], + [enable_atopology=no]) + +AC_ARG_ENABLE(alsatest, + AS_HELP_STRING([--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) + +AC_CHECK_LIB(c, dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")]) + +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 $LIBDL -lpthread" +LIBS="$ALSA_LIBS $LIBS" +AC_MSG_RESULT($ALSA_LIBS) + +dnl Check for a working version of libasound that is of the right version. +if test "x$enable_alsatest" = "xyes"; then + +AC_MSG_CHECKING([required libasound headers version]) +min_alsa_version=ifelse([$1], , 0.1.1, $1) +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_MSG_RESULT($alsa_min_major_version.$alsa_min_minor_version.$alsa_min_micro_version) + +AC_LANG_SAVE +AC_LANG_C +AC_MSG_CHECKING([for libasound headers version >= $alsa_min_major_version.$alsa_min_minor_version.$alsa_min_micro_version ($min_alsa_version)]) +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 + +AC_LANG_SAVE +AC_LANG_C +AC_MSG_CHECKING([for libatopology (sound headers version > 1.1.9)]) +AC_TRY_COMPILE([ +#include +#include +], [ +/* ensure backward compatibility */ +#if !defined(SND_LIB_VERSION) +#define SND_LIB_VERSION 0 +#endif +#if SND_LIB_VERSION > 0x00010109 + exit(0); +#else +# error not present +#endif +exit(0); +], + [AC_MSG_RESULT(yes) + enable_atopology="yes"], + [AC_MSG_RESULT(no)] +) +AC_LANG_RESTORE + +fi + +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] +) +if test "x$enable_atopology" = "xyes"; then +AC_CHECK_LIB([atopology], [snd_tplg_new],, + [ifelse([$3], , [AC_MSG_ERROR(No linkable libatopology was found.)]) + alsa_found=no] +) +fi +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="" + ALSA_TOPOLOGY_LIBS="" +fi + +dnl add the alsa topology library; must be at the end +AC_MSG_CHECKING(for ALSA topology LDFLAGS) +if test "x$enable_atopology" = "xyes"; then + ALSA_TOPOLOGY_LIBS="$ALSA_TOPOLOGY_LIBS -latopology" +fi +AC_MSG_RESULT($ALSA_TOPOLOGY_LIBS) + +dnl That should be it. Now just export out symbols: +AC_SUBST(ALSA_CFLAGS) +AC_SUBST(ALSA_LIBS) +AC_SUBST(ALSA_TOPOLOGY_LIBS) +]) diff --git a/utils/alsa.pc.in b/utils/alsa.pc.in new file mode 100644 index 0000000..444f66d --- /dev/null +++ b/utils/alsa.pc.in @@ -0,0 +1,12 @@ +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@ +Cflags: -I${includedir} 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..ff81ff4 --- /dev/null +++ b/version @@ -0,0 +1 @@ +1.2.1.2