From 17cdbdf342c647cb1f37c3509810c8076b878b62 Mon Sep 17 00:00:00 2001 From: Sean McNeil Date: Fri, 2 Jul 2010 16:52:59 +0700 Subject: [PATCH] Update alsa-lib to version 1.0.23. Change-Id: Ia95e09adbb5b6bb5ed09f53201a9cb4205dd5c5d --- MODULE_LICENSE_LGPL | 1 - NOTICE | 504 --------------- README | 6 +- configure | 71 ++- configure.in | 21 +- doc/Makefile.am | 2 +- doc/Makefile.in | 2 +- doc/doxygen.cfg | 1 + doc/doxygen.cfg.in | 1 + include/asoundlib.h | 5 - include/conf.h | 21 +- include/control.h | 5 + include/iatomic.h | 23 + include/local.h | 30 +- include/mixer.h | 2 - include/pcm.h | 5 +- include/pcm_ioplug.h | 6 +- include/pcm_rate.h | 38 +- include/sound/asound.h | 3 +- include/timer.h | 2 + include/version.h | 4 +- libtool | 50 +- modules/mixer/simple/Makefile.am | 4 +- modules/mixer/simple/Makefile.in | 4 +- src/alisp/alisp.c | 5 +- src/conf.c | 1279 +++++++++++++++++++++++++++++--------- src/conf/cards/CMI8788.conf | 13 +- src/conf/cards/GUS.conf | 47 -- src/conf/cards/HDA-Intel.conf | 3 + src/conf/cards/Makefile.am | 1 + src/conf/cards/Makefile.in | 8 +- src/conf/cards/SB-XFi.conf | 108 ++++ src/conf/cards/USB-Audio.conf | 47 +- src/conf/pcm/dmix.conf | 12 +- src/control/cards.c | 40 +- src/control/control.c | 41 +- src/control/control_ext.c | 20 +- src/control/control_hw.c | 11 - src/control/hcontrol.c | 17 +- src/control/namehint.c | 36 +- src/control/setup.c | 12 +- src/control/tlv.c | 40 +- src/dlmisc.c | 19 +- src/hwdep/hwdep_hw.c | 11 - src/mixer/simple.c | 3 +- src/mixer/simple_none.c | 10 + src/output.c | 2 +- src/pcm/pcm.c | 180 +++--- src/pcm/pcm_direct.c | 27 +- src/pcm/pcm_direct.h | 7 +- src/pcm/pcm_dmix.c | 12 +- src/pcm/pcm_dmix_generic.c | 2 +- src/pcm/pcm_dmix_i386.c | 1 + src/pcm/pcm_dmix_i386.h | 2 +- src/pcm/pcm_dmix_x86_64.h | 4 +- src/pcm/pcm_dshare.c | 2 +- src/pcm/pcm_dsnoop.c | 2 +- src/pcm/pcm_file.c | 266 ++++++-- src/pcm/pcm_generic.c | 1 + src/pcm/pcm_hooks.c | 61 +- src/pcm/pcm_hw.c | 139 ++--- src/pcm/pcm_ioplug.c | 4 +- src/pcm/pcm_meter.c | 4 +- src/pcm/pcm_mmap.c | 6 - src/pcm/pcm_mmap_emul.c | 36 +- src/pcm/pcm_null.c | 1 + src/pcm/pcm_params.c | 33 +- src/pcm/pcm_plug.c | 35 +- src/pcm/pcm_plugin.c | 1 + src/pcm/pcm_rate.c | 53 +- src/pcm/pcm_rate_linear.c | 24 +- src/pcm/pcm_share.c | 3 +- src/pcm/pcm_softvol.c | 22 +- src/rawmidi/rawmidi.c | 4 +- src/rawmidi/rawmidi_hw.c | 11 - src/seq/seq.c | 54 +- src/seq/seq_hw.c | 11 - src/seq/seq_midi_event.c | 257 ++++++-- src/seq/seqmid.c | 4 +- src/timer/timer_hw.c | 12 - src/timer/timer_local.h | 2 +- test/Makefile.am | 2 + test/Makefile.in | 168 ++++- test/lsb/Makefile.am | 7 + test/lsb/Makefile.in | 612 ++++++++++++++++++ test/lsb/config.c | 582 +++++++++++++++++ test/lsb/midi_event.c | 371 +++++++++++ test/lsb/test.h | 29 + test/pcm.c | 53 +- version | 2 +- 90 files changed, 4167 insertions(+), 1538 deletions(-) delete mode 100644 MODULE_LICENSE_LGPL delete mode 100644 NOTICE create mode 100644 src/conf/cards/SB-XFi.conf create mode 100644 test/lsb/Makefile.am create mode 100644 test/lsb/Makefile.in create mode 100644 test/lsb/config.c create mode 100644 test/lsb/midi_event.c create mode 100644 test/lsb/test.h diff --git a/MODULE_LICENSE_LGPL b/MODULE_LICENSE_LGPL deleted file mode 100644 index 8d1c8b69..00000000 --- a/MODULE_LICENSE_LGPL +++ /dev/null @@ -1 +0,0 @@ - diff --git a/NOTICE b/NOTICE deleted file mode 100644 index b1e3f5a2..00000000 --- a/NOTICE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/README b/README index dc80cc50..0ff07b98 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ -This version of the ALSA library was obtained from the following location: -ftp://ftp.alsa-project.org/pub/lib/alsa-lib-1.0.19.tar.bz2 +# This version of the ALSA library was obtained from the following location: +# ftp://ftp.alsa-project.org/pub/lib/alsa-lib-1.0.23.tar.bz2 -This package was (previously in 1.0.16) configured with the following options: +# This package was (in 1.0.16) configured with the following options: ./configure \ --disable-debug \ diff --git a/configure b/configure index f0425273..b7925be4 100755 --- a/configure +++ b/configure @@ -2449,7 +2449,7 @@ fi # Define the identity of the package. PACKAGE=alsa-lib - VERSION=1.0.19 + VERSION=1.0.23 cat >>confdefs.h <<_ACEOF @@ -2607,6 +2607,9 @@ else fi +# Test for new silent rules and enable only if they are available + + @@ -2625,6 +2628,8 @@ echo $ECHO_N "checking for cross-compiler... $ECHO_C" >&6; } echo "${ECHO_T}$CC" >&6; } fi +CFLAGS="$CFLAGS -D_GNU_SOURCE" + ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -4854,7 +4859,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4857 "configure"' > conftest.$ac_ext + echo '#line 4862 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7555,11 +7560,11 @@ else -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:7558: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7563: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7562: \$? = $ac_status" >&5 + echo "$as_me:7567: \$? = $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. @@ -7823,11 +7828,11 @@ else -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:7826: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7831: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7830: \$? = $ac_status" >&5 + echo "$as_me:7835: \$? = $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. @@ -7927,11 +7932,11 @@ else -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:7930: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7935: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7934: \$? = $ac_status" >&5 + echo "$as_me:7939: \$? = $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 @@ -10379,7 +10384,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:12855: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12854: \$? = $ac_status" >&5 + echo "$as_me:12859: \$? = $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. @@ -12951,11 +12956,11 @@ else -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:12954: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12959: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12958: \$? = $ac_status" >&5 + echo "$as_me:12963: \$? = $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 @@ -14521,11 +14526,11 @@ else -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:14524: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14529: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14528: \$? = $ac_status" >&5 + echo "$as_me:14533: \$? = $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. @@ -14625,11 +14630,11 @@ else -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:14628: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14633: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14632: \$? = $ac_status" >&5 + echo "$as_me:14637: \$? = $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 @@ -16855,11 +16860,11 @@ else -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:16858: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16863: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16862: \$? = $ac_status" >&5 + echo "$as_me:16867: \$? = $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. @@ -17123,11 +17128,11 @@ else -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:17126: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17131: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:17130: \$? = $ac_status" >&5 + echo "$as_me:17135: \$? = $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. @@ -17227,11 +17232,11 @@ else -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:17230: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17235: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:17234: \$? = $ac_status" >&5 + echo "$as_me:17239: \$? = $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 @@ -20821,15 +20826,18 @@ echo $ECHO_N "checking for softfloat... $ECHO_C" >&6; } # Check whether --with-softfloat was given. if test "${with_softfloat+set}" = set; then - withval=$with_softfloat; + withval=$with_softfloat; case "$withval" in + y|yes) softfloat=yes ;; + *) softfloat=no ;; + esac +fi + +if test "$softfloat" = "yes" ; then + cat >>confdefs.h <<\_ACEOF #define HAVE_SOFT_FLOAT "1" _ACEOF - softfloat=yes -fi - -if test "$softfloat" = "yes" ; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } else @@ -21594,6 +21602,7 @@ else build_alisp="yes" fi +test "$softfloat" = "yes" && build_alisp="no" # Check whether --enable-old-symbols was given. if test "${enable_old_symbols+set}" = set; then enableval=$enable_old_symbols; keep_old_symbols="$enableval" @@ -21811,6 +21820,7 @@ fi if test "$softfloat" = "yes"; then build_pcm_lfloat="no" + build_pcm_ladspa="no" fi @@ -22225,7 +22235,7 @@ if test ! -L "$srcdir"/include/alsa ; then 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/compat/Makefile src/alisp/Makefile src/conf/Makefile src/conf/cards/Makefile src/conf/pcm/Makefile modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile alsalisp/Makefile aserver/Makefile test/Makefile utils/Makefile utils/alsa-lib.spec utils/alsa.pc" +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/compat/Makefile src/alisp/Makefile src/conf/Makefile src/conf/cards/Makefile src/conf/pcm/Makefile modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile alsalisp/Makefile aserver/Makefile test/Makefile test/lsb/Makefile utils/Makefile utils/alsa-lib.spec utils/alsa.pc" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -23134,6 +23144,7 @@ do "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" ;; diff --git a/configure.in b/configure.in index 9a71d95c..f6df5020 100644 --- a/configure.in +++ b/configure.in @@ -12,11 +12,14 @@ dnl add API = c+1:0:a+1 dnl remove API = c+1:0:0 dnl ************************************************* AC_CANONICAL_HOST -AM_INIT_AUTOMAKE(alsa-lib, 1.0.19) +AM_INIT_AUTOMAKE(alsa-lib, 1.0.23) eval LIBTOOL_VERSION_INFO="2:0:0" dnl ************************************************* AM_CONDITIONAL(INSTALL_M4, test -n "${ACLOCAL}") +# Test for new silent rules and enable only if they are available +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + AC_PREFIX_DEFAULT(/usr) dnl Checks for programs. @@ -35,6 +38,8 @@ then AC_MSG_RESULT($CC) fi +CFLAGS="$CFLAGS -D_GNU_SOURCE" + AC_PROG_CC AC_PROG_CPP @@ -201,9 +206,12 @@ AC_MSG_CHECKING(for softfloat) AC_ARG_WITH(softfloat, AS_HELP_STRING([--with-softfloat], [do you have floating point unit on this machine? (optional)]), - [ AC_DEFINE(HAVE_SOFT_FLOAT, "1", [Avoid calculation in float]) - softfloat=yes ],) + [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) @@ -367,6 +375,7 @@ AC_ARG_ENABLE(seq, AC_ARG_ENABLE(alisp, AS_HELP_STRING([--disable-alisp], [disable the alisp component]), [build_alisp="$enableval"], [build_alisp="yes"]) +test "$softfloat" = "yes" && build_alisp="no" AC_ARG_ENABLE(old-symbols, AS_HELP_STRING([--disable-old-symbols], [disable old obsoleted symbols]), [keep_old_symbols="$enableval"], [keep_old_symbols="yes"]) @@ -474,6 +483,7 @@ fi if test "$softfloat" = "yes"; then build_pcm_lfloat="no" + build_pcm_ladspa="no" fi AM_CONDITIONAL(BUILD_PCM_PLUGIN, test x$build_pcm_plugin = xyes) @@ -592,8 +602,9 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \ src/conf/cards/Makefile \ src/conf/pcm/Makefile \ modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \ - alsalisp/Makefile aserver/Makefile test/Makefile utils/Makefile \ - utils/alsa-lib.spec utils/alsa.pc) + alsalisp/Makefile aserver/Makefile \ + test/Makefile test/lsb/Makefile \ + utils/Makefile utils/alsa-lib.spec utils/alsa.pc) dnl Create asoundlib.h dynamically according to configure options echo "Creating asoundlib.h..." diff --git a/doc/Makefile.am b/doc/Makefile.am index a5896a7e..2cc250bf 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -5,7 +5,7 @@ EXTRA_DIST=README.1st asoundrc.txt doxygen.cfg index.doxygen INCLUDES=-I$(top_srcdir)/include doc: - test -e doxygen.cfg || sed s:@top_srcdir@:..:g doxygen.cfg.in > doxygen.cfg + test -e doxygen.cfg || sed s:[@]top_srcdir[@]:..:g doxygen.cfg.in > doxygen.cfg doxygen doxygen.cfg doc-pack: doc diff --git a/doc/Makefile.in b/doc/Makefile.in index 503d6519..65b3d3a6 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -574,7 +574,7 @@ uninstall-info: uninstall-info-recursive doc: - test -e doxygen.cfg || sed s:@top_srcdir@:..:g doxygen.cfg.in > doxygen.cfg + test -e doxygen.cfg || sed s:[@]top_srcdir[@]:..:g doxygen.cfg.in > doxygen.cfg doxygen doxygen.cfg doc-pack: doc diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg index 9ee4c3c0..71e0ee02 100644 --- a/doc/doxygen.cfg +++ b/doc/doxygen.cfg @@ -114,6 +114,7 @@ PREDEFINED = DOXYGEN PIC "DOC_HIDDEN" \ "link_warning(x,y)=" OPTIMIZE_OUTPUT_FOR_C = YES # doxygen 1.2.6 option +TYPEDEF_HIDES_STRUCT = YES # needed in doxygen >= 1.5.4 #INPUT_FILTER = inputfilter #FILTER_SOURCE_FILES = YES diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in index 4f682cfc..8606c485 100644 --- a/doc/doxygen.cfg.in +++ b/doc/doxygen.cfg.in @@ -114,6 +114,7 @@ PREDEFINED = DOXYGEN PIC "DOC_HIDDEN" \ "link_warning(x,y)=" OPTIMIZE_OUTPUT_FOR_C = YES # doxygen 1.2.6 option +TYPEDEF_HIDES_STRUCT = YES # needed in doxygen >= 1.5.4 #INPUT_FILTER = inputfilter #FILTER_SOURCE_FILES = YES diff --git a/include/asoundlib.h b/include/asoundlib.h index 9fc860a4..c418aa6a 100644 --- a/include/asoundlib.h +++ b/include/asoundlib.h @@ -47,14 +47,9 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include -#include #endif /* __ASOUNDLIB_H */ diff --git a/include/conf.h b/include/conf.h index 7c0cab06..ff270f61 100644 --- a/include/conf.h +++ b/include/conf.h @@ -44,11 +44,11 @@ extern "C" { /** \brief \c dlsym version for the config hook callback. */ #define SND_CONFIG_DLSYM_VERSION_HOOK _dlsym_config_hook_001 -/** Configuration node type. */ +/** \brief Configuration node type. */ typedef enum _snd_config_type { /** Integer number. */ SND_CONFIG_TYPE_INTEGER, - /** 64 bit Integer number. */ + /** 64-bit integer number. */ SND_CONFIG_TYPE_INTEGER64, /** Real number. */ SND_CONFIG_TYPE_REAL, @@ -154,11 +154,20 @@ 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 pos Iterator variable for the current node. - * \param next Iterator variable for the next node. - * \param node Handle to the compound configuration node to iterate over. + * \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. * - * This macro is designed to permit the removal of the current node. + * 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)) diff --git a/include/control.h b/include/control.h index 2361dc3a..3d6b0a5f 100644 --- a/include/control.h +++ b/include/control.h @@ -174,6 +174,10 @@ typedef enum _snd_ctl_event_type { #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 @@ -419,6 +423,7 @@ 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); diff --git a/include/iatomic.h b/include/iatomic.h index 8f6ec228..e92dbfd4 100644 --- a/include/iatomic.h +++ b/include/iatomic.h @@ -1079,6 +1079,29 @@ static __inline__ int atomic_sub_return(int i, volatile atomic_t *v) #endif /* __sh__ */ +#ifdef __bfin__ + +#include + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) +#define atomic_add(i,v) bfin_atomic_add32(&(v)->counter, i) +#define atomic_sub(i,v) bfin_atomic_sub32(&(v)->counter, i) +#define atomic_inc(v) bfin_atomic_inc32(&(v)->counter); +#define atomic_dec(v) bfin_atomic_dec32(&(v)->counter); + +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() mb() +#define wmb() mb() + +#define IATOMIC_DEFINED 1 + +#endif /* __bfin__ */ + #ifndef IATOMIC_DEFINED /* * non supported architecture. diff --git a/include/local.h b/include/local.h index b5a1c453..fa3f0b7f 100644 --- a/include/local.h +++ b/include/local.h @@ -230,22 +230,28 @@ extern snd_lib_error_handler_t snd_err_msg; # define link_warning(symbol, msg) #endif -/* open with resmgr */ -#ifdef SUPPORT_RESMGR static inline int snd_open_device(const char *filename, int fmode) { - int fd = open(filename, 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) - return fd; - if (errno == EAGAIN || errno == EBUSY) - return fd; - if (! access(filename, F_OK)) - return rsm_open_device(filename, fmode); - return -1; + fcntl(fd, F_SETFD, FD_CLOEXEC); + return fd; } -#else -#define snd_open_device(filename, fmode) open(filename, fmode); -#endif /* make local functions really local */ #define snd_dlobj_cache_lookup \ diff --git a/include/mixer.h b/include/mixer.h index df921642..58256a63 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -124,8 +124,6 @@ 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_add_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem); -int snd_mixer_remove_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem); int snd_mixer_elem_new(snd_mixer_elem_t **elem, snd_mixer_elem_type_t type, int compare_weight, diff --git a/include/pcm.h b/include/pcm.h index 15e9cb27..f3618c3d 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -526,8 +526,6 @@ 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_forward(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_can_rewind(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); @@ -1022,7 +1020,8 @@ 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, snd_pcm_scope_ops_t *val); +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); diff --git a/include/pcm_ioplug.h b/include/pcm_ioplug.h index b5968f1a..6331cf07 100644 --- a/include/pcm_ioplug.h +++ b/include/pcm_ioplug.h @@ -55,11 +55,11 @@ typedef struct snd_pcm_ioplug snd_pcm_ioplug_t; /** Callback table of ioplug */ typedef struct snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; -/** +/* * bit flags for additional conditions */ -#define SND_PCM_IOPLUG_FLAG_LISTED (1<<0) /* list up this PCM */ -#define SND_PCM_IOPLUG_FLAG_MONOTONIC (1<<1) /* monotonic timestamps */ +#define SND_PCM_IOPLUG_FLAG_LISTED (1<<0) /**< list up this PCM */ +#define SND_PCM_IOPLUG_FLAG_MONOTONIC (1<<1) /**< monotonic timestamps */ /* * Protocol version diff --git a/include/pcm_rate.h b/include/pcm_rate.h index d211e097..4d70df26 100644 --- a/include/pcm_rate.h +++ b/include/pcm_rate.h @@ -38,7 +38,7 @@ extern "C" { /** * Protocol version */ -#define SND_PCM_RATE_PLUGIN_VERSION 0x010001 +#define SND_PCM_RATE_PLUGIN_VERSION 0x010002 /** hw_params information for a single side */ typedef struct snd_pcm_rate_side_info { @@ -98,6 +98,22 @@ typedef struct snd_pcm_rate_ops { * 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 */ @@ -110,6 +126,26 @@ typedef int (*snd_pcm_rate_open_func_t)(unsigned int version, void **objp, #define SND_PCM_RATE_PLUGIN_ENTRY(name) _snd_pcm_rate_##name##_open +#ifndef DOC_HIDDEN +/* old rate_ops for protocol version 0x010001 */ +typedef struct snd_pcm_rate_old_ops { + void (*close)(void *obj); + int (*init)(void *obj, snd_pcm_rate_info_t *info); + void (*free)(void *obj); + void (*reset)(void *obj); + int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info); + void (*convert)(void *obj, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, unsigned int src_frames); + void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames, + const int16_t *src, unsigned int src_frames); + snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); + snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); +} snd_pcm_rate_old_ops_t; +#endif + #ifdef __cplusplus } #endif diff --git a/include/sound/asound.h b/include/sound/asound.h index 977b2d6c..fa889381 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -402,7 +402,7 @@ struct sndrv_pcm_sw_params { struct sndrv_pcm_channel_info { unsigned int channel; - off_t offset; /* mmap offset */ + long offset; /* mmap offset */ unsigned int first; /* offset to first sample in bits */ unsigned int step; /* samples distance in bits */ }; @@ -593,6 +593,7 @@ enum sndrv_timer_slave_class { #define SNDRV_TIMER_GLOBAL_SYSTEM 0 #define SNDRV_TIMER_GLOBAL_RTC 1 #define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 /* info flags */ #define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ diff --git a/include/timer.h b/include/timer.h index 4d06e31f..2803f532 100644 --- a/include/timer.h +++ b/include/timer.h @@ -115,6 +115,8 @@ typedef struct _snd_timer_tread { #define SND_TIMER_GLOBAL_RTC 1 /** global timer - HPET */ #define SND_TIMER_GLOBAL_HPET 2 +/** global timer - HRTIMER */ +#define SND_TIMER_GLOBAL_HRTIMER 3 /** timer open mode flag - non-blocking behaviour */ #define SND_TIMER_OPEN_NONBLOCK (1<<0) diff --git a/include/version.h b/include/version.h index 6ac58806..ec708e13 100644 --- a/include/version.h +++ b/include/version.h @@ -4,12 +4,12 @@ #define SND_LIB_MAJOR 1 /**< major number of library version */ #define SND_LIB_MINOR 0 /**< minor number of library version */ -#define SND_LIB_SUBMINOR 19 /**< subminor number of library version */ +#define SND_LIB_SUBMINOR 23 /**< 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.0.19" +#define SND_LIB_VERSION_STR "1.0.23" diff --git a/libtool b/libtool index c3cd4aa3..013d33bf 100755 --- a/libtool +++ b/libtool @@ -1,7 +1,7 @@ -#! /bin/sh +#! /bin/bash # libtoolT - Provide generalized library-building support services. -# Generated automatically by (GNU alsa-lib 1.0.19) +# Generated automatically by (GNU alsa-lib 1.0.23) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 @@ -30,10 +30,10 @@ # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. -SED="/usr/bin/sed" +SED="/bin/sed" # Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="/usr/bin/sed -e 1s/^X//" +Xsed="/bin/sed -e 1s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. @@ -44,10 +44,10 @@ available_tags=" CXX" # ### BEGIN LIBTOOL CONFIG -# Libtool was configured on host alsa0: +# Libtool was configured on host mcneil-lap-dell: # Shell to use when invoking shell scripts. -SHELL="/bin/sh" +SHELL="/bin/bash" # Whether or not to build shared libraries. build_libtool_libs=yes @@ -66,12 +66,12 @@ fast_install=yes # The host system. host_alias= -host=x86_64-suse-linux-gnu +host=x86_64-unknown-linux-gnu host_os=linux-gnu # The build system. build_alias= -build=x86_64-suse-linux-gnu +build=x86_64-unknown-linux-gnu build_os=linux-gnu # An echo program that does not interpret backslashes. @@ -85,7 +85,7 @@ AR_FLAGS="cru" LTCC="gcc" # LTCC compiler flags. -LTCFLAGS="-O2 -fomit-frame-pointer -Wall -pipe" +LTCFLAGS=" -D_GNU_SOURCE" # A language-specific compiler. CC="gcc" @@ -94,10 +94,10 @@ CC="gcc" with_gcc=yes # An ERE matcher. -EGREP="/usr/bin/grep -E" +EGREP="/bin/grep -E" # The linker used to build libraries. -LD="/usr/x86_64-suse-linux/bin/ld -m elf_x86_64" +LD="/usr/bin/ld -m elf_x86_64" # Whether we need hard or soft links. LN_S="ln -s" @@ -325,10 +325,10 @@ variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COM link_all_deplibs=unknown # Compile-time system search path for libraries -sys_lib_search_path_spec=" /usr/lib64/gcc/x86_64-suse-linux/4.1.2/ /usr/lib/gcc/x86_64-suse-linux/4.1.2/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib/x86_64-suse-linux/4.1.2/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib/../lib64/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../x86_64-suse-linux/4.1.2/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/ /lib/x86_64-suse-linux/4.1.2/ /lib/../lib64/ /usr/lib/x86_64-suse-linux/4.1.2/ /usr/lib/../lib64/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../ /lib/ /usr/lib/" +sys_lib_search_path_spec=" /usr/lib/gcc/x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../x86_64-linux-gnu/lib/x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../x86_64-linux-gnu/lib/../lib/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/ /lib/x86_64-linux-gnu/4.4.3/ /lib/../lib/ /usr/lib/x86_64-linux-gnu/4.4.3/ /usr/lib/../lib/ /usr/lib/x86_64-linux-gnu/x86_64-linux-gnu/4.4.3/ /usr/lib/x86_64-linux-gnu/../lib/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../x86_64-linux-gnu/lib/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../ /lib/ /usr/lib/ /usr/lib/x86_64-linux-gnu/" # Run-time system search path for libraries -sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/X11R6/lib64/Xaw3d /usr/X11R6/lib64 /usr/lib64/Xaw3d /usr/X11R6/lib/Xaw3d /usr/X11R6/lib /usr/lib/Xaw3d /usr/x86_64-suse-linux/lib /usr/local/lib /opt/kde3/lib /opt/gnome/lib /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /opt/kde3/lib64 /opt/gnome/lib64 " +sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/lib/mesa /usr/lib32/mesa /usr/lib32/alsa-lib /usr/lib/alsa-lib /usr/local/lib /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu " # Fix the shell variable $srcfile for the compiler. fix_srcfile_path="" @@ -7215,10 +7215,10 @@ disable_libs=static # End: # ### BEGIN LIBTOOL TAG CONFIG: CXX -# Libtool was configured on host alsa0: +# Libtool was configured on host mcneil-lap-dell: # Shell to use when invoking shell scripts. -SHELL="/bin/sh" +SHELL="/bin/bash" # Whether or not to build shared libraries. build_libtool_libs=yes @@ -7237,12 +7237,12 @@ fast_install=yes # The host system. host_alias= -host=x86_64-suse-linux-gnu +host=x86_64-unknown-linux-gnu host_os=linux-gnu # The build system. build_alias= -build=x86_64-suse-linux-gnu +build=x86_64-unknown-linux-gnu build_os=linux-gnu # An echo program that does not interpret backslashes. @@ -7256,7 +7256,7 @@ AR_FLAGS="cru" LTCC="gcc" # LTCC compiler flags. -LTCFLAGS="-O2 -fomit-frame-pointer -Wall -pipe" +LTCFLAGS=" -D_GNU_SOURCE" # A language-specific compiler. CC="g++" @@ -7265,10 +7265,10 @@ CC="g++" with_gcc=yes # An ERE matcher. -EGREP="/usr/bin/grep -E" +EGREP="/bin/grep -E" # The linker used to build libraries. -LD="/usr/x86_64-suse-linux/bin/ld -m elf_x86_64" +LD="/usr/bin/ld -m elf_x86_64" # Whether we need hard or soft links. LN_S="ln -s" @@ -7397,11 +7397,11 @@ striplib="strip --strip-unneeded" # Dependencies to place before the objects being linked to create a # shared library. -predep_objects="/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crti.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtbeginS.o" +predep_objects="/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.3/crtbeginS.o" # Dependencies to place after the objects being linked to create a # shared library. -postdep_objects="/usr/lib64/gcc/x86_64-suse-linux/4.1.2/crtendS.o /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crtn.o" +postdep_objects="/usr/lib/gcc/x86_64-linux-gnu/4.4.3/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crtn.o" # Dependencies to place before the objects being linked to create a # shared library. @@ -7413,7 +7413,7 @@ postdeps="-lstdc++ -lm -lgcc_s -lc -lgcc_s" # The library search path used internally by the compiler when linking # a shared library. -compiler_lib_search_path="-L/usr/lib64/gcc/x86_64-suse-linux/4.1.2 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib -L/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../.." +compiler_lib_search_path="-L/usr/lib/gcc/x86_64-linux-gnu/4.4.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../.. -L/usr/lib/x86_64-linux-gnu" # Method to check whether dependent libraries are shared objects. deplibs_check_method="pass_all" @@ -7493,10 +7493,10 @@ variables_saved_for_relink="PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COM link_all_deplibs=unknown # Compile-time system search path for libraries -sys_lib_search_path_spec=" /usr/lib64/gcc/x86_64-suse-linux/4.1.2/ /usr/lib/gcc/x86_64-suse-linux/4.1.2/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib/x86_64-suse-linux/4.1.2/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib/../lib64/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../x86_64-suse-linux/4.1.2/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/ /lib/x86_64-suse-linux/4.1.2/ /lib/../lib64/ /usr/lib/x86_64-suse-linux/4.1.2/ /usr/lib/../lib64/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/lib/ /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../ /lib/ /usr/lib/" +sys_lib_search_path_spec=" /usr/lib/gcc/x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../x86_64-linux-gnu/lib/x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../x86_64-linux-gnu/lib/../lib/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../x86_64-linux-gnu/4.4.3/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/ /lib/x86_64-linux-gnu/4.4.3/ /lib/../lib/ /usr/lib/x86_64-linux-gnu/4.4.3/ /usr/lib/../lib/ /usr/lib/x86_64-linux-gnu/x86_64-linux-gnu/4.4.3/ /usr/lib/x86_64-linux-gnu/../lib/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../x86_64-linux-gnu/lib/ /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../ /lib/ /usr/lib/ /usr/lib/x86_64-linux-gnu/" # Run-time system search path for libraries -sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/X11R6/lib64/Xaw3d /usr/X11R6/lib64 /usr/lib64/Xaw3d /usr/X11R6/lib/Xaw3d /usr/X11R6/lib /usr/lib/Xaw3d /usr/x86_64-suse-linux/lib /usr/local/lib /opt/kde3/lib /opt/gnome/lib /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /opt/kde3/lib64 /opt/gnome/lib64 " +sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/lib/mesa /usr/lib32/mesa /usr/lib32/alsa-lib /usr/lib/alsa-lib /usr/local/lib /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu " # Fix the shell variable $srcfile for the compiler. fix_srcfile_path="" diff --git a/modules/mixer/simple/Makefile.am b/modules/mixer/simple/Makefile.am index f73871fa..bad09444 100644 --- a/modules/mixer/simple/Makefile.am +++ b/modules/mixer/simple/Makefile.am @@ -21,11 +21,11 @@ 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 +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 +smixer_hda_la_LIBADD = ../../../src/libasound.la -ldl if BUILD_PYTHON smixer_python_la_SOURCES = python.c diff --git a/modules/mixer/simple/Makefile.in b/modules/mixer/simple/Makefile.in index 63234cbc..5981b1f1 100644 --- a/modules/mixer/simple/Makefile.in +++ b/modules/mixer/simple/Makefile.in @@ -308,10 +308,10 @@ 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 +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 +smixer_hda_la_LIBADD = ../../../src/libasound.la -ldl @BUILD_PYTHON_TRUE@smixer_python_la_SOURCES = python.c @BUILD_PYTHON_TRUE@smixer_python_la_LDFLAGS = -module -avoid-version $(LDFLAGS_NOUNDEFINED) @BUILD_PYTHON_TRUE@smixer_python_la_CFLAGS = $(PYTHON_INCLUDES) diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c index 0e6f5496..f3580f90 100644 --- a/src/alisp/alisp.c +++ b/src/alisp/alisp.c @@ -233,6 +233,9 @@ static struct alisp_object * incref_tree(struct alisp_instance *instance, struct 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) @@ -250,6 +253,7 @@ static struct alisp_object * incref_tree_explicit(struct alisp_instance *instanc return incref_object(instance, p); return p; } +#endif static void free_objects(struct alisp_instance *instance) { @@ -1021,7 +1025,6 @@ static const char *obj_type_str(struct alisp_object * p) case ALISP_OBJ_CONS: return "cons"; default: assert(0); } - return NULL; } static void print_obj_lists(struct alisp_instance *instance, snd_output_t *out) diff --git a/src/conf.c b/src/conf.c index c86f819b..570c90fa 100644 --- a/src/conf.c +++ b/src/conf.c @@ -440,7 +440,7 @@ struct _snd_config { } compound; } u; struct list_head list; - snd_config_t *father; + snd_config_t *parent; int hop; }; @@ -879,16 +879,16 @@ static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t static int _snd_config_make_add(snd_config_t **config, char **id, - snd_config_type_t type, snd_config_t *father) + snd_config_type_t type, snd_config_t *parent) { snd_config_t *n; int err; - assert(father->type == SND_CONFIG_TYPE_COMPOUND); + assert(parent->type == SND_CONFIG_TYPE_COMPOUND); err = _snd_config_make(&n, id, type); if (err < 0) return err; - n->father = father; - list_add_tail(&n->list, &father->u.compound.fields); + n->parent = parent; + list_add_tail(&n->list, &parent->u.compound.fields); *config = n; return 0; } @@ -912,7 +912,7 @@ static int _snd_config_search(snd_config_t *config, return -ENOENT; } -static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, char **id, int skip) +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; @@ -940,7 +940,7 @@ static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, return -EINVAL; } } else { - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, father); + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, parent); if (err < 0) return err; } @@ -957,9 +957,9 @@ static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, } } else { if (i <= INT_MAX) - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, father); + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, parent); else - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, father); + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, parent); if (err < 0) return err; } @@ -978,7 +978,7 @@ static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, return -EINVAL; } } else { - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, father); + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, parent); if (err < 0) return err; } @@ -988,10 +988,10 @@ static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, return 0; } -static int parse_defs(snd_config_t *father, input_t *input, int skip, int override); +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 *father, input_t *input, int idx, 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; @@ -1023,7 +1023,7 @@ static int parse_array_def(snd_config_t *father, input_t *input, int idx, int sk goto __end; } } else { - err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); if (err < 0) goto __end; } @@ -1050,7 +1050,7 @@ static int parse_array_def(snd_config_t *father, input_t *input, int idx, int sk } default: unget_char(c, input); - err = parse_value(&n, father, input, &id, skip); + err = parse_value(&n, parent, input, &id, skip); if (err < 0) goto __end; break; @@ -1061,7 +1061,7 @@ static int parse_array_def(snd_config_t *father, input_t *input, int idx, int sk return err; } -static int parse_array_defs(snd_config_t *father, input_t *input, int skip, int override) +static int parse_array_defs(snd_config_t *parent, input_t *input, int skip, int override) { int idx = 0; while (1) { @@ -1071,14 +1071,14 @@ static int parse_array_defs(snd_config_t *father, input_t *input, int skip, int unget_char(c, input); if (c == ']') return 0; - err = parse_array_def(father, input, idx++, skip, override); + err = parse_array_def(parent, input, idx++, skip, override); if (err < 0) return err; } return 0; } -static int parse_def(snd_config_t *father, input_t *input, int skip, int override) +static int parse_def(snd_config_t *parent, input_t *input, int skip, int override) { char *id = NULL; int c; @@ -1116,7 +1116,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid free(id); continue; } - if (_snd_config_search(father, id, -1, &n) == 0) { + if (_snd_config_search(parent, id, -1, &n) == 0) { if (mode == DONT_OVERRIDE) { skip = 1; free(id); @@ -1128,7 +1128,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid return -EINVAL; } n->u.compound.join = 1; - father = n; + parent = n; free(id); continue; } @@ -1139,11 +1139,11 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid err = -ENOENT; goto __end; } - err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); if (err < 0) goto __end; n->u.compound.join = 1; - father = n; + parent = n; } if (c == '=') { c = get_nonwhite(input); @@ -1151,7 +1151,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid return c; } if (!skip) { - if (_snd_config_search(father, id, -1, &n) == 0) { + if (_snd_config_search(parent, id, -1, &n) == 0) { if (mode == DONT_OVERRIDE) { skip = 1; n = NULL; @@ -1181,7 +1181,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid goto __end; } } else { - err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent); if (err < 0) goto __end; } @@ -1204,7 +1204,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid } default: unget_char(c, input); - err = parse_value(&n, father, input, &id, skip); + err = parse_value(&n, parent, input, &id, skip); if (err < 0) goto __end; break; @@ -1222,7 +1222,7 @@ static int parse_def(snd_config_t *father, input_t *input, int skip, int overrid return err; } -static int parse_defs(snd_config_t *father, input_t *input, int skip, int override) +static int parse_defs(snd_config_t *parent, input_t *input, int skip, int override) { int c, err; while (1) { @@ -1232,7 +1232,7 @@ static int parse_defs(snd_config_t *father, input_t *input, int skip, int overri unget_char(c, input); if (c == '}') return 0; - err = parse_def(father, input, skip, override); + err = parse_def(parent, input, skip, override); if (err < 0) return err; } @@ -1242,20 +1242,17 @@ static int parse_defs(snd_config_t *father, input_t *input, int skip, int overri 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: - assert(0); - break; case '0' ... '9': case '-': goto quoted; } } - if (!*p) { - snd_output_puts(out, "''"); - return; - } loop: switch (*p) { case 0: @@ -1327,10 +1324,11 @@ static void string_print(char *str, int id, snd_output_t *out) snd_output_putc(out, '\''); } -static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins); +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_leaf(snd_config_t *n, snd_output_t *out, - unsigned int level) +static int _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, + unsigned int level) { int err; unsigned int k; @@ -1353,7 +1351,7 @@ static int _snd_config_save_leaf(snd_config_t *n, snd_output_t *out, case SND_CONFIG_TYPE_COMPOUND: snd_output_putc(out, '{'); snd_output_putc(out, '\n'); - err = _snd_config_save_leaves(n, out, level + 1, 0); + err = _snd_config_save_children(n, out, level + 1, 0); if (err < 0) return err; for (k = 0; k < level; ++k) { @@ -1368,14 +1366,15 @@ static int _snd_config_save_leaf(snd_config_t *n, snd_output_t *out, static void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins) { if (joins > 0) { - assert(n->father); - id_print(n->father, out, joins - 1); + 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_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins) +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; @@ -1385,7 +1384,7 @@ static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsi snd_config_t *n = snd_config_iterator_entry(i); if (n->type == SND_CONFIG_TYPE_COMPOUND && n->u.compound.join) { - err = _snd_config_save_leaves(n, out, level, joins + 1); + err = _snd_config_save_children(n, out, level, joins + 1); if (err < 0) return err; continue; @@ -1399,7 +1398,7 @@ static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsi snd_output_putc(out, '='); #endif snd_output_putc(out, ' '); - err = _snd_config_save_leaf(n, out, level); + err = _snd_config_save_node_value(n, out, level); if (err < 0) return err; #if 0 @@ -1415,7 +1414,7 @@ static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsi /** * \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 \p dst. + * \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 @@ -1425,7 +1424,11 @@ static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsi * an ordinary type, the compound members are deleted (including * their contents). * - * A successful call to this function invalidates the source node. + * 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) { @@ -1435,7 +1438,7 @@ int snd_config_substitute(snd_config_t *dst, snd_config_t *src) snd_config_iterator_t i, next; snd_config_for_each(i, next, src) { snd_config_t *n = snd_config_iterator_entry(i); - n->father = dst; + n->parent = dst; } src->u.compound.fields.next->prev = &dst->u.compound.fields; src->u.compound.fields.prev->next = &dst->u.compound.fields; @@ -1455,10 +1458,23 @@ int snd_config_substitute(snd_config_t *dst, snd_config_t *src) /** * \brief Converts an ASCII string to a configuration node type. - * \param ascii A string containing a configuration node type. - * \param type The function puts the node type at the address specified - * by \p type. - * \return Zero if successgul, otherwise a negative error code. + * \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) { @@ -1490,6 +1506,9 @@ int snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type) * \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) { @@ -1498,13 +1517,19 @@ snd_config_type_t snd_config_get_type(const snd_config_t *config) /** * \brief Returns the id of a configuration node. - * \param config Handle to the configuration node. - * \param id The function puts the pointer to the id string at the address - * specified by \p id. + * \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. + * 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) { @@ -1516,16 +1541,39 @@ int snd_config_get_id(const snd_config_t *config, const char **id) /** * \brief Sets the id of a configuration node. * \param config Handle to the configuration node. - * \param id The new node id. + * \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 && id); - new_id = strdup(id); - if (!new_id) - return -ENOMEM; + 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; @@ -1533,11 +1581,19 @@ int snd_config_set_id(snd_config_t *config, const char *id) /** * \brief Creates a top level configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. + * \param[out] config Handle to the new node. * \return Zero if successful, otherwise a negative error code. * - * The returned node is a compound node. + * 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) { @@ -1611,6 +1667,16 @@ static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override) * \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) { @@ -1622,6 +1688,10 @@ int snd_config_load(snd_config_t *config, snd_input_t *in) * \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) { @@ -1630,21 +1700,41 @@ int snd_config_load_override(snd_config_t *config, snd_input_t *in) /** * \brief Adds a child to a compound configuration node. - * \param father Handle to the compound configuration node. - * \param leaf Handle to the configuration node to be added to \p father. + * \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 *father, snd_config_t *leaf) +int snd_config_add(snd_config_t *parent, snd_config_t *child) { snd_config_iterator_t i, next; - assert(father && leaf); - snd_config_for_each(i, next, father) { + 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(leaf->id, n->id) == 0) + if (strcmp(child->id, n->id) == 0) return -EEXIST; } - leaf->father = father; - list_add_tail(&leaf->list, &father->u.compound.fields); + child->parent = parent; + list_add_tail(&child->list, &parent->u.compound.fields); return 0; } @@ -1653,25 +1743,40 @@ int snd_config_add(snd_config_t *father, snd_config_t *leaf) * \param config Handle to the configuration node to be removed. * \return Zero if successful, otherwise a negative error code. * - * This functions does \e not delete the removed node. + * 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->father) + if (config->parent) list_del(&config->list); - config->father = NULL; + config->parent = NULL; return 0; } /** - * \brief Deletes a configuration node (freeing all its related resources). + * \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, all children are deleted - * recursively. + * deleted. + * + * If the node is a compound node, its descendants (the whole subtree) + * are deleted recursively. + * + * \par Conforming to: + * LSB 3.2 + * + * \sa snd_config_remove */ int snd_config_delete(snd_config_t *config) { @@ -1684,8 +1789,8 @@ int snd_config_delete(snd_config_t *config) i = config->u.compound.fields.next; while (i != &config->u.compound.fields) { struct list_head *nexti = i->next; - snd_config_t *leaf = snd_config_iterator_entry(i); - err = snd_config_delete(leaf); + snd_config_t *child = snd_config_iterator_entry(i); + err = snd_config_delete(child); if (err < 0) return err; i = nexti; @@ -1698,7 +1803,7 @@ int snd_config_delete(snd_config_t *config) default: break; } - if (config->father) + if (config->parent) list_del(&config->list); free(config->id); free(config); @@ -1706,11 +1811,22 @@ int snd_config_delete(snd_config_t *config) } /** - * \brief Deletes the children of a compound configuration node (freeing all its related resources) + * \brief Deletes the children of a node. * \param config Handle to the compound configuration node. * \return Zero if successful, otherwise a negative error code. * - * Any compound nodes among the children of \p config are deleted recursively. + * 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) { @@ -1723,8 +1839,8 @@ int snd_config_delete_compound_members(const snd_config_t *config) i = config->u.compound.fields.next; while (i != &config->u.compound.fields) { struct list_head *nexti = i->next; - snd_config_t *leaf = snd_config_iterator_entry(i); - err = snd_config_delete(leaf); + snd_config_t *child = snd_config_iterator_entry(i); + err = snd_config_delete(child); if (err < 0) return err; i = nexti; @@ -1734,11 +1850,22 @@ int snd_config_delete_compound_members(const snd_config_t *config) /** * \brief Creates a configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param type The type of the new 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) @@ -1756,12 +1883,23 @@ int snd_config_make(snd_config_t **config, const char *id, /** * \brief Creates an integer configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new 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. * - * The value of the new node is 0. + * 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) { @@ -1769,13 +1907,24 @@ int snd_config_make_integer(snd_config_t **config, const char *id) } /** - * \brief Creates an integer64 configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. + * \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. * - * The value of the new node is 0. + * 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) { @@ -1783,13 +1932,21 @@ int snd_config_make_integer64(snd_config_t **config, const char *id) } /** - * \brief Creates a real configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. + * \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. * - * The value of the new node is 0.0. + * 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) { @@ -1798,12 +1955,23 @@ int snd_config_make_real(snd_config_t **config, const char *id) /** * \brief Creates a string configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new 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. * - * The value of the new node is \c NULL. + * 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) { @@ -1812,12 +1980,20 @@ int snd_config_make_string(snd_config_t **config, const char *id) /** * \brief Creates a pointer configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new 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. * - * The value of the new node is \c NULL. + * 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) { @@ -1826,12 +2002,41 @@ int snd_config_make_pointer(snd_config_t **config, const char *id) /** * \brief Creates an empty compound configuration node. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param join Join flag. - * This is checked in #snd_config_save to change look. (Huh?) + * \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) @@ -1846,11 +2051,22 @@ int snd_config_make_compound(snd_config_t **config, const char *id, /** * \brief Creates an integer configuration node with the given initial value. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param value The initial value of the new 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] 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) { @@ -1864,12 +2080,23 @@ int snd_config_imake_integer(snd_config_t **config, const char *id, const long v } /** - * \brief Creates an integer configuration node with the given initial value. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param value The initial value of the new node. + * \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) { @@ -1883,12 +2110,20 @@ int snd_config_imake_integer64(snd_config_t **config, const char *id, const long } /** - * \brief Creates a real configuration node with the given initial value. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param value The initial value of the new node. + * \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) { @@ -1903,13 +2138,22 @@ int snd_config_imake_real(snd_config_t **config, const char *id, const double va /** * \brief Creates a string configuration node with the given initial value. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param value The initial value of the new node. May be \c NULL. + * \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 the new node with its own copy of the passed string. + * 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) { @@ -1934,11 +2178,19 @@ int snd_config_imake_string(snd_config_t **config, const char *id, const char *v /** * \brief Creates a pointer configuration node with the given initial value. - * \param config The function puts the handle to the new node at the address - * specified by \p config. - * \param id The id of the new node. - * \param value The initial value of the new node. May be \c NULL. + * \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) { @@ -1956,6 +2208,14 @@ int snd_config_imake_pointer(snd_config_t **config, const char *id, const void * * \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) { @@ -1967,10 +2227,18 @@ int snd_config_set_integer(snd_config_t *config, long value) } /** - * \brief Changes the value of an integer64 configuration node. + * \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) { @@ -1982,10 +2250,15 @@ int snd_config_set_integer64(snd_config_t *config, long long value) } /** - * \brief Changes the value of a real configuration node. + * \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) { @@ -1999,11 +2272,19 @@ int snd_config_set_real(snd_config_t *config, double value) /** * \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. + * \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 - * the passed string in the node. + * \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) { @@ -2026,10 +2307,15 @@ int snd_config_set_string(snd_config_t *config, const char *value) /** * \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. + * \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) { @@ -2043,11 +2329,27 @@ int snd_config_set_pointer(snd_config_t *config, const void *value) /** * \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. \p ascii must - * not be \c NULL, not even for a string node. + * \param ascii The new value for the node, as an ASCII string. * \return Zero if successful, otherwise a negative error code. * - * The node must have a simple type, and the new value must have the same type. + * 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) { @@ -2097,10 +2399,17 @@ int snd_config_set_ascii(snd_config_t *config, const char *ascii) /** * \brief Returns the value of an integer configuration node. - * \param config Handle to the configuration node. - * \param ptr The function puts the node's value at the address specified - * by \p ptr. + * \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) { @@ -2112,11 +2421,18 @@ int snd_config_get_integer(const snd_config_t *config, long *ptr) } /** - * \brief Returns the value of an integer64 configuration node. - * \param config Handle to the configuration node. - * \param ptr The function puts the node's value at the address specified - * by \p ptr. + * \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) { @@ -2128,11 +2444,15 @@ int snd_config_get_integer64(const snd_config_t *config, long long *ptr) } /** - * \brief Returns the value of a real configuration node. - * \param config Handle to the configuration node. - * \param ptr The function puts the node's value at the address specified - * by \p ptr. + * \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) { @@ -2145,13 +2465,17 @@ int snd_config_get_real(const snd_config_t *config, double *ptr) /** * \brief Returns the value of a real or integer configuration node. - * \param config Handle to the configuration node. - * \param ptr The function puts the node's value at the address specified - * by \p ptr. + * \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) { @@ -2169,13 +2493,24 @@ int snd_config_get_ireal(const snd_config_t *config, double *ptr) /** * \brief Returns the value of a string configuration node. - * \param config Handle to the configuration node. - * \param ptr The function puts the node's value at the address specified - * by \p ptr. + * \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. + * 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) { @@ -2188,10 +2523,15 @@ int snd_config_get_string(const snd_config_t *config, const char **ptr) /** * \brief Returns the value of a pointer configuration node. - * \param config Handle to the configuration node. - * \param ptr The function puts the node's value at the address specified - * by \p ptr. + * \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) { @@ -2204,13 +2544,30 @@ int snd_config_get_pointer(const snd_config_t *config, const void **ptr) /** * \brief Returns the value of a configuration node as a string. - * \param config Handle to the configuration node. - * \param ascii The function puts the pointer to the returned string at the - * address specified by \p ascii. + * \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. + * 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) { @@ -2281,12 +2638,18 @@ int snd_config_get_ascii(const snd_config_t *config, char **ascii) * \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. + * \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); - return strcmp(config->id, id); + if (config->id) + return strcmp(config->id, id); + else + return -1; } /** @@ -2294,14 +2657,26 @@ int snd_config_test_id(const snd_config_t *config, const char *id) * \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_leaves(config, out, 0, 0); + return _snd_config_save_children(config, out, 0, 0); else - return _snd_config_save_leaf(config, out, 0); + return _snd_config_save_node_value(config, out, 0); } /* @@ -2426,6 +2801,7 @@ int snd_config_save(snd_config_t *config, snd_output_t *out) } \ 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?)"); \ @@ -2451,11 +2827,43 @@ int snd_config_save(snd_config_t *config, snd_output_t *out) /** * \brief Searches for a node in a configuration tree. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param key Search key: one or more node keys, separated with dots. - * \param result The function puts the handle to the node found at the address - * specified by \p result. + * \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) { @@ -2464,13 +2872,53 @@ int snd_config_search(snd_config_t *config, const char *key, snd_config_t **resu /** * \brief Searches for a node in a configuration tree, expanding aliases. - * \param root Handle to the root configuration node containing alias - * definitions. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param key Search key: one or more node keys, separated with dots. - * \param result The function puts the handle to the node found at the address - * specified by \p result. + * \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) { @@ -2479,11 +2927,34 @@ int snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key /** * \brief Searches for a node in a configuration tree. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param result The function puts the handle to the node found at the address - * specified by \p result. - * \param ... One or more concatenated dot separated search keys, terminated with \c NULL. + * \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, ...) { @@ -2492,13 +2963,27 @@ int snd_config_searchv(snd_config_t *config, snd_config_t **result, ...) /** * \brief Searches for a node in a configuration tree, expanding aliases. - * \param root Handle to the root configuration node containing alias - * definitions. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param result The function puts the handle to the node found at the address - * specified by \p result. - * \param ... One or more concatenated dot separated search keys, terminated with \c NULL. + * \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, ...) { @@ -2506,17 +2991,30 @@ int snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t * } /** - * \brief Searches for a node in a configuration tree, using an alias. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param base Search key base, or \c NULL. - * \param key Search key suffix. - * \param result The function puts the handle to the node found at the address - * specified by \p result. + * \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. * - * First \c key is tried, then, if nothing is found, \c base.key is tried. - * If the value found is a string, this is recursively tried in the - * same way. + * 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, @@ -2530,11 +3028,25 @@ 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 config Handle to the root of the configuration (sub)tree to search. - * \param key Search key: one or more node keys, separated with dots. - * \param result The function puts the handle to the node found at the address - * specified by \p result. + * \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) { @@ -2547,13 +3059,27 @@ int snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t /** * \brief Searches for a node in a configuration tree, expanding aliases and hooks. - * \param root Handle to the root configuration node containing alias - * definitions. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param key Search key: one or more node keys, separated with dots. - * \param result The function puts the handle to the node found at the address - * specified by \p result. + * \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) { @@ -2567,13 +3093,29 @@ int snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const cha /** * \brief Searches for a node in a configuration tree, expanding aliases and hooks. - * \param root Handle to the root configuration node containing alias - * definitions. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param result The function puts the handle to the node found at the address - * specified by \p result. - * \param ... One or more concatenated dot separated search keys, terminated with \c NULL. + * \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, ...) @@ -2583,16 +3125,26 @@ int snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config, /** * \brief Searches for a node in a configuration tree, using an alias and expanding hooks. - * \param config Handle to the root of the configuration (sub)tree to search. - * \param base Search key base, or \c NULL. - * \param key Search key suffix. - * \param result The function puts the handle to the node found at the address - * specified by \p result. + * \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. * - * First \c key is tried, then, if nothing is found, \c base.key is tried. - * If the value found is a string, this is recursively tried in the - * same way. + * 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, @@ -2611,7 +3163,26 @@ int snd_config_search_alias_hooks(snd_config_t *config, /** * \ingroup Config - * Configuration top level node (the global configuration). + * \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; @@ -2651,6 +3222,7 @@ static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_c 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; @@ -2760,12 +3332,15 @@ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data) /** * \brief Loads and parses the given configurations files. - * \param root Handle to the root configuration node. - * \param config Handle to the configuration node for this hook. - * \param dst The function puts the handle to the configuration node loaded - * from the file(s) at the address specified by \p dst. - * \param private_data Handle to the private data configuration node. + * \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) { @@ -2873,13 +3448,19 @@ int snd_determine_driver(int card, char **driver); #endif /** - * \brief Loads and parses the given configurations files for each installed sound card. - * \param root Handle to the root configuration node. - * \param config Handle to the configuration node for this hook. - * \param dst The function puts the handle to the configuration node loaded - * from the file(s) at the address specified by \p dst. - * \param private_data Handle to the private data configuration node. + * \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) { @@ -2899,6 +3480,7 @@ int snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, 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) @@ -2931,20 +3513,30 @@ SND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VER /** * \brief Updates a configuration tree by rereading the configuration files (if needed). - * \param _top Address of the handle to the top level node. - * \param _update Address of a pointer to private update information. - * \param cfgs A list of configuration file names, delimited with ':'. - * If \p cfgs is set to \c NULL, the default global configuration - * file is used ("/usr/share/alsa/alsa.conf"). - * \return A non-negative value if successful, otherwise a negative error code. - * \retval 0 No action is needed. - * \retval 1 The configuration tree has been rebuilt. + * \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. + * 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) { @@ -3090,16 +3682,19 @@ static pthread_mutex_t snd_config_update_mutex = PTHREAD_MUTEX_INITIALIZER; /** * \brief Updates #snd_config by rereading the global configuration files (if needed). - * \return A non-negative value if successful, otherwise a negative error code. - * \retval 0 No action is needed. - * \retval 1 The configuration tree has been rebuilt. + * \return 0 if #snd_config was up to date, 1 if #snd_config was + * updated, otherwise a negative error code. * - * 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 #snd_config is updated, all string pointers and + * configuration node handles previously obtained from it may become + * invalid. * - * \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. + * + * \par Conforming to: + * LSB 3.2 */ int snd_config_update(void) { @@ -3117,7 +3712,7 @@ int snd_config_update(void) /** * \brief Frees a private update structure. - * \param update The private update structure to free. + * \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) @@ -3135,6 +3730,12 @@ int snd_config_update_free(snd_config_update_t *update) /** * \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) { @@ -3157,23 +3758,40 @@ int snd_config_update_free_global(void) } /** - * \brief Returns an iterator pointing to the first child of a compound configuration node. - * \param node Handle to the compound configuration node. - * \return An iterator pointing to the first child. + * \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 *node) +snd_config_iterator_t snd_config_iterator_first(const snd_config_t *config) { - assert(node->type == SND_CONFIG_TYPE_COMPOUND); - return node->u.compound.fields.next; + assert(config->type == SND_CONFIG_TYPE_COMPOUND); + return config->u.compound.fields.next; } /** * \brief Returns an iterator pointing to the next sibling. - * \param iterator An iterator pointing to a child configuration node. - * \return An iterator pointing to the next sibling of \p iterator. - * If \p iterator is the last sibling, the returned value is the same - * as the result of calling #snd_config_iterator_end on the father - * of the nodes. + * \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) { @@ -3181,20 +3799,31 @@ snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t itera } /** - * \brief Returns an iterator pointing past the last child of a compound configuration node. - * \param node Handle to the compound configuration node. - * \return An iterator pointing past the last child of \p node. + * \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 *node) +snd_config_iterator_t snd_config_iterator_end(const snd_config_t *config) { - assert(node->type == SND_CONFIG_TYPE_COMPOUND); - return (const snd_config_iterator_t)&node->u.compound.fields; + 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 iterator A configuration node iterator. - * \return The configuration node handle pointed to by \p 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) { @@ -3209,7 +3838,7 @@ typedef enum _snd_config_walk_pass { } snd_config_walk_pass_t; #endif -/* Return 1 if node needs to be attached to father */ +/* 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, @@ -3327,10 +3956,21 @@ static int _snd_config_copy(snd_config_t *src, /** * \brief Creates a copy of a configuration node. - * \param dst The function puts the handle to the new configuration node - * at the address specified by \p dst. - * \param src Handle to the source 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) @@ -3350,7 +3990,7 @@ static int _snd_config_expand(snd_config_t *src, switch (pass) { case SND_CONFIG_WALK_PASS_PRE: { - if (strcmp(id, "@args") == 0) + if (id && strcmp(id, "@args") == 0) return 0; err = snd_config_make_compound(dst, id, src->u.compound.join); if (err < 0) @@ -3395,7 +4035,7 @@ static int _snd_config_expand(snd_config_t *src, snd_config_t *val; snd_config_t *vars = private_data; snd_config_get_string(src, &s); - if (*s == '$') { + if (s && *s == '$') { s++; if (snd_config_search(vars, s, &val) < 0) return 0; @@ -3447,6 +4087,7 @@ static int _snd_config_evaluate(snd_config_t *src, 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; @@ -3531,14 +4172,14 @@ static int _snd_config_evaluate(snd_config_t *src, /** * \brief Evaluates a configuration node at runtime. - * \param config Handle to the source configuration node. - * \param root Handle to the root of the source configuration. - * \param private_data Handle to the private data node for runtime evaluation. - * \param result The function puts the handle to the result node at the - * address specified by \p result. \p result is \c NULL for - * in-place evaluation. + * \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. - * \note Only in-place evaluation is currently implemented. + * + * 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) @@ -3859,7 +4500,7 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) goto _err; } err = snd_config_get_string(typ, &tmp); - if (err < 0) + if (err < 0 || !tmp) goto _invalid_type; if (strcmp(tmp, "integer") == 0) { long v; @@ -3932,14 +4573,21 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) } /** - * \brief Expands a configuration node applying arguments and functions. - * \param config Handle to the configuration node. - * \param root Handle to the root configuration node. - * \param args Arguments string (optional). - * \param private_data Handle to the private data node for functions. - * \param result The function puts the handle to the result configuration node - * at the address specified by \p result. + * \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) @@ -3995,20 +4643,33 @@ int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args } /** - * \brief Searches for a definition in a configuration tree, using aliases and expanding hooks and arguments. - * \param config Handle to the configuration (sub)tree to search. - * \param base Implicit key base, or \c NULL for none. - * \param name Key suffix. - * \param result The function puts the handle to the expanded found node at - * the address specified by \p result. + * \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. * - * First the key is tried, then, if nothing is found, base.key is tried. - * If the value found is a string, this is recursively tried in the - * same way. + * 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. * - * If \p key contains a dot (.), the implicit base is ignored and the key - * starts from the root given by \p config. + * \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, diff --git a/src/conf/cards/CMI8788.conf b/src/conf/cards/CMI8788.conf index 26910d51..0ca71e9d 100644 --- a/src/conf/cards/CMI8788.conf +++ b/src/conf/cards/CMI8788.conf @@ -13,7 +13,7 @@ CMI8788.pcm.front.0 { card $CARD } -# default with dmix+softvol & dsnoop +# default with dmix & dsnoop CMI8788.pcm.default { @args [ CARD ] @args.CARD { @@ -23,15 +23,8 @@ CMI8788.pcm.default { playback.pcm { type plug slave.pcm { - type softvol - slave.pcm { - @func concat - strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] - } - control { - name "PCM Playback Volume" - card $CARD - } + @func concat + strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] } } capture.pcm { diff --git a/src/conf/cards/GUS.conf b/src/conf/cards/GUS.conf index 80e30589..d744c548 100644 --- a/src/conf/cards/GUS.conf +++ b/src/conf/cards/GUS.conf @@ -17,50 +17,3 @@ GUS.pcm.front.0 { card $CARD } } - -# -# It's a temporary solution. -# - -!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 - mmap_emulation on -} diff --git a/src/conf/cards/HDA-Intel.conf b/src/conf/cards/HDA-Intel.conf index bcbcb9b5..d3ac0021 100644 --- a/src/conf/cards/HDA-Intel.conf +++ b/src/conf/cards/HDA-Intel.conf @@ -57,7 +57,10 @@ HDA-Intel.pcm.default { max_dB 30.0 resolution 121 } + # to avoid possible phase inversions with digital mics + route_policy copy } + hint.device 0 } diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am index f4d6c17b..9da78f01 100644 --- a/src/conf/cards/Makefile.am +++ b/src/conf/cards/Makefile.am @@ -41,6 +41,7 @@ cfg_files = aliases.conf \ RME9636.conf \ RME9652.conf \ SI7018.conf \ + SB-XFi.conf \ TRID4DWAVENX.conf \ USB-Audio.conf \ YMF744.conf \ diff --git a/src/conf/cards/Makefile.in b/src/conf/cards/Makefile.in index b44be0f3..f34fe1e9 100644 --- a/src/conf/cards/Makefile.in +++ b/src/conf/cards/Makefile.in @@ -272,10 +272,10 @@ cfg_files = aliases.conf AACI.conf ATIIXP.conf ATIIXP-SPDMA.conf \ GUS.conf HDA-Intel.conf ICE1712.conf ICE1724.conf ICH.conf \ ICH4.conf ICH-MODEM.conf Maestro3.conf NFORCE.conf \ PC-Speaker.conf PMac.conf PMacToonie.conf PS3.conf \ - RME9636.conf RME9652.conf SI7018.conf TRID4DWAVENX.conf \ - USB-Audio.conf YMF744.conf VIA686A.conf VIA8233.conf \ - VIA8233A.conf VIA8237.conf VX222.conf VXPocket.conf \ - VXPocket440.conf $(am__append_1) + RME9636.conf RME9652.conf SI7018.conf SB-XFi.conf \ + TRID4DWAVENX.conf USB-Audio.conf YMF744.conf VIA686A.conf \ + VIA8233.conf VIA8233A.conf VIA8237.conf VX222.conf \ + VXPocket.conf VXPocket440.conf $(am__append_1) alsa_DATA = $(cfg_files) @BUILD_ALISP_TRUE@SI7018dir = $(alsaconfigdir)/cards/SI7018 @BUILD_ALISP_FALSE@SI7018_files = diff --git a/src/conf/cards/SB-XFi.conf b/src/conf/cards/SB-XFi.conf new file mode 100644 index 00000000..38d0027f --- /dev/null +++ b/src/conf/cards/SB-XFi.conf @@ -0,0 +1,108 @@ +# +# Configuration for the SB X-Fi driver +# + + + +SB-XFi.pcm.front.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 0 +} + + + +SB-XFi.pcm.rear.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 1 + hint.device 1 +} + + + +SB-XFi.pcm.center_lfe.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 2 + hint.device 2 +} + + + +SB-XFi.pcm.side.0 { + @args [ CARD ] + @args.CARD { + type string + } + type hw + card $CARD + device 3 + hint.device 3 +} + + + + + + + +SB-XFi.pcm.surround40.0 cards.SB-XFi.pcm.front.0 +SB-XFi.pcm.surround51.0 cards.SB-XFi.pcm.front.0 +SB-XFi.pcm.surround71.0 cards.SB-XFi.pcm.front.0 + + + +SB-XFi.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type asym + playback.pcm { + type hooks + slave.pcm { + type hw + card $CARD + device 4 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface PCM + name "IEC958 Playback PCM Stream" + device 4 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + } + hint.device 4 +} diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf index d6fbec5d..5849e3f3 100644 --- a/src/conf/cards/USB-Audio.conf +++ b/src/conf/cards/USB-Audio.conf @@ -40,11 +40,48 @@ USB-Audio.pcm.iec958_device { # If a device requires non-standard definitions for front, surround40, # surround51, surround71 or iec958, they can be defined here. -# USB-Audio."NoiseBlaster 3000".pcm.surround51 { -# @args [ CARD ] -# @args.CARD { type string } -# ... -# } +# M-Audio AudioPhile USB: +# device 0: analog output, digital input +# device 1: digital output, analog input +USB-Audio."AudioPhile".pcm.default { + @args [ CARD ] + @args.CARD { type string } + type asym + playback.pcm { + type plug + slave.pcm { + type hw + card $CARD + device 0 + } + } + capture.pcm { + type plug + slave.pcm { + @func concat + strings [ "dsnoop:DEVICE=1,CARD=" $CARD ] + } + } +} +USB-Audio."AudioPhile".pcm.iec958 { + @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 + } +} ################################################################################ diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf index 4108ddb6..e62cb295 100644 --- a/src/conf/pcm/dmix.conf +++ b/src/conf/pcm/dmix.conf @@ -63,12 +63,12 @@ pcm.!dmix { name { @func concat strings [ - "cards." + "defaults.dmix." { @func card_driver card $CARD } - ".pcm.dmix.period_size" + ".period_size" ] } default 1024 @@ -78,12 +78,12 @@ pcm.!dmix { name { @func concat strings [ - "cards." + "defaults.dmix." { @func card_driver card $CARD } - ".pcm.dmix.period_time" + ".period_time" ] } default -1 @@ -93,12 +93,12 @@ pcm.!dmix { name { @func concat strings [ - "cards." + "defaults.dmix." { @func card_driver card $CARD } - ".pcm.dmix.periods" + ".periods" ] } default 16 diff --git a/src/control/cards.c b/src/control/cards.c index 4d2c7394..0bb8f861 100644 --- a/src/control/cards.c +++ b/src/control/cards.c @@ -39,27 +39,40 @@ #define SND_FILE_LOAD ALOAD_DEVICE_DIRECTORY "aloadC%i" #endif -static int snd_card_load1(int card) +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); - - open_dev = snd_open_device(control, O_RDONLY); + res = snd_card_load2(control); #ifdef SUPPORT_ALOAD - if (open_dev < 0) { + if (res < 0) { char aload[sizeof(SND_FILE_LOAD) + 10]; sprintf(aload, SND_FILE_LOAD, card); - open_dev = snd_open_device(aload, O_RDONLY); + res = snd_card_load2(aload); } #endif - if (open_dev >= 0) { - close (open_dev); - return 0; - } else { - return -errno; - } + return res; } /** @@ -69,7 +82,7 @@ static int snd_card_load1(int card) */ int snd_card_load(int card) { - return !!(snd_card_load1(card) == 0); + return !!(snd_card_load1(card) >= 0); } /** @@ -107,6 +120,7 @@ int snd_card_next(int *rcard) * * 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) { @@ -127,6 +141,8 @@ int snd_card_get_index(const char *string) return card; return err; } + if (string[0] == '/') /* device name */ + return snd_card_load2(string); for (card = 0; card < 32; card++) { #ifdef SUPPORT_ALOAD if (! snd_card_load(card)) diff --git a/src/control/control.c b/src/control/control.c index c0907973..b63a28cd 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -211,7 +211,7 @@ int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsign } /** - * \brief Ask to be informed about events (poll, #snd_ctl_async, #snd_ctl_read) + * \brief Ask to be informed about events (poll, #snd_async_add_ctl_handler, #snd_ctl_read) * \param ctl CTL handle * \param subscribe 0 = unsubscribe, 1 = subscribe * \return 0 on success otherwise a negative error code @@ -674,8 +674,8 @@ int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_event_t *event) int snd_ctl_wait(snd_ctl_t *ctl, int timeout) { struct pollfd *pfd; - unsigned short *revents; - int i, npfds, pollio, err, err_poll; + unsigned short revents; + int npfds, err, err_poll; npfds = snd_ctl_poll_descriptors_count(ctl); if (npfds <= 0 || npfds >= 16) { @@ -683,7 +683,6 @@ int snd_ctl_wait(snd_ctl_t *ctl, int timeout) return -EIO; } pfd = alloca(sizeof(*pfd) * npfds); - revents = alloca(sizeof(*revents) * npfds); err = snd_ctl_poll_descriptors(ctl, pfd, npfds); if (err < 0) return err; @@ -691,26 +690,20 @@ int snd_ctl_wait(snd_ctl_t *ctl, int timeout) SNDMSG("invalid poll descriptors %d\n", err); return -EIO; } - do { + for (;;) { err_poll = poll(pfd, npfds, timeout); if (err_poll < 0) return -errno; if (! err_poll) - break; - err = snd_ctl_poll_descriptors_revents(ctl, pfd, npfds, revents); + return 0; + err = snd_ctl_poll_descriptors_revents(ctl, pfd, npfds, &revents); if (err < 0) return err; - pollio = 0; - 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; + if (revents & (POLLERR | POLLNVAL)) + return -EIO; + if (revents & (POLLIN | POLLOUT)) + return 1; + } } /** @@ -2256,6 +2249,18 @@ void snd_ctl_elem_value_copy(snd_ctl_elem_value_t *dst, const snd_ctl_elem_value } /** + * \brief compare one #snd_ctl_elem_value_t to another + * \param dst pointer to destination + * \param src pointer to source + * \return 0 on match, less than or greater than otherwise, see memcmp + */ +int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, const snd_ctl_elem_value_t *right) +{ + assert(left && right); + return memcmp(left, right, sizeof(*left)); +} + +/** * \brief Get CTL element identifier of a CTL element id/value * \param obj CTL element id/value * \param ptr Pointer to returned CTL element identifier diff --git a/src/control/control_ext.c b/src/control/control_ext.c index a8675c13..e20d4f3b 100644 --- a/src/control/control_ext.c +++ b/src/control/control_ext.c @@ -107,6 +107,7 @@ static int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) ret = ext->callback->elem_list(ext, offset, ids); if (ret < 0) return ret; + ids->numid = offset + 1; /* fake number */ list->used++; offset++; ids++; @@ -114,13 +115,24 @@ static int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) 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 = ext->callback->find_elem(ext, &info->id); + 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); @@ -200,7 +212,7 @@ static int snd_ctl_ext_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *contro int type, ret; unsigned int access, count; - key = ext->callback->find_elem(ext, &control->id); + 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); @@ -254,7 +266,7 @@ static int snd_ctl_ext_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *contr int type, ret; unsigned int access, count; - key = ext->callback->find_elem(ext, &control->id); + 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); @@ -574,7 +586,7 @@ 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_ifarce, +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. diff --git a/src/control/control_hw.c b/src/control/control_hw.c index e9a6be27..cf258b43 100644 --- a/src/control/control_hw.c +++ b/src/control/control_hw.c @@ -392,17 +392,6 @@ int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) if (fd < 0) return -errno; } -#if 0 - /* - * this is bogus, an application have to care about open filedescriptors - */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - SYSERR("fcntl FD_CLOEXEC failed"); - err = -errno; - close(fd); - return err; - } -#endif if (ioctl(fd, SNDRV_CTL_IOCTL_PVERSION, &ver) < 0) { err = -errno; close(fd); diff --git a/src/control/hcontrol.c b/src/control/hcontrol.c index 181e7672..8ffc434f 100644 --- a/src/control/hcontrol.c +++ b/src/control/hcontrol.c @@ -48,9 +48,6 @@ to reduce overhead accessing the real controls in kernel drivers. #include #include #include -#ifndef DOC_HIDDEN -#define __USE_GNU -#endif #include "control_local.h" #ifdef HAVE_LIBPTHREAD #include @@ -471,8 +468,9 @@ int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, const snd_hctl_elem_t *c2) { - int res; - int d = c1->id.iface - c2->id.iface; + int res, d; + + d = c1->id.iface - c2->id.iface; if (d != 0) return d; if (c1->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER) { @@ -480,11 +478,16 @@ static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, 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; - d = c1->id.index - c2->id.index; - return d; + return c1->id.index - c2->id.index; } /** diff --git a/src/control/namehint.c b/src/control/namehint.c index e878f830..78572d86 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -219,6 +219,7 @@ static int try_config(struct hint_list *list, const char *str; int err = 0, level; long dev = list->device; + int cleanup_res = 0; list->device_input = -1; list->device_output = -1; @@ -244,6 +245,7 @@ static int try_config(struct hint_list *list, snd_lib_error_set_handler(eh); if (err < 0) goto __skip_add; + cleanup_res = 1; err = -EINVAL; if (snd_config_get_type(res) != SND_CONFIG_TYPE_COMPOUND) goto __cleanup; @@ -330,6 +332,7 @@ static int try_config(struct hint_list *list, goto __hint; snd_config_delete(res); res = NULL; + cleanup_res = 0; if (strchr(buf, ':') != NULL) goto __ok; /* find, if all parameters have a default, */ @@ -379,7 +382,7 @@ static int try_config(struct hint_list *list, err = hint_list_add(list, buf, buf1); } __skip_add: - if (res) + if (res && cleanup_res) snd_config_delete(res); if (buf1) free(buf1); @@ -450,13 +453,10 @@ static int add_card(struct hint_list *list, int card) if (err == -EXDEV) continue; if (err < 0) { + list->card = card; list->device = -1; err = try_config(list, list->siface, str); } - if (err < 0) { - list->card = -1; - err = try_config(list, list->siface, str); - } if (err == -ENOMEM) goto __error; } @@ -482,6 +482,29 @@ static int get_card_name(struct hint_list *list, int card) return 0; } +static int add_software_devices(struct hint_list *list) +{ + int err; + snd_config_t *conf, *n; + snd_config_iterator_t i, next; + const char *str; + + err = snd_config_search(snd_config, list->siface, &conf); + if (err < 0) + return err; + snd_config_for_each(i, next, conf) { + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &str) < 0) + continue; + list->card = -1; + list->device = -1; + err = try_config(list, list->siface, str); + if (err == -ENOMEM) + return -ENOMEM; + } + return 0; +} + /** * \brief Return string list with device name hints. * \param card Card number or -1 (means all cards) @@ -532,6 +555,8 @@ int snd_device_name_hint(int card, const char *iface, void ***hints) list.iface = SND_CTL_ELEM_IFACE_SEQUENCER; else if (strcmp(iface, "hwdep") == 0) list.iface = SND_CTL_ELEM_IFACE_HWDEP; + else if (strcmp(iface, "ctl") == 0) + list.iface = SND_CTL_ELEM_IFACE_MIXER; else return -EINVAL; list.show_all = 0; @@ -543,6 +568,7 @@ int snd_device_name_hint(int card, const char *iface, void ***hints) if (err >= 0) err = add_card(&list, card); } else { + add_software_devices(&list); err = snd_card_next(&card); if (err < 0) goto __error; diff --git a/src/control/setup.c b/src/control/setup.c index 408244e2..eecda457 100644 --- a/src/control/setup.c +++ b/src/control/setup.c @@ -192,7 +192,17 @@ int snd_sctl_remove(snd_sctl_t *h) return err; } } - if (elem->preserve) { + /* 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"); diff --git a/src/control/tlv.c b/src/control/tlv.c index 0006a87c..cfd9b973 100644 --- a/src/control/tlv.c +++ b/src/control/tlv.c @@ -89,6 +89,8 @@ int snd_tlv_parse_dB_info(unsigned int *tlv, } 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 @@ -165,6 +167,8 @@ int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, *max = *min + (long)(step * (rangemax - rangemin)); return 0; } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: case SND_CTL_TLVT_DB_LINEAR: *min = (int)tlv[2]; *max = (int)tlv[3]; @@ -214,6 +218,23 @@ int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, *db_gain = (volume - rangemin) * step + min; return 0; } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: { + int mindb, maxdb; + mindb = tlv[2]; + maxdb = tlv[3]; + if (volume <= rangemin || rangemax <= rangemin) { + if (tlv[0] == SND_CTL_TLVT_DB_MINMAX_MUTE) + *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; + else + *db_gain = mindb; + } else if (volume >= rangemax) + *db_gain = maxdb; + else + *db_gain = (maxdb - mindb) * (volume - rangemin) / + (rangemax - rangemin) + mindb; + return 0; + } #ifndef HAVE_SOFT_FLOAT case SND_CTL_TLVT_DB_LINEAR: { int mindb = tlv[2]; @@ -297,6 +318,24 @@ int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, } return 0; } + case SND_CTL_TLVT_DB_MINMAX: + case SND_CTL_TLVT_DB_MINMAX_MUTE: { + int min, max; + min = tlv[2]; + max = tlv[3]; + if (db_gain <= min) + *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; @@ -366,7 +405,6 @@ static int get_tlv_info(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, * \brief Get the dB min/max values on the given control element * \param ctl the control handler * \param id the element id - * \param volume the raw volume value to convert * \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 diff --git a/src/dlmisc.c b/src/dlmisc.c index b84eaf6c..a0d62d38 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -27,7 +27,6 @@ * */ -#define _GNU_SOURCE #include "list.h" #include "local.h" @@ -54,13 +53,13 @@ void *snd_dlopen(const char *name, int mode) #else #ifdef HAVE_LIBDL if (name == NULL) { -#ifdef ANDROID - return RTLD_DEFAULT; -#else - Dl_info dlinfo; - if (dladdr(snd_dlopen, &dlinfo) > 0) - name = dlinfo.dli_fname; -#endif + 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 @@ -86,10 +85,6 @@ int snd_dlclose(void *handle) return 0; #endif #ifdef HAVE_LIBDL -#ifdef ANDROID - if (handle == RTLD_DEFAULT) - return 0; -#endif return dlclose(handle); #else return 0; diff --git a/src/hwdep/hwdep_hw.c b/src/hwdep/hwdep_hw.c index 238a507a..e4fcdc39 100644 --- a/src/hwdep/hwdep_hw.c +++ b/src/hwdep/hwdep_hw.c @@ -122,17 +122,6 @@ int snd_hwdep_hw_open(snd_hwdep_t **handle, const char *name, int card, int devi if (fd < 0) return -errno; } -#if 0 - /* - * this is bogus, an application have to care about open filedescriptors - */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - SYSERR("fcntl FD_CLOEXEC failed"); - ret = -errno; - close(fd); - return ret; - } -#endif if (ioctl(fd, SNDRV_HWDEP_IOCTL_PVERSION, &ver) < 0) { ret = -errno; close(fd); diff --git a/src/mixer/simple.c b/src/mixer/simple.c index 39790b2e..8079fe7a 100644 --- a/src/mixer/simple.c +++ b/src/mixer/simple.c @@ -103,7 +103,7 @@ int snd_mixer_selem_register(snd_mixer_t *mixer, } #define CHECK_ENUM(xelem) \ - if (!((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM)) \ + if (!(((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM))) \ return -EINVAL; #define COND_CAPS(xelem, what) \ @@ -878,7 +878,6 @@ int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value) int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) { CHECK_BASIC(elem); - CHECK_ENUM(elem); return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0); } diff --git a/src/mixer/simple_none.c b/src/mixer/simple_none.c index 0f4dd3a1..426f2d71 100644 --- a/src/mixer/simple_none.c +++ b/src/mixer/simple_none.c @@ -40,6 +40,7 @@ #include #include #include "mixer_simple.h" +#include "config.h" #ifndef DOC_HIDDEN @@ -134,6 +135,7 @@ static int get_compare_weight(const char *name, unsigned int idx) static const char *const names[] = { "Master", "Headphone", + "Speaker", "Tone", "Bass", "Treble", @@ -158,6 +160,7 @@ static int get_compare_weight(const char *name, unsigned int idx) "I2S", "IEC958", "PC Speaker", + "Beep", "Aux", "Mono", "Playback", @@ -1450,7 +1453,14 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, } 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; diff --git a/src/output.c b/src/output.c index 8a723f8b..adc461ae 100644 --- a/src/output.c +++ b/src/output.c @@ -333,7 +333,7 @@ static const snd_output_ops_t snd_output_buffer_ops = { #endif /** - * \brief Returns the address of the buffer of a #SND_OUTPUT_TYPE_BUFFER output handle. + * \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. diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 2016dd45..f910189a 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -104,9 +104,13 @@ implementation can be found in the \ref alsa_pcm_rw section. 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 a file -descriptor to poll or select on. The implemented -transfer routines can be found in the \ref alsa_transfers section. +network etc.), too. \ref snd_pcm_poll_descriptors can be used to get file +descriptors to poll or select on (note that wait direction might be diferent +than expected - do not use only returned file descriptors, but handle +events member as well - see \ref snd_pcm_poll_descriptors function +description for more details and \ref snd_pcm_poll_descriptors_revents for +events demangling). The implemented transfer routines can be found in +the \ref alsa_transfers section. \subsection pcm_transfer_async Asynchronous notification @@ -164,17 +168,17 @@ The PCM device is prepared for operation. Application can use the operation. \par SND_PCM_STATE_RUNNING -The PCM device is running. It processes the samples. The stream can +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. +#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. You can recover from -this state with #snd_pcm_prepare(), +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 @@ -630,6 +634,7 @@ playback devices. #include #include #include +#include #include #include #include "pcm_local.h" @@ -1221,9 +1226,9 @@ use_default_symbol_version(__snd_pcm_forward, snd_pcm_forward, ALSA_0.9.0rc8); * \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 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. */ @@ -1253,9 +1258,9 @@ snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_ufr * \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 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. */ @@ -1285,8 +1290,8 @@ snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t * \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 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. @@ -1317,8 +1322,8 @@ snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t * \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 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. @@ -1404,7 +1409,9 @@ int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm) * does the right "demangling". * * You can use output from this function as arguments for the select() - * syscall, too. + * syscall, too. Do not forget to translate POLLIN and POLLOUT events to + * corresponding FD_SET arrays and demangle events using + * \link ::snd_pcm_poll_descriptors_revents() \endlink . */ int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) { @@ -1429,7 +1436,7 @@ int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int s * \param pcm PCM handle * \param pfds array of poll descriptors * \param nfds count of poll descriptors - * \param revents returned events + * \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 @@ -1439,6 +1446,9 @@ int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int s * syscall returned that some events are waiting, this function might * return empty set of events. In this case, application should * do next event waiting using poll() or select(). + * + * Note: Even if multiple poll descriptors are used (i.e. pfds > 1), + * this function returns only a single event. */ int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { @@ -2337,8 +2347,8 @@ int snd_pcm_wait(snd_pcm_t *pcm, int timeout) int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout) { struct pollfd *pfd; - unsigned short *revents; - int i, npfds, pollio, err, err_poll; + unsigned short revents = 0; + int npfds, err, err_poll; npfds = snd_pcm_poll_descriptors_count(pcm); if (npfds <= 0 || npfds >= 16) { @@ -2346,7 +2356,6 @@ int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout) return -EIO; } pfd = alloca(sizeof(*pfd) * npfds); - revents = alloca(sizeof(*revents) * npfds); err = snd_pcm_poll_descriptors(pcm, pfd, npfds); if (err < 0) return err; @@ -2355,7 +2364,6 @@ int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout) return -EIO; } do { - pollio = 0; err_poll = poll(pfd, npfds, timeout); if (err_poll < 0) { if (errno == EINTR) @@ -2364,28 +2372,23 @@ int snd_pcm_wait_nocheck(snd_pcm_t *pcm, int timeout) } if (! err_poll) break; - err = snd_pcm_poll_descriptors_revents(pcm, pfd, npfds, revents); + err = snd_pcm_poll_descriptors_revents(pcm, pfd, npfds, &revents); if (err < 0) return err; - for (i = 0; i < npfds; i++) { - if (revents[i] & (POLLERR | POLLNVAL)) { - /* check more precisely */ - switch (snd_pcm_state(pcm)) { - case SND_PCM_STATE_XRUN: - return -EPIPE; - case SND_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - case SND_PCM_STATE_DISCONNECTED: - return -ENODEV; - default: - return -EIO; - } + if (revents & (POLLERR | POLLNVAL)) { + /* check more precisely */ + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EIO; } - if ((revents[i] & (POLLIN | POLLOUT)) == 0) - continue; - pollio++; } - } while (! pollio); + } while (!(revents & (POLLIN | POLLOUT))); #if 0 /* very useful code to test poll related problems */ { snd_pcm_sframes_t avail_update; @@ -2457,8 +2460,8 @@ snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm) /** * \brief Combine snd_pcm_avail and snd_pcm_delay functions * \param pcm PCM handle - * \param avail Number of available frames in the ring buffer - * \param delay Total I/O latency in frames + * \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. @@ -6525,46 +6528,51 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_ { snd_pcm_uframes_t xfer = 0; snd_pcm_sframes_t err = 0; - snd_pcm_state_t state = snd_pcm_state(pcm); + snd_pcm_state_t state; if (size == 0) return 0; - switch (state) { - case SND_PCM_STATE_PREPARED: - err = snd_pcm_start(pcm); - if (err < 0) - goto _end; - break; - case SND_PCM_STATE_DRAINING: - case SND_PCM_STATE_RUNNING: - break; - case SND_PCM_STATE_XRUN: - return -EPIPE; - case SND_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - case SND_PCM_STATE_DISCONNECTED: - return -ENODEV; - default: - return -EBADFD; - } - while (size > 0) { snd_pcm_uframes_t frames; snd_pcm_sframes_t avail; _again: - if (state == SND_PCM_STATE_RUNNING) { + state = snd_pcm_state(pcm); + switch (state) { + case SND_PCM_STATE_PREPARED: + err = snd_pcm_start(pcm); + if (err < 0) + goto _end; + break; + case SND_PCM_STATE_RUNNING: err = snd_pcm_hwsync(pcm); if (err < 0) goto _end; + break; + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PAUSED: + break; + case SND_PCM_STATE_XRUN: + err = -EPIPE; + goto _end; + case SND_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end; + case SND_PCM_STATE_DISCONNECTED: + err = -ENODEV; + goto _end; + default: + err = -EBADFD; + goto _end; } avail = snd_pcm_avail_update(pcm); if (avail < 0) { err = avail; goto _end; } - if ((snd_pcm_uframes_t)avail < pcm->avail_min && - size > (snd_pcm_uframes_t)avail) { + if (avail == 0) { + if (state == SND_PCM_STATE_DRAINING) + goto _end; if (pcm->mode & SND_PCM_NONBLOCK) { err = -EAGAIN; goto _end; @@ -6599,33 +6607,37 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area { snd_pcm_uframes_t xfer = 0; snd_pcm_sframes_t err = 0; - snd_pcm_state_t state = snd_pcm_state(pcm); + snd_pcm_state_t state; if (size == 0) return 0; - switch (state) { - case SND_PCM_STATE_PREPARED: - case SND_PCM_STATE_RUNNING: - break; - case SND_PCM_STATE_XRUN: - return -EPIPE; - case SND_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - case SND_PCM_STATE_DISCONNECTED: - return -ENODEV; - default: - return -EBADFD; - } - while (size > 0) { snd_pcm_uframes_t frames; snd_pcm_sframes_t avail; _again: - if (state == SND_PCM_STATE_RUNNING) { + state = snd_pcm_state(pcm); + switch (state) { + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_PAUSED: + break; + case SND_PCM_STATE_RUNNING: err = snd_pcm_hwsync(pcm); if (err < 0) goto _end; + break; + case SND_PCM_STATE_XRUN: + err = -EPIPE; + goto _end; + case SND_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end; + case SND_PCM_STATE_DISCONNECTED: + err = -ENODEV; + goto _end; + default: + err = -EBADFD; + goto _end; } avail = snd_pcm_avail_update(pcm); if (avail < 0) { @@ -7208,6 +7220,8 @@ OBSOLETE1(snd_pcm_sw_params_get_silence_size, ALSA_0.9, ALSA_0.9.0rc4); * \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. @@ -7260,7 +7274,7 @@ int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent) * \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 (0 = optimum latency for players) + * \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, diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 82cc126c..0a9047dd 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -540,7 +540,6 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) { snd_timer_stop(dmix->timer); - snd_pcm_direct_clear_timer_queue(dmix); return 0; } @@ -567,6 +566,7 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in switch (snd_pcm_state(dmix->spcm)) { case SND_PCM_STATE_XRUN: case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_SETUP: events |= POLLERR; break; default: @@ -577,6 +577,7 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in switch (snd_pcm_state(pcm)) { case SND_PCM_STATE_XRUN: case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_SETUP: events |= POLLERR; break; default: @@ -591,7 +592,10 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info) { - // snd_pcm_direct_t *dmix = pcm->private_data; + 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; @@ -885,6 +889,7 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str 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, }; @@ -1122,8 +1127,9 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) snd_timer_poll_descriptors(dmix->timer, &dmix->timer_fd, 1); dmix->poll_fd = dmix->timer_fd.fd; - dmix->timer_event_suspend = 1<timer_event_resume = 1<timer_events = (1<timer_event_suspend = 1<timer_event_resume = 1<timer_events &= ~((1<timer_events |= (1<timer_events |= 1<tread) { filter = (1<timer_event_suspend | - dmix->timer_event_resume; + dmix->timer_events; snd_timer_params_set_filter(params, filter); } ret = snd_timer_params(dmix->timer, params); diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 006617a5..132c281c 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -142,10 +142,9 @@ struct snd_pcm_direct { int hw_fd; /* hardware file descriptor */ struct pollfd timer_fd; int poll_fd; - int tread; - int timer_need_poll; - unsigned int timer_event_suspend; - unsigned int timer_event_resume; + int tread: 1; + int timer_need_poll: 1; + unsigned int timer_events; int server_fd; pid_t server_pid; snd_timer_t *timer; /* timer used as poll_fd */ diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 5b967e86..cb62de92 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -145,9 +145,11 @@ static void dmix_server_free(snd_pcm_direct_t *dmix) #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, @@ -172,6 +174,10 @@ static void mix_areas(snd_pcm_direct_t *dmix, 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; @@ -236,6 +242,10 @@ static void remix_areas(snd_pcm_direct_t *dmix, 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; @@ -595,8 +605,8 @@ 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; - snd_pcm_direct_timer_stop(dmix); dmix->state = SND_PCM_STATE_SETUP; + snd_pcm_direct_timer_stop(dmix); return 0; } diff --git a/src/pcm/pcm_dmix_generic.c b/src/pcm/pcm_dmix_generic.c index a1086c95..9e9d3c3c 100644 --- a/src/pcm/pcm_dmix_generic.c +++ b/src/pcm/pcm_dmix_generic.c @@ -122,7 +122,7 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) #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_3LE) | \ + (1ULL << SND_PCM_FORMAT_S24_LE) | (1ULL << SND_PCM_FORMAT_S24_3LE) | \ (1ULL << SND_PCM_FORMAT_U8)) #include diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c index 68c47553..dcc6b9a4 100644 --- a/src/pcm/pcm_dmix_i386.c +++ b/src/pcm/pcm_dmix_i386.c @@ -77,6 +77,7 @@ #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 \ diff --git a/src/pcm/pcm_dmix_i386.h b/src/pcm/pcm_dmix_i386.h index 9ea155d9..462371a5 100644 --- a/src/pcm/pcm_dmix_i386.h +++ b/src/pcm/pcm_dmix_i386.h @@ -400,8 +400,8 @@ static void MIX_AREAS_24(unsigned int size, "\tmovzwl (%%esi), %%ecx\n" "\tmovl (%%ebx), %%edx\n" "\tsall $16, %%eax\n" + "\torl %%eax, %%ecx\n" "\t" LOCK_PREFIX "btsw $0, (%%edi)\n" - "\tleal (%%ecx,%%eax,1), %%ecx\n" "\tjc 2f\n" "\t" XSUB " %%edx, %%ecx\n" "2:" diff --git a/src/pcm/pcm_dmix_x86_64.h b/src/pcm/pcm_dmix_x86_64.h index b4d0a412..ab40f50a 100644 --- a/src/pcm/pcm_dmix_x86_64.h +++ b/src/pcm/pcm_dmix_x86_64.h @@ -284,11 +284,11 @@ static void MIX_AREAS_24(unsigned int size, * *sum += sample; */ "\tmovsbl 2(%%rsi), %%eax\n" - "\tmovswl (%%rsi), %%ecx\n" + "\tmovzwl (%%rsi), %%ecx\n" "\tmovl (%%rbx), %%edx\n" "\tsall $16, %%eax\n" + "\torl %%eax, %%ecx\n" "\t" LOCK_PREFIX "btsw $0, (%%rdi)\n" - "\t.byte 0x67, 0x8d, 0x0c, 0x01\n" "\tjc 2f\n" "\t" XSUB " %%edx, %%ecx\n" "2:" diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index c91fa3b1..02782a78 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -355,9 +355,9 @@ 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); - dshare->state = SND_PCM_STATE_SETUP; return 0; } diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 9d42c123..15c727a5 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -280,8 +280,8 @@ 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; - snd_timer_stop(dsnoop->timer); dsnoop->state = SND_PCM_STATE_SETUP; + snd_timer_stop(dsnoop->timer); return 0; } diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 82823a04..bfa1cc8b 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "pcm_local.h" #include "pcm_plugin.h" @@ -39,6 +40,16 @@ const char *_snd_module_pcm_file = ""; #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 @@ -57,6 +68,9 @@ struct wav_fmt { typedef struct { snd_pcm_generic_t gen; char *fname; + char *final_fname; + int trunc; + int perm; int fd; char *ifname; int ifd; @@ -84,6 +98,175 @@ typedef struct { #define TO_LE16(x) bswap_16(x) #endif +static int snd_pcm_file_append_value(char **string_p, char **index_ch_p, + int *len_p, const char *value) +{ + char *string, *index_ch; + int index, len, value_len; + /* input pointer values */ + len = *(len_p); + string = *(string_p); + index_ch = *(index_ch_p); + + value_len = strlen(value); + /* reallocation to accommodate the value */ + index = index_ch - string; + len += value_len; + string = realloc(string, len + 1); + if (!string) + return -ENOMEM; + index_ch = string + index; + /* concatenating the new value */ + strcpy(index_ch, value); + index_ch += value_len; + /* return values */ + *(len_p) = len; + *(string_p) = string; + *(index_ch_p) = index_ch; + return 0; +} + +static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p) +{ + char value[VALUE_MAXLEN]; + char *fname = file->fname; + char *new_fname = NULL; + char *old_last_ch, *old_index_ch, *new_index_ch; + int old_len, new_len, err; + + snd_pcm_t *pcm = file->gen.slave; + + /* we want to keep fname, const */ + old_len = new_len = strlen(fname); + old_last_ch = fname + old_len - 1; + new_fname = malloc(new_len + 1); + if (!new_fname) + return -ENOMEM; + + old_index_ch = fname; /* first character of the old name */ + new_index_ch = new_fname; /* first char of the new name */ + + while (old_index_ch <= old_last_ch) { + if (*(old_index_ch) == LEADING_KEY && + old_index_ch != old_last_ch) { + /* is %, not last char, skipping and checking + next char */ + switch (*(++old_index_ch)) { + case RATE_KEY: + snprintf(value, sizeof(value), "%d", + pcm->rate); + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, value); + if (err < 0) + return err; + break; + + case CHANNELS_KEY: + snprintf(value, sizeof(value), "%d", + pcm->channels); + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, value); + if (err < 0) + return err; + break; + + case BWIDTH_KEY: + snprintf(value, sizeof(value), "%d", + pcm->frame_bits/pcm->channels); + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, value); + if (err < 0) + return err; + break; + + case FORMAT_KEY: + err = snd_pcm_file_append_value(&new_fname, + &new_index_ch, &new_len, + snd_pcm_format_name(pcm->format)); + if (err < 0) + return err; + break; + + default: + /* non-key char, just copying */ + *(new_index_ch++) = *(old_index_ch); + } + /* next old char */ + old_index_ch++; + } else { + /* plain copying, shifting both strings to next chars */ + *(new_index_ch++) = *(old_index_ch++); + } + } + /* closing the new string */ + *(new_index_ch) = '\0'; + *(new_fname_p) = new_fname; + return 0; + +} + +static int snd_pcm_file_open_output_file(snd_pcm_file_t *file) +{ + int err, fd; + + /* fname can contain keys, generating final_fname */ + err = snd_pcm_file_replace_fname(file, &(file->final_fname)); + if (err < 0) + return err; + /*printf("DEBUG - original fname: %s, final fname: %s\n", + file->fname, file->final_fname);*/ + + if (file->final_fname[0] == '|') { + /* pipe mode */ + FILE *pipe; + /* clearing */ + pipe = popen(file->final_fname + 1, "w"); + if (!pipe) { + SYSERR("running %s for writing failed", + file->final_fname); + return -errno; + } + fd = fileno(pipe); + } else { + if (file->trunc) + fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC, + file->perm); + else { + fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL, + file->perm); + if (fd < 0) { + char *tmpfname = NULL; + int idx, len; + len = strlen(file->final_fname) + 6; + tmpfname = malloc(len); + if (!tmpfname) + return -ENOMEM; + for (idx = 1; idx < 10000; idx++) { + snprintf(tmpfname, len, + "%s.%04d", file->final_fname, + idx); + fd = open(tmpfname, + O_WRONLY|O_CREAT|O_EXCL, + file->perm); + if (fd >= 0) { + free(file->final_fname); + file->final_fname = tmpfname; + break; + } + } + if (fd < 0) { + SYSERR("open %s for writing failed", + file->final_fname); + free(tmpfname); + return -errno; + } + } + } + } + file->fd = fd; + return 0; +} + static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt) { fmt->fmt = TO_LE16(0x01); @@ -152,6 +335,8 @@ static void fixup_wav_header(snd_pcm_t *pcm) } #endif /* DOC_HIDDEN */ + + static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes) { snd_pcm_file_t *file = pcm->private_data; @@ -442,6 +627,13 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) a->first = slave->sample_bits * channel; a->step = slave->frame_bits; } + if (file->fd < 0) { + err = snd_pcm_file_open_output_file(file); + if (err < 0) { + SYSERR("failed opening output file %s", file->fname); + return err; + } + } return 0; } @@ -452,6 +644,10 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out) 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); @@ -533,7 +729,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, snd_pcm_file_t *file; snd_pcm_file_format_t format; struct timespec timespec; - char *tmpname = NULL; int err; assert(pcmp); @@ -546,58 +741,27 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, SNDERR("file format %s is unknown", fmt); return -EINVAL; } - if (fname) { - if (trunc) - fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm); - else { - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm); - if (fd < 0) { - int idx, len; - len = strlen(fname) + 6; - tmpname = malloc(len); - if (!tmpname) - return -ENOMEM; - for (idx = 1; idx < 10000; idx++) { - snprintf(tmpname, len, - "%s.%04d", fname, idx); - fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm); - if (fd >= 0) { - fname = tmpname; - break; - } - } - } - } - if (fd < 0) { - SYSERR("open %s for writing failed", fname); - free(tmpname); - return -errno; - } - } file = calloc(1, sizeof(snd_pcm_file_t)); if (!file) { - if (fname) - close(fd); - free(tmpname); return -ENOMEM; } + /* opening output fname is delayed until writing, + when PCM params are known */ + if (fname) + file->fname = strdup(fname); + file->trunc = trunc; + file->perm = perm; + if (ifname) { ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */ if (ifd < 0) { SYSERR("open %s for reading failed", ifname); - if (fname) - close(fd); free(file); - free(tmpname); return -errno; } - } - - if (fname) - file->fname = strdup(fname); - if (ifname) file->ifname = strdup(ifname); + } file->fd = fd; file->ifd = ifd; file->format = format; @@ -608,7 +772,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, if (err < 0) { free(file->fname); free(file); - free(tmpname); return err; } pcm->ops = &snd_pcm_file_ops; @@ -625,8 +788,6 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; - - free(tmpname); return 0; } @@ -634,8 +795,9 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, \section pcm_plugins_file Plugin: File -This plugin stores contents of a PCM stream to file, and optionally -uses an existing file as an input data source (i.e., "virtual mic") +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 { @@ -647,7 +809,17 @@ pcm.name { # or pcm { } # Slave PCM definition } - file STR # Output filename + 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 @@ -773,7 +945,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, err = snd_pcm_slave_conf(root, slave, &sconf, 0); if (err < 0) return err; - if (!fname && fd < 0 && !ifname) { + if ((!fname || strlen(fname) == 0) && fd < 0 && !ifname) { snd_config_delete(sconf); SNDERR("file is not defined"); return -EINVAL; diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c index d26aead3..84ea85f1 100644 --- a/src/pcm/pcm_generic.c +++ b/src/pcm/pcm_generic.c @@ -26,6 +26,7 @@ * */ +#include #include #include #include "pcm_local.h" diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index 826685f8..3a99d557 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -43,12 +43,39 @@ struct _snd_pcm_hook { 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; @@ -71,6 +98,10 @@ static int snd_pcm_hooks_close(snd_pcm_t *pcm) 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; @@ -193,6 +224,7 @@ int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int 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); @@ -312,6 +344,7 @@ static int snd_pcm_hook_add_conf(snd_pcm_t *pcm, snd_config_t *root, snd_config_ 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; @@ -402,20 +435,26 @@ static int snd_pcm_hook_add_conf(snd_pcm_t *pcm, snd_config_t *root, snd_config_ _err: if (type) snd_config_delete(type); - if (err >= 0) { - 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 + if (err < 0) + return err; + + if (args && snd_config_get_string(args, &str) >= 0) { + err = snd_config_search_definition(root, "hook_args", str, &args); + if (err < 0) + SNDERR("unknown hook_args %s", str); + else err = install_func(pcm, args); + snd_config_delete(args); + } else + err = install_func(pcm, args); + + if (err >= 0) + err = hook_add_dlobj(pcm, h); + + if (err < 0) { snd_dlclose(h); - } - if (err < 0) return err; + } return 0; } diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 95bb2ac6..9d243d53 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "pcm_local.h" #include "../control/control_local.h" #include "../timer/timer_local.h" @@ -134,7 +135,7 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr); if (err < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed"); + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); return err; } return 0; @@ -201,7 +202,7 @@ static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock) if ((flags = fcntl(fd, F_GETFL)) < 0) { err = -errno; - SYSMSG("F_GETFL failed"); + SYSMSG("F_GETFL failed (%i)", err); return err; } if (nonblock) @@ -210,7 +211,7 @@ static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock) flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { err = -errno; - SYSMSG("F_SETFL for O_NONBLOCK failed"); + SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err); return err; } return 0; @@ -224,7 +225,7 @@ static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid) if ((flags = fcntl(fd, F_GETFL)) < 0) { err = -errno; - SYSMSG("F_GETFL failed"); + SYSMSG("F_GETFL failed (%i)", err); return err; } if (sig >= 0) @@ -233,19 +234,19 @@ static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid) flags &= ~O_ASYNC; if (fcntl(fd, F_SETFL, flags) < 0) { err = -errno; - SYSMSG("F_SETFL for O_ASYNC failed"); + 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"); + SYSMSG("F_SETSIG failed (%i)", err); return err; } if (fcntl(fd, F_SETOWN, (long)pid) < 0) { err = -errno; - SYSMSG("F_SETOWN failed"); + SYSMSG("F_SETOWN failed (%i)", err); return err; } return 0; @@ -257,7 +258,7 @@ static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info) int fd = hw->fd, err; if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_INFO failed"); + SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err); return err; } return 0; @@ -322,9 +323,11 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) int err; if (hw_params_call(hw, params) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed"); + SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err); return err; } + params->info &= ~0xf0000000; + params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0); err = sync_ptr(hw, 0); if (err < 0) return err; @@ -335,18 +338,6 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 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; - if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) { - err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed"); - return err; - } - return 0; -} - static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) { if (hw->period_timer) { @@ -364,9 +355,9 @@ static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable) if (enable) { snd_timer_params_alloca(¶ms); - err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, hw->subdevice, SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD); + 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, SND_TIMER_OPEN_NONBLOCK); + 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) { @@ -418,6 +409,20 @@ static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable) } 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; } @@ -440,7 +445,7 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) } if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed"); + SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); return err; } params->period_event = old_period_event; @@ -462,7 +467,7 @@ static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info i.channel = info->channel; if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed"); + SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err); return err; } info->channel = i.channel; @@ -481,7 +486,7 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status) int fd = hw->fd, err; if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_STATUS failed"); + SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err); return err; } if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) { @@ -504,31 +509,9 @@ 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 (hw->sync_ptr) { - err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); - if (err < 0) - return err; - switch (FAST_PCM_STATE(hw)) { - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_DRAINING: - case SNDRV_PCM_STATE_PAUSED: - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_SUSPENDED: - break; - case SNDRV_PCM_STATE_XRUN: - return -EPIPE; - default: - return -EBADFD; - } - if (pcm->stream == SND_PCM_STREAM_PLAYBACK) - *delayp = snd_pcm_mmap_playback_hw_avail(pcm); - else - *delayp = snd_pcm_mmap_capture_avail(pcm); - return 0; - } if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_DELAY failed"); + SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err); return err; } return 0; @@ -546,7 +529,7 @@ static int snd_pcm_hw_hwsync(snd_pcm_t *pcm) } else { if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed"); + SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err); return err; } } @@ -572,7 +555,7 @@ static int snd_pcm_hw_prepare(snd_pcm_t *pcm) int fd = hw->fd, err; if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed"); + SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err); return err; } return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); @@ -584,7 +567,7 @@ static int snd_pcm_hw_reset(snd_pcm_t *pcm) int fd = hw->fd, err; if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_RESET failed"); + SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err); return err; } return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); @@ -601,7 +584,7 @@ static int snd_pcm_hw_start(snd_pcm_t *pcm) sync_ptr(hw, 0); if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_START failed"); + 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))); @@ -617,7 +600,7 @@ static int snd_pcm_hw_drop(snd_pcm_t *pcm) int err; if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_DROP failed"); + SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err); return err; } else { } @@ -630,7 +613,7 @@ static int snd_pcm_hw_drain(snd_pcm_t *pcm) int err; if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed"); + SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err); return err; } return 0; @@ -642,7 +625,7 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable) int err; if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed"); + SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err); return err; } return 0; @@ -659,7 +642,7 @@ static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fra int err; if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_REWIND failed"); + SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err); return err; } err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); @@ -680,7 +663,7 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr 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"); + SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err); return err; } err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); @@ -723,7 +706,7 @@ static int snd_pcm_hw_resume(snd_pcm_t *pcm) int fd = hw->fd, err; if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_RESUME failed"); + SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err); return err; } return 0; @@ -734,7 +717,7 @@ 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"); + SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno); return -errno; } return 0; @@ -743,7 +726,7 @@ static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2) 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"); + SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type); return -EINVAL; } return hw_link(master, pcm); @@ -764,7 +747,7 @@ 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"); + SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno); return -errno; } return 0; @@ -864,7 +847,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, &sync_ptr); if (err < 0) { err = -errno; - SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed"); + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); return err; } hw->sync_ptr = calloc(1, sizeof(struct sndrv_pcm_sync_ptr)); @@ -891,7 +874,7 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); if (ptr == MAP_FAILED || ptr == NULL) { err = -errno; - SYSMSG("control mmap failed"); + SYSMSG("control mmap failed (%i)", err); return err; } hw->mmap_control = ptr; @@ -912,7 +895,7 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) } else { if (munmap((void*)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) { err = -errno; - SYSMSG("status munmap failed"); + SYSMSG("status munmap failed (%i)", err); return err; } } @@ -929,7 +912,7 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) } else { if (munmap(hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) { err = -errno; - SYSMSG("control munmap failed"); + SYSMSG("control munmap failed (%i)", err); return err; } } @@ -952,7 +935,7 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm) int err = 0; if (close(hw->fd)) { err = -errno; - SYSMSG("close failed\n"); + SYSMSG("close failed (%i)\n", err); } snd_pcm_hw_munmap_status(pcm); snd_pcm_hw_munmap_control(pcm); @@ -1036,6 +1019,8 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out) 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); } } @@ -1144,7 +1129,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, memset(&info, 0, sizeof(info)); if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) { ret = -errno; - SYSMSG("SNDRV_PCM_IOCTL_INFO failed"); + SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret); close(fd); return ret; @@ -1161,21 +1146,9 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, if (fmode & O_ASYNC) mode |= SND_PCM_ASYNC; -#if 0 - /* - * this is bogus, an application have to care about open filedescriptors - */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - ret = -errno; - SYSMSG("fcntl FD_CLOEXEC failed"); - close(fd); - return ret; - } -#endif - if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) { ret = -errno; - SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed"); + SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret); close(fd); return ret; } @@ -1317,14 +1290,14 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, fd = snd_open_device(filename, fmode); if (fd < 0) { ret = -errno; - SYSMSG("open %s failed", filename); + 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"); + SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret); goto _err; } if (info.subdevice != (unsigned int) subdevice) { diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c index e43d3548..2aa75727 100644 --- a/src/pcm/pcm_ioplug.c +++ b/src/pcm/pcm_ioplug.c @@ -442,7 +442,7 @@ static int snd_pcm_ioplug_start(snd_pcm_t *pcm) int err; if (io->data->state != SND_PCM_STATE_PREPARED) - return -EBUSY; + return -EBADFD; err = io->data->callback->start(io->data); if (err < 0) @@ -877,7 +877,7 @@ callback. Finally, the dump callback is used to print the status of the plugin. The hw_params constraints can be defined via either -#snd_pcm_iplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list() +#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). diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 0357921b..5acc7bc8 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -46,7 +46,7 @@ const char *_snd_module_pcm_meter = ""; struct _snd_pcm_scope { int enabled; char *name; - snd_pcm_scope_ops_t *ops; + const snd_pcm_scope_ops_t *ops; void *private_data; struct list_head list; }; @@ -960,7 +960,7 @@ const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope) * \param scope PCM meter scope * \param val callbacks */ -void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, snd_pcm_scope_ops_t *val) +void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, const snd_pcm_scope_ops_t *val) { scope->ops = val; } diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 4b7a3533..4621fe6f 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -23,9 +23,7 @@ #include #include #include -#ifndef ANDROID #include -#endif #include "pcm_local.h" size_t page_size(void) @@ -373,7 +371,6 @@ int snd_pcm_mmap(snd_pcm_t *pcm) } i->addr = ptr; break; -#ifndef ANDROID case SND_PCM_AREA_SHM: if (i->u.shm.shmid < 0) { int id; @@ -419,7 +416,6 @@ int snd_pcm_mmap(snd_pcm_t *pcm) } i->addr = ptr; break; -#endif case SND_PCM_AREA_LOCAL: ptr = malloc(size); if (ptr == NULL) { @@ -500,7 +496,6 @@ int snd_pcm_munmap(snd_pcm_t *pcm) } errno = 0; break; -#ifndef ANDROID case SND_PCM_AREA_SHM: if (i->u.shm.area) { snd_shm_area_destroy(i->u.shm.area); @@ -518,7 +513,6 @@ int snd_pcm_munmap(snd_pcm_t *pcm) } } break; -#endif case SND_PCM_AREA_LOCAL: free(i->addr); break; diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c index 0dc19736..f6e7ae93 100644 --- a/src/pcm/pcm_mmap_emul.c +++ b/src/pcm/pcm_mmap_emul.c @@ -34,6 +34,7 @@ const char *_snd_module_pcm_mmap_emul = ""; #endif +#ifndef DOC_HIDDEN /* * */ @@ -43,7 +44,9 @@ typedef struct { 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 @@ -203,6 +206,24 @@ static int snd_pcm_mmap_emul_hw_params(snd_pcm_t *pcm, return err; } +static int snd_pcm_mmap_emul_sw_params(snd_pcm_t *pcm, + snd_pcm_sw_params_t *params) +{ + mmap_emul_t *map = pcm->private_data; + int err; + + map->start_threshold = params->start_threshold; + + /* HACK: don't auto-start in the slave PCM */ + params->start_threshold = pcm->boundary; + err = snd_pcm_generic_sw_params(pcm, params); + if (err < 0) + return err; + /* restore the value for this PCM */ + params->start_threshold = map->start_threshold; + return err; +} + static int snd_pcm_mmap_emul_prepare(snd_pcm_t *pcm) { mmap_emul_t *map = pcm->private_data; @@ -254,13 +275,18 @@ sync_slave_write(snd_pcm_t *pcm) 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) - return 0; - offset = *slave->appl.ptr % pcm->buffer_size; - return snd_pcm_write_mmap(pcm, offset, size); + 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 */ @@ -335,7 +361,7 @@ static const snd_pcm_ops_t snd_pcm_mmap_emul_ops = { .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_generic_sw_params, + .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, diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 2f2a42f9..692254ae 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -28,6 +28,7 @@ #include #include +#include #include "pcm_local.h" #include "pcm_plugin.h" diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c index 80b3fd21..0e1c3fc5 100644 --- a/src/pcm/pcm_params.c +++ b/src/pcm/pcm_params.c @@ -1081,6 +1081,7 @@ int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params, static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { int err; + const char *compat = getenv("LIBASOUND_COMPAT"); #ifdef CHOOSE_DEBUG snd_output_t *log; snd_output_stdio_attach(&log, stderr, 0); @@ -1103,15 +1104,29 @@ static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, 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_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; + if (compat && *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; diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index abd3d437..967cf46c 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -605,7 +605,16 @@ static int snd_pcm_plug_change_mmap(snd_pcm_t *pcm, snd_pcm_t **new, plug->gen.slave != plug->req_slave); if (err < 0) return err; - slv->access = clt->access; + 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 @@ -743,19 +752,29 @@ static int check_access_change(snd_pcm_hw_params_t *cparams, 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)) - snd_pcm_access_mask_set(&mask, - 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)) - snd_pcm_access_mask_set(&mask, - SND_PCM_ACCESS_RW_NONINTERLEAVED); - *smask = mask; + 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; diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index a751deb5..0ef394a4 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -82,6 +82,7 @@ pcm.rate44100Hz { */ +#include #include #include "pcm_local.h" #include "pcm_plugin.h" diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index a97a5de5..ecf00221 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -69,12 +69,17 @@ struct _snd_pcm_rate { 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 }; @@ -89,14 +94,18 @@ static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_ 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_RATE, SND_PCM_PLUGIN_RATE_MIN, 0); - if (err < 0) - return err; - err = _snd_pcm_hw_param_set_max(params, - SND_PCM_HW_PARAM_RATE, SND_PCM_PLUGIN_RATE_MAX, 0); - 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; } @@ -186,7 +195,7 @@ static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *p if (!snd_interval_checkempty(period_size) && period_size->openmin && period_size->openmax && period_size->min + 1 == period_size->max) { - if ((buffer_size->min / period_size->min) * period_size->min == buffer_size->min) { + 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); @@ -1178,6 +1187,9 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, snd_output_t *out) 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); @@ -1264,6 +1276,7 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type) { char open_name[64]; snd_pcm_rate_open_func_t open_func; + int err; snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type); open_func = snd_dlobj_cache_lookup(open_name); @@ -1285,7 +1298,25 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type) } snd_dlobj_cache_add(open_name, h, open_func); } - return open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); + + rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; + rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; + rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; + + err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); + if (!err) { + rate->plugin_version = rate->ops.version; + if (rate->ops.get_supported_rates) + rate->ops.get_supported_rates(rate->obj, + &rate->rate_min, + &rate->rate_max); + return 0; + } + + /* try to open with the old protocol version */ + rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION_OLD; + return open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD, + &rate->obj, &rate->ops); } #endif @@ -1295,7 +1326,7 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type) * \param name Name of PCM * \param sformat Slave format * \param srate Slave rate - * \param type SRC type string + * \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 diff --git a/src/pcm/pcm_rate_linear.c b/src/pcm/pcm_rate_linear.c index 20e119be..7481b389 100644 --- a/src/pcm/pcm_rate_linear.c +++ b/src/pcm/pcm_rate_linear.c @@ -405,6 +405,19 @@ 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, @@ -414,17 +427,16 @@ static const snd_pcm_rate_ops_t linear_ops = { .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) (unsigned int version, void **objp, snd_pcm_rate_ops_t *ops) +int SND_PCM_RATE_PLUGIN_ENTRY(linear) (ATTRIBUTE_UNUSED unsigned int version, + void **objp, snd_pcm_rate_ops_t *ops) { struct rate_linear *rate; - if (version != SND_PCM_RATE_PLUGIN_VERSION) { - SNDERR("Invalid plugin version %x\n", version); - return -EINVAL; - } - rate = calloc(1, sizeof(*rate)); if (! rate) return -ENOMEM; diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 3f8a0ac7..56a86859 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "pcm_local.h" @@ -1528,7 +1529,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, pcm->private_data = share; pcm->poll_fd = share->client_socket; pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; - pcm->monotonic = pcm->monotonic; + pcm->monotonic = slave->pcm->monotonic; snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0); diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c index 637e5cb3..2c7c006e 100644 --- a/src/pcm/pcm_softvol.c +++ b/src/pcm/pcm_softvol.c @@ -107,7 +107,8 @@ static inline int MULTI_DIV_32x16(int a, unsigned short b) v.i = a; y.i = 0; #if __BYTE_ORDER == __LITTLE_ENDIAN - x.i = (unsigned int)v.s[0] * b; + x.i = (unsigned short)v.s[0]; + x.i *= b; y.s[0] = x.s[1]; y.i += (int)v.s[1] * b; #else @@ -135,6 +136,23 @@ static inline int MULTI_DIV_int(int a, unsigned int b, int swap) 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; @@ -223,7 +241,7 @@ static inline short MULTI_DIV_short(short a, unsigned int b, int swap) tmp = src[0] | \ (src[1] << 8) | \ (((signed char *) src)[2] << 16); \ - tmp = MULTI_DIV_int(tmp, vol_scale, 0); \ + tmp = MULTI_DIV_24(tmp, vol_scale); \ dst[0] = tmp; \ dst[1] = tmp >> 8; \ dst[2] = tmp >> 16; \ diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c index f50cc053..b28488a8 100644 --- a/src/rawmidi/rawmidi.c +++ b/src/rawmidi/rawmidi.c @@ -153,7 +153,7 @@ static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params assert(params); params->buffer_size = page_size(); params->avail_min = 1; - params->no_active_sensing = 0; + params->no_active_sensing = 1; return 0; } @@ -987,6 +987,7 @@ ssize_t snd_rawmidi_read(snd_rawmidi_t *rawmidi, void *buffer, size_t size) return (rawmidi->ops->read)(rawmidi, buffer, size); } +#ifndef DOC_HIDDEN int snd_rawmidi_conf_generic_id(const char *id) { static const char ids[][8] = { @@ -1002,3 +1003,4 @@ int snd_rawmidi_conf_generic_id(const char *id) } return 0; } +#endif diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c index 87829fd7..e08dca7d 100644 --- a/src/rawmidi/rawmidi_hw.c +++ b/src/rawmidi/rawmidi_hw.c @@ -234,17 +234,6 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, return -errno; } } -#if 0 - /* - * this is bogus, an application have to care about open filedescriptors - */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - SYSERR("fcntl FD_CLOEXEC failed"); - ret = -errno; - close(fd); - return ret; - } -#endif if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_PVERSION, &ver) < 0) { ret = -errno; SYSERR("SNDRV_RAWMIDI_IOCTL_PVERSION failed"); diff --git a/src/seq/seq.c b/src/seq/seq.c index feb9733b..f5dfe9ca 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -30,7 +30,7 @@ /*! \page seq Sequencer interface -\section seq_general Genral +\section seq_general General The ALSA sequencer interface is designed to deliver the MIDI-like events between clients/ports. @@ -76,10 +76,10 @@ 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 -accessbility and subscription permissions of the port. +accessibility and subscription permissions of the port. For creation of a port, call #snd_seq_create_port() -with the appropirate port attribute specified in #snd_seq_port_info_t -reocrd. +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. @@ -102,7 +102,7 @@ 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' responce. +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. @@ -171,7 +171,7 @@ 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 applictions which work individually +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. @@ -199,7 +199,7 @@ 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 stroage types according to its usage. +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. @@ -227,7 +227,7 @@ 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 prority. +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(). @@ -240,7 +240,7 @@ The data field is a union of event data. 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 disatch mode, an event is passed 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. @@ -284,7 +284,7 @@ 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. +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. @@ -299,7 +299,7 @@ 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 normalised to absolute format. +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. @@ -320,7 +320,7 @@ 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 simplly delivered to it. +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. @@ -346,7 +346,7 @@ an announcement is sent to subscribers from this port. Some events like SYSEX message, however, need larger data space than the standard data. -For such events, ALSA sequencer provides seveal different data storage types. +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: @@ -359,7 +359,7 @@ 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 sequecer kernel, the whole extra-data is duplicated, so that the event +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. @@ -430,7 +430,7 @@ 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 nanosecononds. There is, however, +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, @@ -463,7 +463,7 @@ void set_tempo(snd_seq_t *handle) \endcode For changing the (running) queue's tempo on the fly, you can either -set the tempo via #snd_seq_queue_tempo() or send a MIDI tempo event +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) @@ -488,7 +488,7 @@ 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 happes at the scheduled time, too. +change happens at the scheduled time, too. \subsection seq_ev_start Starting and stopping a queue @@ -515,7 +515,7 @@ 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 menas +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. @@ -536,11 +536,11 @@ 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 spcified port. +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_SUBS_READ capability. +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 @@ -579,7 +579,7 @@ snd_seq_subscribe_port(handle, subs); When the connection should be exclusively done only between a certain pair, set exclusive attribute to the subscription -record before calling #snd_seq_port_subscribe. +record before calling #snd_seq_subscribe_port. \code snd_seq_port_subscribe_set_exclusive(subs, 1); \endcode @@ -610,7 +610,7 @@ if #SND_SEQ_PORT_CAP_NO_EXPORT capability is set in either sender or receiver po Assume MIDI input port = 64:0, application port = 128:0, and queue for timestamp = 1 with real-time stamp. -The application port must have capabilty #SND_SEQ_PORT_CAP_WRITE. +The application port must have capability #SND_SEQ_PORT_CAP_WRITE. \code void capture_keyboard(snd_seq_t *seq) { @@ -633,7 +633,7 @@ void capture_keyboard(snd_seq_t *seq) \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 capabilty #SND_SEQ_PORT_CAP_READ. +The application port must have capability #SND_SEQ_PORT_CAP_READ. \code void subscribe_output(snd_seq_t *seq) { @@ -663,7 +663,7 @@ 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_SUBS_READ, +#SND_SEQ_PORT_CAP_SUBS_READ, and the receiver #SND_SEQ_PORT_CAP_WRITE and #SND_SEQ_PORT_CAP_SUBS_WRITE, respectively. @@ -790,7 +790,7 @@ void event_filter(snd_seq_t *seq, snd_seq_event_t *ev) /** * \brief get identifier of sequencer handle * \param seq sequencer handle - * \return ascii identifier of 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(). @@ -1471,7 +1471,7 @@ int snd_seq_client_info_get_client(const snd_seq_client_info_t *info) * \param info client_info container * \return client type * - * The client type is either #SEQ_CLIENT_TYPE_KERNEL or #SEQ_CLIENT_TYPE_USER + * 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() @@ -1610,7 +1610,7 @@ void snd_seq_client_info_event_filter_del(snd_seq_client_info_t *info, int event * \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 bitamp of this client_info container. + * 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(), diff --git a/src/seq/seq_hw.c b/src/seq/seq_hw.c index 0e945932..5bb26f34 100644 --- a/src/seq/seq_hw.c +++ b/src/seq/seq_hw.c @@ -457,17 +457,6 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode) SYSERR("open %s failed", filename); return -errno; } -#if 0 - /* - * this is bogus, an application have to care about open filedescriptors - */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - SYSERR("fcntl FD_CLOEXEC failed"); - ret = -errno; - close(fd); - return ret; - } -#endif if (ioctl(fd, SNDRV_SEQ_IOCTL_PVERSION, &ver) < 0) { SYSERR("SNDRV_SEQ_IOCTL_PVERSION failed"); ret = -errno; diff --git a/src/seq/seq_midi_event.c b/src/seq/seq_midi_event.c index b5caa1b8..ddaac5ab 100644 --- a/src/seq/seq_midi_event.c +++ b/src/seq/seq_midi_event.c @@ -129,12 +129,23 @@ static const struct extra_event_list_t { #endif /* DOC_HIDDEN */ /** - * \brief Initialize MIDI event parser - * \param bufsize buffer size for MIDI message - * \param rdev allocated MIDI event parser - * \return 0 on success otherwise a negative error code + * \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. * - * Allocates and initializes MIDI event parser. + * 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) { @@ -159,11 +170,13 @@ int snd_midi_event_new(size_t bufsize, snd_midi_event_t **rdev) } /** - * \brief Free MIDI event parser - * \param dev MIDI event parser - * \return 0 on success otherwise a negative error code + * \brief Frees a MIDI event parser. + * \param dev MIDI event parser. * - * Frees MIDI event parser. + * Frees a MIDI event parser. + * + * \par Conforming to: + * LSB 3.2 */ void snd_midi_event_free(snd_midi_event_t *dev) { @@ -174,11 +187,15 @@ void snd_midi_event_free(snd_midi_event_t *dev) } /** - * \brief Enable/disable MIDI command merging - * \param dev MIDI event parser - * \param on 0 - enable MIDI command merging, 1 - always pass the command + * \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). * - * Enable/disable MIDI command merging + * 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) { @@ -196,11 +213,15 @@ inline static void reset_encode(snd_midi_event_t *dev) } /** - * \brief Reset MIDI encode parser - * \param dev MIDI event parser - * \return 0 on success otherwise a negative error code + * \brief Resets MIDI encode parser. + * \param dev MIDI event parser. * - * Resets MIDI encode 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) { @@ -208,11 +229,15 @@ void snd_midi_event_reset_encode(snd_midi_event_t *dev) } /** - * \brief Reset MIDI decode parser - * \param dev MIDI event parser - * \return 0 on success otherwise a negative error code + * \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. * - * Resets MIDI decode parser + * \par Conforming to: + * LSB 3.2 */ void snd_midi_event_reset_decode(snd_midi_event_t *dev) { @@ -220,11 +245,14 @@ void snd_midi_event_reset_decode(snd_midi_event_t *dev) } /** - * \brief Initializes MIDI parsers - * \param dev MIDI event parser - * \return 0 on success otherwise a negative error code + * \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 * - * Initializes MIDI parsers (both encode and decode) + * \par Conforming to: + * LSB 3.2 */ void snd_midi_event_init(snd_midi_event_t *dev) { @@ -233,12 +261,21 @@ void snd_midi_event_init(snd_midi_event_t *dev) } /** - * \brief Resize MIDI message (event) buffer - * \param dev MIDI event parser - * \param bufsize new requested buffer size - * \return 0 on success otherwise a negative error code + * \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. * - * Resizes MIDI message (event) buffer. + * 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) { @@ -258,16 +295,67 @@ int snd_midi_event_resize_buffer(snd_midi_event_t *dev, size_t bufsize) } /** - * \brief Read bytes and encode to sequencer event if finished - * \param dev MIDI event parser - * \param buf MIDI byte stream - * \param count count of bytes of MIDI byte stream to encode - * \param ev Result - sequencer event - * \return count of encoded bytes otherwise a negative error code - * - * Read bytes and encode to sequencer event if finished. - * If complete sequencer event is available, ev->type is not - * equal to #SND_SEQ_EVENT_NONE. + * \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) { @@ -289,13 +377,23 @@ long snd_midi_event_encode(snd_midi_event_t *dev, const unsigned char *buf, long } /** - * \brief Read one byte and encode to sequencer event if finished - * \param dev MIDI event parser - * \param c a byte of MIDI stream - * \param ev Result - sequencer event - * \return 1 - sequencer event is completed, 0 - next byte is required for completion, otherwise a negative error code + * \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. * - * Read byte and encode to sequencer event if finished. + * 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) { @@ -405,14 +503,56 @@ static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev) } /** - * \brief Decode sequencer event to MIDI byte stream - * \param dev MIDI event parser - * \param buf Result - MIDI byte stream - * \param count Available bytes in MIDI byte stream - * \param ev Event to decode - * \return count of decoded bytes otherwise a negative error code - * - * Decode sequencer event to MIDI byte stream. + * \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) { @@ -442,6 +582,7 @@ long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count if (cmd == MIDI_CMD_COMMON_SYSEX) { + snd_midi_event_reset_decode(dev); qlen = ev->data.ext.len; if (count < qlen) return -ENOMEM; @@ -566,10 +707,10 @@ static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int coun if (dev->nostat && count < 12) return -ENOMEM; cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); - bytes[0] = ev->data.control.param & 0x007f; - bytes[1] = (ev->data.control.param & 0x3f80) >> 7; - bytes[2] = ev->data.control.value & 0x007f; - bytes[3] = (ev->data.control.value & 0x3f80) >> 7; + 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; diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c index 3b0960d6..86a49709 100644 --- a/src/seq/seqmid.c +++ b/src/seq/seqmid.c @@ -317,7 +317,7 @@ int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size) * \param seq sequencer handle * \return 0 on success or negative error code * - * So far, this works ideically like #snd_seq_drop_output(). + * So far, this works identically like #snd_seq_drop_output(). */ int snd_seq_reset_pool_output(snd_seq_t *seq) { @@ -329,7 +329,7 @@ int snd_seq_reset_pool_output(snd_seq_t *seq) * \param seq sequencer handle * \return 0 on success or negative error code * - * So far, this works ideically like #snd_seq_drop_input(). + * So far, this works identically like #snd_seq_drop_input(). */ int snd_seq_reset_pool_input(snd_seq_t *seq) { diff --git a/src/timer/timer_hw.c b/src/timer/timer_hw.c index 34538584..2fae75e5 100644 --- a/src/timer/timer_hw.c +++ b/src/timer/timer_hw.c @@ -23,7 +23,6 @@ #include #include #include -#define __USE_GNU #include #include #include "timer_local.h" @@ -236,17 +235,6 @@ int snd_timer_hw_open(snd_timer_t **handle, const char *name, int dev_class, int fd = snd_open_device(SNDRV_FILE_TIMER, tmode); if (fd < 0) return -errno; -#if 0 - /* - * this is bogus, an application have to care about open filedescriptors - */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - SYSERR("fcntl FD_CLOEXEC failed"); - ret = -errno; - close(fd); - return ret; - } -#endif if (ioctl(fd, SNDRV_TIMER_IOCTL_PVERSION, &ver) < 0) { ret = -errno; close(fd); diff --git a/src/timer/timer_local.h b/src/timer/timer_local.h index 19cadfe6..8040b05c 100644 --- a/src/timer/timer_local.h +++ b/src/timer/timer_local.h @@ -64,7 +64,7 @@ struct _snd_timer_query { snd_timer_type_t type; int mode; int poll_fd; - snd_timer_query_ops_t *ops; + const snd_timer_query_ops_t *ops; void *private_data; }; #endif /* DOC_HIDDEN */ diff --git a/test/Makefile.am b/test/Makefile.am index 2d7e92b0..ae524a4d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS=. lsb + check_PROGRAMS=control pcm pcm_min latency seq \ playmidi1 timer rawmidi midiloop \ oldapi queue_timer namehint client_event_filter diff --git a/test/Makefile.in b/test/Makefile.in index d1a6a432..4d0a046b 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -106,8 +106,15 @@ SOURCES = client_event_filter.c control.c latency.c midiloop.c \ DIST_SOURCES = client_event_filter.c control.c latency.c midiloop.c \ namehint.c oldapi.c pcm.c pcm_min.c playmidi1.c queue_timer.c \ rawmidi.c seq.c timer.c +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive ETAGS = etags CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ @@ -310,6 +317,7 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +SUBDIRS = . lsb control_LDADD = ../src/libasound.la pcm_LDADD = ../src/libasound.la pcm_min_LDADD = ../src/libasound.la @@ -327,7 +335,7 @@ code_CFLAGS = -Wall -pipe -g -O2 INCLUDES = -I$(top_srcdir)/include AM_CFLAGS = -Wall -pipe -g EXTRA_DIST = seq-decoder.c seq-sender.c midifile.h midifile.c midifile.3 -all: all-am +all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj @@ -458,6 +466,77 @@ distclean-libtool: -rm -f libtool uninstall-info-am: +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (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" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -468,10 +547,23 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) mkid -fID $$unique tags: TAGS -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ 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 || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ @@ -484,7 +576,7 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $$tags $$unique; \ fi ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ @@ -533,20 +625,36 @@ distdir: $(DISTFILES) || exit 1; \ fi; \ done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) -check: check-am +check: check-recursive all-am: Makefile -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am +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-am +installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ @@ -562,24 +670,24 @@ distclean-generic: 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: clean-recursive clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am -distclean: distclean-am +distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags -dvi: dvi-am +dvi: dvi-recursive dvi-am: -html: html-am +html: html-recursive -info: info-am +info: info-recursive info-am: @@ -587,43 +695,47 @@ install-data-am: install-exec-am: -install-info: install-info-am +install-info: install-info-recursive install-man: installcheck-am: -maintainer-clean: maintainer-clean-am +maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic -mostlyclean: mostlyclean-am +mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool -pdf: pdf-am +pdf: pdf-recursive pdf-am: -ps: ps-am +ps: ps-recursive ps-am: uninstall-am: uninstall-info-am -.PHONY: CTAGS GTAGS all all-am check check-am clean \ - clean-checkPROGRAMS clean-generic clean-libtool ctags \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-checkPROGRAMS clean-generic clean-libtool \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-recursive distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-exec install-exec-am install-info \ install-info-am install-man install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-info-am + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/test/lsb/Makefile.am b/test/lsb/Makefile.am new file mode 100644 index 00000000..ceb4d715 --- /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 00000000..f9f1b6fb --- /dev/null +++ b/test/lsb/Makefile.in @@ -0,0 +1,612 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 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@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +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 = $(am__EXEEXT_1) +subdir = test/lsb +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +am__EXEEXT_1 = config$(EXEEXT) midi_event$(EXEEXT) +config_SOURCES = config.c +config_OBJECTS = config.$(OBJEXT) +config_LDADD = $(LDADD) +config_DEPENDENCIES = ../../src/libasound.la +midi_event_SOURCES = midi_event.c +midi_event_OBJECTS = midi_event.$(OBJEXT) +midi_event_LDADD = $(LDADD) +midi_event_DEPENDENCIES = ../../src/libasound.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = config.c midi_event.c +DIST_SOURCES = config.c midi_event.c +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CONFIG_DIR = @ALSA_CONFIG_DIR@ +ALSA_DEPLIBS = @ALSA_DEPLIBS@ +ALSA_HSEARCH_R_FALSE = @ALSA_HSEARCH_R_FALSE@ +ALSA_HSEARCH_R_TRUE = @ALSA_HSEARCH_R_TRUE@ +ALSA_PLUGIN_DIR = @ALSA_PLUGIN_DIR@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_ALISP_FALSE = @BUILD_ALISP_FALSE@ +BUILD_ALISP_TRUE = @BUILD_ALISP_TRUE@ +BUILD_CTL_PLUGIN_EXT_FALSE = @BUILD_CTL_PLUGIN_EXT_FALSE@ +BUILD_CTL_PLUGIN_EXT_TRUE = @BUILD_CTL_PLUGIN_EXT_TRUE@ +BUILD_CTL_PLUGIN_FALSE = @BUILD_CTL_PLUGIN_FALSE@ +BUILD_CTL_PLUGIN_SHM_FALSE = @BUILD_CTL_PLUGIN_SHM_FALSE@ +BUILD_CTL_PLUGIN_SHM_TRUE = @BUILD_CTL_PLUGIN_SHM_TRUE@ +BUILD_CTL_PLUGIN_TRUE = @BUILD_CTL_PLUGIN_TRUE@ +BUILD_HWDEP_FALSE = @BUILD_HWDEP_FALSE@ +BUILD_HWDEP_TRUE = @BUILD_HWDEP_TRUE@ +BUILD_MIXER_FALSE = @BUILD_MIXER_FALSE@ +BUILD_MIXER_TRUE = @BUILD_MIXER_TRUE@ +BUILD_MODULES_FALSE = @BUILD_MODULES_FALSE@ +BUILD_MODULES_TRUE = @BUILD_MODULES_TRUE@ +BUILD_PCM_FALSE = @BUILD_PCM_FALSE@ +BUILD_PCM_PLUGIN_ADPCM_FALSE = @BUILD_PCM_PLUGIN_ADPCM_FALSE@ +BUILD_PCM_PLUGIN_ADPCM_TRUE = @BUILD_PCM_PLUGIN_ADPCM_TRUE@ +BUILD_PCM_PLUGIN_ALAW_FALSE = @BUILD_PCM_PLUGIN_ALAW_FALSE@ +BUILD_PCM_PLUGIN_ALAW_TRUE = @BUILD_PCM_PLUGIN_ALAW_TRUE@ +BUILD_PCM_PLUGIN_ASYM_FALSE = @BUILD_PCM_PLUGIN_ASYM_FALSE@ +BUILD_PCM_PLUGIN_ASYM_TRUE = @BUILD_PCM_PLUGIN_ASYM_TRUE@ +BUILD_PCM_PLUGIN_COPY_FALSE = @BUILD_PCM_PLUGIN_COPY_FALSE@ +BUILD_PCM_PLUGIN_COPY_TRUE = @BUILD_PCM_PLUGIN_COPY_TRUE@ +BUILD_PCM_PLUGIN_DMIX_FALSE = @BUILD_PCM_PLUGIN_DMIX_FALSE@ +BUILD_PCM_PLUGIN_DMIX_TRUE = @BUILD_PCM_PLUGIN_DMIX_TRUE@ +BUILD_PCM_PLUGIN_DSHARE_FALSE = @BUILD_PCM_PLUGIN_DSHARE_FALSE@ +BUILD_PCM_PLUGIN_DSHARE_TRUE = @BUILD_PCM_PLUGIN_DSHARE_TRUE@ +BUILD_PCM_PLUGIN_DSNOOP_FALSE = @BUILD_PCM_PLUGIN_DSNOOP_FALSE@ +BUILD_PCM_PLUGIN_DSNOOP_TRUE = @BUILD_PCM_PLUGIN_DSNOOP_TRUE@ +BUILD_PCM_PLUGIN_EMPTY_FALSE = @BUILD_PCM_PLUGIN_EMPTY_FALSE@ +BUILD_PCM_PLUGIN_EMPTY_TRUE = @BUILD_PCM_PLUGIN_EMPTY_TRUE@ +BUILD_PCM_PLUGIN_EXTPLUG_FALSE = @BUILD_PCM_PLUGIN_EXTPLUG_FALSE@ +BUILD_PCM_PLUGIN_EXTPLUG_TRUE = @BUILD_PCM_PLUGIN_EXTPLUG_TRUE@ +BUILD_PCM_PLUGIN_FALSE = @BUILD_PCM_PLUGIN_FALSE@ +BUILD_PCM_PLUGIN_FILE_FALSE = @BUILD_PCM_PLUGIN_FILE_FALSE@ +BUILD_PCM_PLUGIN_FILE_TRUE = @BUILD_PCM_PLUGIN_FILE_TRUE@ +BUILD_PCM_PLUGIN_HOOKS_FALSE = @BUILD_PCM_PLUGIN_HOOKS_FALSE@ +BUILD_PCM_PLUGIN_HOOKS_TRUE = @BUILD_PCM_PLUGIN_HOOKS_TRUE@ +BUILD_PCM_PLUGIN_IEC958_FALSE = @BUILD_PCM_PLUGIN_IEC958_FALSE@ +BUILD_PCM_PLUGIN_IEC958_TRUE = @BUILD_PCM_PLUGIN_IEC958_TRUE@ +BUILD_PCM_PLUGIN_IOPLUG_FALSE = @BUILD_PCM_PLUGIN_IOPLUG_FALSE@ +BUILD_PCM_PLUGIN_IOPLUG_TRUE = @BUILD_PCM_PLUGIN_IOPLUG_TRUE@ +BUILD_PCM_PLUGIN_LADSPA_FALSE = @BUILD_PCM_PLUGIN_LADSPA_FALSE@ +BUILD_PCM_PLUGIN_LADSPA_TRUE = @BUILD_PCM_PLUGIN_LADSPA_TRUE@ +BUILD_PCM_PLUGIN_LFLOAT_FALSE = @BUILD_PCM_PLUGIN_LFLOAT_FALSE@ +BUILD_PCM_PLUGIN_LFLOAT_TRUE = @BUILD_PCM_PLUGIN_LFLOAT_TRUE@ +BUILD_PCM_PLUGIN_LINEAR_FALSE = @BUILD_PCM_PLUGIN_LINEAR_FALSE@ +BUILD_PCM_PLUGIN_LINEAR_TRUE = @BUILD_PCM_PLUGIN_LINEAR_TRUE@ +BUILD_PCM_PLUGIN_METER_FALSE = @BUILD_PCM_PLUGIN_METER_FALSE@ +BUILD_PCM_PLUGIN_METER_TRUE = @BUILD_PCM_PLUGIN_METER_TRUE@ +BUILD_PCM_PLUGIN_MMAP_EMUL_FALSE = @BUILD_PCM_PLUGIN_MMAP_EMUL_FALSE@ +BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE = @BUILD_PCM_PLUGIN_MMAP_EMUL_TRUE@ +BUILD_PCM_PLUGIN_MULAW_FALSE = @BUILD_PCM_PLUGIN_MULAW_FALSE@ +BUILD_PCM_PLUGIN_MULAW_TRUE = @BUILD_PCM_PLUGIN_MULAW_TRUE@ +BUILD_PCM_PLUGIN_MULTI_FALSE = @BUILD_PCM_PLUGIN_MULTI_FALSE@ +BUILD_PCM_PLUGIN_MULTI_TRUE = @BUILD_PCM_PLUGIN_MULTI_TRUE@ +BUILD_PCM_PLUGIN_NULL_FALSE = @BUILD_PCM_PLUGIN_NULL_FALSE@ +BUILD_PCM_PLUGIN_NULL_TRUE = @BUILD_PCM_PLUGIN_NULL_TRUE@ +BUILD_PCM_PLUGIN_PLUG_FALSE = @BUILD_PCM_PLUGIN_PLUG_FALSE@ +BUILD_PCM_PLUGIN_PLUG_TRUE = @BUILD_PCM_PLUGIN_PLUG_TRUE@ +BUILD_PCM_PLUGIN_RATE_FALSE = @BUILD_PCM_PLUGIN_RATE_FALSE@ +BUILD_PCM_PLUGIN_RATE_TRUE = @BUILD_PCM_PLUGIN_RATE_TRUE@ +BUILD_PCM_PLUGIN_ROUTE_FALSE = @BUILD_PCM_PLUGIN_ROUTE_FALSE@ +BUILD_PCM_PLUGIN_ROUTE_TRUE = @BUILD_PCM_PLUGIN_ROUTE_TRUE@ +BUILD_PCM_PLUGIN_SHARE_FALSE = @BUILD_PCM_PLUGIN_SHARE_FALSE@ +BUILD_PCM_PLUGIN_SHARE_TRUE = @BUILD_PCM_PLUGIN_SHARE_TRUE@ +BUILD_PCM_PLUGIN_SHM_FALSE = @BUILD_PCM_PLUGIN_SHM_FALSE@ +BUILD_PCM_PLUGIN_SHM_TRUE = @BUILD_PCM_PLUGIN_SHM_TRUE@ +BUILD_PCM_PLUGIN_SOFTVOL_FALSE = @BUILD_PCM_PLUGIN_SOFTVOL_FALSE@ +BUILD_PCM_PLUGIN_SOFTVOL_TRUE = @BUILD_PCM_PLUGIN_SOFTVOL_TRUE@ +BUILD_PCM_PLUGIN_TRUE = @BUILD_PCM_PLUGIN_TRUE@ +BUILD_PCM_TRUE = @BUILD_PCM_TRUE@ +BUILD_PYTHON_FALSE = @BUILD_PYTHON_FALSE@ +BUILD_PYTHON_TRUE = @BUILD_PYTHON_TRUE@ +BUILD_RAWMIDI_FALSE = @BUILD_RAWMIDI_FALSE@ +BUILD_RAWMIDI_TRUE = @BUILD_RAWMIDI_TRUE@ +BUILD_SEQ_FALSE = @BUILD_SEQ_FALSE@ +BUILD_SEQ_TRUE = @BUILD_SEQ_TRUE@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_M4_FALSE = @INSTALL_M4_FALSE@ +INSTALL_M4_TRUE = @INSTALL_M4_TRUE@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KEEP_OLD_SYMBOLS_FALSE = @KEEP_OLD_SYMBOLS_FALSE@ +KEEP_OLD_SYMBOLS_TRUE = @KEEP_OLD_SYMBOLS_TRUE@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_VERSION_INFO = @LIBTOOL_VERSION_INFO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +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@ +SYMBOLIC_FUNCTIONS_FALSE = @SYMBOLIC_FUNCTIONS_FALSE@ +SYMBOLIC_FUNCTIONS_TRUE = @SYMBOLIC_FUNCTIONS_TRUE@ +SYMBOL_PREFIX = @SYMBOL_PREFIX@ +VERSION = @VERSION@ +VERSIONED_SYMBOLS_FALSE = @VERSIONED_SYMBOLS_FALSE@ +VERSIONED_SYMBOLS_TRUE = @VERSIONED_SYMBOLS_TRUE@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +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@ +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@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +TESTS = config midi_event +noinst_HEADERS = test.h +AM_CFLAGS = -Wall -pipe +LDADD = ../../src/libasound.la +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/lsb/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign test/lsb/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +config$(EXEEXT): $(config_OBJECTS) $(config_DEPENDENCIES) + @rm -f config$(EXEEXT) + $(LINK) $(config_LDFLAGS) $(config_OBJECTS) $(config_LDADD) $(LIBS) +midi_event$(EXEEXT): $(midi_event_OBJECTS) $(midi_event_DEPENDENCIES) + @rm -f midi_event$(EXEEXT) + $(LINK) $(midi_event_LDFLAGS) $(midi_event_OBJECTS) $(midi_event_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midi_event.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list='$(TESTS)'; \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + echo "XPASS: $$tst"; \ + ;; \ + *) \ + echo "PASS: $$tst"; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *" $$tst "*) \ + xfail=`expr $$xfail + 1`; \ + echo "XFAIL: $$tst"; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + echo "SKIP: $$tst"; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all tests failed"; \ + else \ + banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + skipped="($$skip tests were not run)"; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/lsb/config.c b/test/lsb/config.c new file mode 100644 index 00000000..3503798f --- /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 00000000..2ae90a7b --- /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 00000000..ff697c58 --- /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/pcm.c b/test/pcm.c index ee274223..abb83e4c 100644 --- a/test/pcm.c +++ b/test/pcm.c @@ -34,17 +34,18 @@ static void generate_sine(const snd_pcm_channel_area_t *areas, static double max_phase = 2. * M_PI; double phase = *_phase; double step = max_phase*freq/(double)rate; - double res; - unsigned char *samples[channels], *tmp; + unsigned char *samples[channels]; int steps[channels]; - unsigned int chn, byte; - union { - int i; - unsigned char c[4]; - } ires; - unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1; - int bps = snd_pcm_format_width(format) / 8; /* bytes per sample */ - + 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) { @@ -61,12 +62,27 @@ static void generate_sine(const snd_pcm_channel_area_t *areas, } /* fill the channel areas */ while (count-- > 0) { - res = sin(phase) * maxval; - ires.i = res; - tmp = ires.c; + union { + float f; + int i; + } fval; + int res, i; + if (is_float) { + fval.f = sin(phase) * maxval; + res = fval.i; + } else + res = sin(phase) * maxval; + if (to_unsigned) + res ^= 1U << (format_bits - 1); for (chn = 0; chn < channels; chn++) { - for (byte = 0; byte < (unsigned int)bps; byte++) - *(samples[chn] + byte) = tmp[byte]; + /* 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; @@ -827,6 +843,13 @@ int main(int argc, char *argv[]) } 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; diff --git a/version b/version index 140333f6..154b9fce 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.0.19 +1.0.23 -- 2.11.0