pax_global_header00006660000000000000000000000064136471001410014507gustar00rootroot0000000000000052 comment=0f9f84877baec02e72435fdfc27ef6d273ff5a8b apulse-0.1.13/000077500000000000000000000000001364710014100130625ustar00rootroot00000000000000apulse-0.1.13/.gitignore000066400000000000000000000000171364710014100150500ustar00rootroot00000000000000/build /debian apulse-0.1.13/3rdparty/000077500000000000000000000000001364710014100146325ustar00rootroot00000000000000apulse-0.1.13/3rdparty/pulseaudio-headers/000077500000000000000000000000001364710014100204155ustar00rootroot00000000000000apulse-0.1.13/3rdparty/pulseaudio-headers/GPL000066400000000000000000000431051364710014100207650ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. apulse-0.1.13/3rdparty/pulseaudio-headers/LGPL000066400000000000000000000636371364710014100211150ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/000077500000000000000000000000001364710014100215455ustar00rootroot00000000000000apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/cdecl.h000066400000000000000000000025021364710014100227670ustar00rootroot00000000000000#ifndef foopulsecdeclhfoo #define foopulsecdeclhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ /** \file * C++ compatibility support */ #ifdef __cplusplus /** If using C++ this macro enables C mode, otherwise does nothing */ #define PA_C_DECL_BEGIN extern "C" { /** If using C++ this macros switches back to C++ mode, otherwise does nothing */ #define PA_C_DECL_END } #else /** If using C++ this macro enables C mode, otherwise does nothing */ #define PA_C_DECL_BEGIN /** If using C++ this macros switches back to C++ mode, otherwise does nothing */ #define PA_C_DECL_END #endif #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/channelmap.h000066400000000000000000000406401364710014100240300ustar00rootroot00000000000000#ifndef foochannelmaphfoo #define foochannelmaphfoo /*** This file is part of PulseAudio. Copyright 2005-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include /** \page channelmap Channel Maps * * \section overv_sec Overview * * Channel maps provide a way to associate channels in a stream with a * specific speaker position. This relieves applications of having to * make sure their channel order is identical to the final output. * * \section init_sec Initialisation * * A channel map consists of an array of \ref pa_channel_position values, * one for each channel. This array is stored together with a channel count * in a pa_channel_map structure. * * Before filling the structure, the application must initialise it using * pa_channel_map_init(). There are also a number of convenience functions * for standard channel mappings: * * \li pa_channel_map_init_mono() - Create a channel map with only mono audio. * \li pa_channel_map_init_stereo() - Create a standard stereo mapping. * \li pa_channel_map_init_auto() - Create a standard channel map for a specific number of channels * \li pa_channel_map_init_extend() - Similar to * pa_channel_map_init_auto() but synthesize a channel map if no * predefined one is known for the specified number of channels. * * \section conv_sec Convenience Functions * * The library contains a number of convenience functions for dealing with * channel maps: * * \li pa_channel_map_valid() - Tests if a channel map is valid. * \li pa_channel_map_equal() - Tests if two channel maps are identical. * \li pa_channel_map_snprint() - Creates a textual description of a channel * map. */ /** \file * Constants and routines for channel mapping handling * * See also \subpage channelmap */ PA_C_DECL_BEGIN /** A list of channel labels */ typedef enum pa_channel_position { PA_CHANNEL_POSITION_INVALID = -1, PA_CHANNEL_POSITION_MONO = 0, PA_CHANNEL_POSITION_FRONT_LEFT, /**< Apple, Dolby call this 'Left' */ PA_CHANNEL_POSITION_FRONT_RIGHT, /**< Apple, Dolby call this 'Right' */ PA_CHANNEL_POSITION_FRONT_CENTER, /**< Apple, Dolby call this 'Center' */ /** \cond fulldocs */ PA_CHANNEL_POSITION_LEFT = PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_RIGHT = PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_CENTER = PA_CHANNEL_POSITION_FRONT_CENTER, /** \endcond */ PA_CHANNEL_POSITION_REAR_CENTER, /**< Microsoft calls this 'Back Center', Apple calls this 'Center Surround', Dolby calls this 'Surround Rear Center' */ PA_CHANNEL_POSITION_REAR_LEFT, /**< Microsoft calls this 'Back Left', Apple calls this 'Left Surround' (!), Dolby calls this 'Surround Rear Left' */ PA_CHANNEL_POSITION_REAR_RIGHT, /**< Microsoft calls this 'Back Right', Apple calls this 'Right Surround' (!), Dolby calls this 'Surround Rear Right' */ PA_CHANNEL_POSITION_LFE, /**< Microsoft calls this 'Low Frequency', Apple calls this 'LFEScreen' */ /** \cond fulldocs */ PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, /** \endcond */ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, /**< Apple, Dolby call this 'Left Center' */ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, /**< Apple, Dolby call this 'Right Center */ PA_CHANNEL_POSITION_SIDE_LEFT, /**< Apple calls this 'Left Surround Direct', Dolby calls this 'Surround Left' (!) */ PA_CHANNEL_POSITION_SIDE_RIGHT, /**< Apple calls this 'Right Surround Direct', Dolby calls this 'Surround Right' (!) */ PA_CHANNEL_POSITION_AUX0, PA_CHANNEL_POSITION_AUX1, PA_CHANNEL_POSITION_AUX2, PA_CHANNEL_POSITION_AUX3, PA_CHANNEL_POSITION_AUX4, PA_CHANNEL_POSITION_AUX5, PA_CHANNEL_POSITION_AUX6, PA_CHANNEL_POSITION_AUX7, PA_CHANNEL_POSITION_AUX8, PA_CHANNEL_POSITION_AUX9, PA_CHANNEL_POSITION_AUX10, PA_CHANNEL_POSITION_AUX11, PA_CHANNEL_POSITION_AUX12, PA_CHANNEL_POSITION_AUX13, PA_CHANNEL_POSITION_AUX14, PA_CHANNEL_POSITION_AUX15, PA_CHANNEL_POSITION_AUX16, PA_CHANNEL_POSITION_AUX17, PA_CHANNEL_POSITION_AUX18, PA_CHANNEL_POSITION_AUX19, PA_CHANNEL_POSITION_AUX20, PA_CHANNEL_POSITION_AUX21, PA_CHANNEL_POSITION_AUX22, PA_CHANNEL_POSITION_AUX23, PA_CHANNEL_POSITION_AUX24, PA_CHANNEL_POSITION_AUX25, PA_CHANNEL_POSITION_AUX26, PA_CHANNEL_POSITION_AUX27, PA_CHANNEL_POSITION_AUX28, PA_CHANNEL_POSITION_AUX29, PA_CHANNEL_POSITION_AUX30, PA_CHANNEL_POSITION_AUX31, PA_CHANNEL_POSITION_TOP_CENTER, /**< Apple calls this 'Top Center Surround' */ PA_CHANNEL_POSITION_TOP_FRONT_LEFT, /**< Apple calls this 'Vertical Height Left' */ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, /**< Apple calls this 'Vertical Height Right' */ PA_CHANNEL_POSITION_TOP_FRONT_CENTER, /**< Apple calls this 'Vertical Height Center' */ PA_CHANNEL_POSITION_TOP_REAR_LEFT, /**< Microsoft and Apple call this 'Top Back Left' */ PA_CHANNEL_POSITION_TOP_REAR_RIGHT, /**< Microsoft and Apple call this 'Top Back Right' */ PA_CHANNEL_POSITION_TOP_REAR_CENTER, /**< Microsoft and Apple call this 'Top Back Center' */ PA_CHANNEL_POSITION_MAX } pa_channel_position_t; /** \cond fulldocs */ #define PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_INVALID #define PA_CHANNEL_POSITION_MONO PA_CHANNEL_POSITION_MONO #define PA_CHANNEL_POSITION_LEFT PA_CHANNEL_POSITION_LEFT #define PA_CHANNEL_POSITION_RIGHT PA_CHANNEL_POSITION_RIGHT #define PA_CHANNEL_POSITION_CENTER PA_CHANNEL_POSITION_CENTER #define PA_CHANNEL_POSITION_FRONT_LEFT PA_CHANNEL_POSITION_FRONT_LEFT #define PA_CHANNEL_POSITION_FRONT_RIGHT PA_CHANNEL_POSITION_FRONT_RIGHT #define PA_CHANNEL_POSITION_FRONT_CENTER PA_CHANNEL_POSITION_FRONT_CENTER #define PA_CHANNEL_POSITION_REAR_CENTER PA_CHANNEL_POSITION_REAR_CENTER #define PA_CHANNEL_POSITION_REAR_LEFT PA_CHANNEL_POSITION_REAR_LEFT #define PA_CHANNEL_POSITION_REAR_RIGHT PA_CHANNEL_POSITION_REAR_RIGHT #define PA_CHANNEL_POSITION_LFE PA_CHANNEL_POSITION_LFE #define PA_CHANNEL_POSITION_SUBWOOFER PA_CHANNEL_POSITION_SUBWOOFER #define PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER #define PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER #define PA_CHANNEL_POSITION_SIDE_LEFT PA_CHANNEL_POSITION_SIDE_LEFT #define PA_CHANNEL_POSITION_SIDE_RIGHT PA_CHANNEL_POSITION_SIDE_RIGHT #define PA_CHANNEL_POSITION_AUX0 PA_CHANNEL_POSITION_AUX0 #define PA_CHANNEL_POSITION_AUX1 PA_CHANNEL_POSITION_AUX1 #define PA_CHANNEL_POSITION_AUX2 PA_CHANNEL_POSITION_AUX2 #define PA_CHANNEL_POSITION_AUX3 PA_CHANNEL_POSITION_AUX3 #define PA_CHANNEL_POSITION_AUX4 PA_CHANNEL_POSITION_AUX4 #define PA_CHANNEL_POSITION_AUX5 PA_CHANNEL_POSITION_AUX5 #define PA_CHANNEL_POSITION_AUX6 PA_CHANNEL_POSITION_AUX6 #define PA_CHANNEL_POSITION_AUX7 PA_CHANNEL_POSITION_AUX7 #define PA_CHANNEL_POSITION_AUX8 PA_CHANNEL_POSITION_AUX8 #define PA_CHANNEL_POSITION_AUX9 PA_CHANNEL_POSITION_AUX9 #define PA_CHANNEL_POSITION_AUX10 PA_CHANNEL_POSITION_AUX10 #define PA_CHANNEL_POSITION_AUX11 PA_CHANNEL_POSITION_AUX11 #define PA_CHANNEL_POSITION_AUX12 PA_CHANNEL_POSITION_AUX12 #define PA_CHANNEL_POSITION_AUX13 PA_CHANNEL_POSITION_AUX13 #define PA_CHANNEL_POSITION_AUX14 PA_CHANNEL_POSITION_AUX14 #define PA_CHANNEL_POSITION_AUX15 PA_CHANNEL_POSITION_AUX15 #define PA_CHANNEL_POSITION_AUX16 PA_CHANNEL_POSITION_AUX16 #define PA_CHANNEL_POSITION_AUX17 PA_CHANNEL_POSITION_AUX17 #define PA_CHANNEL_POSITION_AUX18 PA_CHANNEL_POSITION_AUX18 #define PA_CHANNEL_POSITION_AUX19 PA_CHANNEL_POSITION_AUX19 #define PA_CHANNEL_POSITION_AUX20 PA_CHANNEL_POSITION_AUX20 #define PA_CHANNEL_POSITION_AUX21 PA_CHANNEL_POSITION_AUX21 #define PA_CHANNEL_POSITION_AUX22 PA_CHANNEL_POSITION_AUX22 #define PA_CHANNEL_POSITION_AUX23 PA_CHANNEL_POSITION_AUX23 #define PA_CHANNEL_POSITION_AUX24 PA_CHANNEL_POSITION_AUX24 #define PA_CHANNEL_POSITION_AUX25 PA_CHANNEL_POSITION_AUX25 #define PA_CHANNEL_POSITION_AUX26 PA_CHANNEL_POSITION_AUX26 #define PA_CHANNEL_POSITION_AUX27 PA_CHANNEL_POSITION_AUX27 #define PA_CHANNEL_POSITION_AUX28 PA_CHANNEL_POSITION_AUX28 #define PA_CHANNEL_POSITION_AUX29 PA_CHANNEL_POSITION_AUX29 #define PA_CHANNEL_POSITION_AUX30 PA_CHANNEL_POSITION_AUX30 #define PA_CHANNEL_POSITION_AUX31 PA_CHANNEL_POSITION_AUX31 #define PA_CHANNEL_POSITION_TOP_CENTER PA_CHANNEL_POSITION_TOP_CENTER #define PA_CHANNEL_POSITION_TOP_FRONT_LEFT PA_CHANNEL_POSITION_TOP_FRONT_LEFT #define PA_CHANNEL_POSITION_TOP_FRONT_RIGHT PA_CHANNEL_POSITION_TOP_FRONT_RIGHT #define PA_CHANNEL_POSITION_TOP_FRONT_CENTER PA_CHANNEL_POSITION_TOP_FRONT_CENTER #define PA_CHANNEL_POSITION_TOP_REAR_LEFT PA_CHANNEL_POSITION_TOP_REAR_LEFT #define PA_CHANNEL_POSITION_TOP_REAR_RIGHT PA_CHANNEL_POSITION_TOP_REAR_RIGHT #define PA_CHANNEL_POSITION_TOP_REAR_CENTER PA_CHANNEL_POSITION_TOP_REAR_CENTER #define PA_CHANNEL_POSITION_MAX PA_CHANNEL_POSITION_MAX /** \endcond */ /** A mask of channel positions. \since 0.9.16 */ typedef uint64_t pa_channel_position_mask_t; /** Makes a bit mask from a channel position. \since 0.9.16 */ #define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1ULL << (f))) /** A list of channel mapping definitions for pa_channel_map_init_auto() */ typedef enum pa_channel_map_def { PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ /** \cond fulldocs */ PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA. This mapping is probably * not too useful since ALSA's default channel mapping depends on * the device string used. */ /** \endcond */ PA_CHANNEL_MAP_AUX, /**< Only aux channels */ PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping. This mapping works * as if all LSBs of dwChannelMask are set. */ /** \cond fulldocs */ PA_CHANNEL_MAP_OSS, /**< The default channel mapping used by OSS as defined in the OSS * 4.0 API specs. This mapping is probably not too useful since * the OSS API has changed in this respect and no longer knows a * default channel mapping based on the number of channels. */ /** \endcond */ /**< Upper limit of valid channel mapping definitions */ PA_CHANNEL_MAP_DEF_MAX, PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ } pa_channel_map_def_t; /** \cond fulldocs */ #define PA_CHANNEL_MAP_AIFF PA_CHANNEL_MAP_AIFF #define PA_CHANNEL_MAP_ALSA PA_CHANNEL_MAP_ALSA #define PA_CHANNEL_MAP_AUX PA_CHANNEL_MAP_AUX #define PA_CHANNEL_MAP_WAVEEX PA_CHANNEL_MAP_WAVEEX #define PA_CHANNEL_MAP_OSS PA_CHANNEL_MAP_OSS #define PA_CHANNEL_MAP_DEF_MAX PA_CHANNEL_MAP_DEF_MAX #define PA_CHANNEL_MAP_DEFAULT PA_CHANNEL_MAP_DEFAULT /** \endcond */ /** A channel map which can be used to attach labels to specific * channels of a stream. These values are relevant for conversion and * mixing of streams */ typedef struct pa_channel_map { uint8_t channels; /**< Number of channels */ pa_channel_position_t map[PA_CHANNELS_MAX]; /**< Channel labels */ } pa_channel_map; /** Initialize the specified channel map and return a pointer to * it. The channel map will have a defined state but * pa_channel_map_valid() will fail for it. */ pa_channel_map* pa_channel_map_init(pa_channel_map *m); /** Initialize the specified channel map for monaural audio and return a pointer to it */ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); /** Initialize the specified channel map for stereophonic audio and return a pointer to it */ pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); /** Initialize the specified channel map for the specified number of * channels using default labels and return a pointer to it. This call * will fail (return NULL) if there is no default channel map known for this * specific number of channels and mapping. */ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); /** Similar to pa_channel_map_init_auto() but instead of failing if no * default mapping is known with the specified parameters it will * synthesize a mapping based on a known mapping with fewer channels * and fill up the rest with AUX0...AUX31 channels \since 0.9.11 */ pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); /** Return a text label for the specified channel position */ const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE; /** The inverse of pa_channel_position_to_string(). \since 0.9.16 */ pa_channel_position_t pa_channel_position_from_string(const char *s) PA_GCC_PURE; /** Return a human readable text label for the specified channel position. \since 0.9.7 */ const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos); /** The maximum length of strings returned by * pa_channel_map_snprint(). Please note that this value can change * with any release without warning and without being considered API * or ABI breakage. You should not use this definition anywhere where * it might become part of an ABI. */ #define PA_CHANNEL_MAP_SNPRINT_MAX 336 /** Make a human readable string from the specified channel map */ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); /** Parse a channel position list or well-known mapping name into a * channel map structure. This turns the output of * pa_channel_map_snprint() and pa_channel_map_to_name() back into a * pa_channel_map */ pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s); /** Compare two channel maps. Return 1 if both match. */ int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) PA_GCC_PURE; /** Return non-zero if the specified channel map is considered valid */ int pa_channel_map_valid(const pa_channel_map *map) PA_GCC_PURE; /** Return non-zero if the specified channel map is compatible with * the specified sample spec. \since 0.9.12 */ int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) PA_GCC_PURE; /** Returns non-zero if every channel defined in b is also defined in a. \since 0.9.15 */ int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) PA_GCC_PURE; /** Returns non-zero if it makes sense to apply a volume 'balance' * with this mapping, i.e.\ if there are left/right channels * available. \since 0.9.15 */ int pa_channel_map_can_balance(const pa_channel_map *map) PA_GCC_PURE; /** Returns non-zero if it makes sense to apply a volume 'fade' * (i.e.\ 'balance' between front and rear) with this mapping, i.e.\ if * there are front/rear channels available. \since 0.9.15 */ int pa_channel_map_can_fade(const pa_channel_map *map) PA_GCC_PURE; /** Tries to find a well-known channel mapping name for this channel * mapping, i.e.\ "stereo", "surround-71" and so on. If the channel * mapping is unknown NULL will be returned. This name can be parsed * with pa_channel_map_parse() \since 0.9.15 */ const char* pa_channel_map_to_name(const pa_channel_map *map) PA_GCC_PURE; /** Tries to find a human readable text label for this channel mapping, i.e.\ "Stereo", "Surround 7.1" and so on. If the channel mapping is unknown NULL will be returned. \since 0.9.15 */ const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) PA_GCC_PURE; /** Returns non-zero if the specified channel position is available at * least once in the channel map. \since 0.9.16 */ int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) PA_GCC_PURE; /** Generates a bit mask from a channel map. \since 0.9.16 */ pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) PA_GCC_PURE; PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/context.h000066400000000000000000000317701364710014100234120ustar00rootroot00000000000000#ifndef foocontexthfoo #define foocontexthfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include #include /** \page async Asynchronous API * * \section overv_sec Overview * * The asynchronous API is the native interface to the PulseAudio library. * It allows full access to all available functionality. This however means that * it is rather complex and can take some time to fully master. * * \section mainloop_sec Main Loop Abstraction * * The API is based around an asynchronous event loop, or main loop, * abstraction. This abstraction contains three basic elements: * * \li Deferred events - Events that will trigger as soon as possible. Note * that some implementations may block all other events * when a deferred event is active. * \li I/O events - Events that trigger on file descriptor activities. * \li Times events - Events that trigger after a fixed amount of time. * * The abstraction is represented as a number of function pointers in the * pa_mainloop_api structure. * * To actually be able to use these functions, an implementation needs to * be coupled to the abstraction. There are three of these shipped with * PulseAudio, but any other can be used with a minimal amount of work, * provided it supports the three basic events listed above. * * The implementations shipped with PulseAudio are: * * \li \subpage mainloop - A minimal but fast implementation based on poll(). * \li \subpage threaded_mainloop - A special version of the previous * implementation where all of PulseAudio's * internal handling runs in a separate * thread. * \li \subpage glib-mainloop - A wrapper around GLib's main loop. * * UNIX signals may be hooked to a main loop using the functions from * \ref mainloop-signal.h. These rely only on the main loop abstraction * and can therefore be used with any of the implementations. * * \section refcnt_sec Reference Counting * * Almost all objects in PulseAudio are reference counted. What that means * is that you rarely malloc() or free() any objects. Instead you increase * and decrease their reference counts. Whenever an object's reference * count reaches zero, that object gets destroy and any resources it uses * get freed. * * The benefit of this design is that an application need not worry about * whether or not it needs to keep an object around in case the library is * using it internally. If it is, then it has made sure it has its own * reference to it. * * Whenever the library creates an object, it will have an initial * reference count of one. Most of the time, this single reference will be * sufficient for the application, so all required reference count * interaction will be a single call to the object's unref function. * * \section context_sec Context * * A context is the basic object for a connection to a PulseAudio server. * It multiplexes commands, data streams and events through a single * channel. * * There is no need for more than one context per application, unless * connections to multiple servers are needed. * * \subsection ops_subsec Operations * * All operations on the context are performed asynchronously. I.e. the * client will not wait for the server to complete the request. To keep * track of all these in-flight operations, the application is given a * pa_operation object for each asynchronous operation. * * There are only two actions (besides reference counting) that can be * performed on a pa_operation: querying its state with * pa_operation_get_state() and aborting it with pa_operation_cancel(). * * A pa_operation object is reference counted, so an application must * make sure to unreference it, even if it has no intention of using it. * * \subsection conn_subsec Connecting * * A context must be connected to a server before any operation can be * issued. Calling pa_context_connect() will initiate the connection * procedure. Unlike most asynchronous operations, connecting does not * result in a pa_operation object. Instead, the application should * register a callback using pa_context_set_state_callback(). * * \subsection disc_subsec Disconnecting * * When the sound support is no longer needed, the connection needs to be * closed using pa_context_disconnect(). This is an immediate function that * works synchronously. * * Since the context object has references to other objects it must be * disconnected after use or there is a high risk of memory leaks. If the * connection has terminated by itself, then there is no need to explicitly * disconnect the context using pa_context_disconnect(). * * \section Functions * * The sound server's functionality can be divided into a number of * subsections: * * \li \subpage streams * \li \subpage scache * \li \subpage introspect * \li \subpage subscribe */ /** \file * Connection contexts for asynchronous communication with a * server. A pa_context object wraps a connection to a PulseAudio * server using its native protocol. * * See also \subpage async */ PA_C_DECL_BEGIN /** An opaque connection context to a daemon */ typedef struct pa_context pa_context; /** Generic notification callback prototype */ typedef void (*pa_context_notify_cb_t)(pa_context *c, void *userdata); /** A generic callback for operation completion */ typedef void (*pa_context_success_cb_t) (pa_context *c, int success, void *userdata); /** A callback for asynchronous meta/policy event messages. The set * of defined events can be extended at any time. Also, server modules * may introduce additional message types so make sure that your * callback function ignores messages it doesn't know. \since * 0.9.15 */ typedef void (*pa_context_event_cb_t)(pa_context *c, const char *name, pa_proplist *p, void *userdata); /** Instantiate a new connection context with an abstract mainloop API * and an application name. It is recommended to use pa_context_new_with_proplist() * instead and specify some initial properties.*/ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); /** Instantiate a new connection context with an abstract mainloop API * and an application name, and specify the initial client property * list. \since 0.9.11 */ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist); /** Decrease the reference counter of the context by one */ void pa_context_unref(pa_context *c); /** Increase the reference counter of the context by one */ pa_context* pa_context_ref(pa_context *c); /** Set a callback function that is called whenever the context status changes */ void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata); /** Set a callback function that is called whenever a meta/policy * control event is received. \since 0.9.15 */ void pa_context_set_event_callback(pa_context *p, pa_context_event_cb_t cb, void *userdata); /** Return the error number of the last failed operation */ int pa_context_errno(pa_context *c); /** Return non-zero if some data is pending to be written to the connection */ int pa_context_is_pending(pa_context *c); /** Return the current context status */ pa_context_state_t pa_context_get_state(pa_context *c); /** Connect the context to the specified server. If server is NULL, connect to the default server. This routine may but will not always return synchronously on error. Use pa_context_set_state_callback() to be notified when the connection is established. If flags doesn't have PA_CONTEXT_NOAUTOSPAWN set and no specific server is specified or accessible a new daemon is spawned. If api is non-NULL, the functions specified in the structure are used when forking a new child process. */ int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); /** Terminate the context connection immediately */ void pa_context_disconnect(pa_context *c); /** Drain the context. If there is nothing to drain, the function returns NULL */ pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata); /** Tell the daemon to exit. The returned operation is unlikely to * complete successfully, since the daemon probably died before * returning a success notification */ pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata); /** Set the name of the default sink. */ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Set the name of the default source. */ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. */ int pa_context_is_local(pa_context *c); /** Set a different application name for context on the server. */ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Return the server name this context is connected to. */ const char* pa_context_get_server(pa_context *c); /** Return the protocol version of the library. */ uint32_t pa_context_get_protocol_version(pa_context *c); /** Return the protocol version of the connected server. */ uint32_t pa_context_get_server_protocol_version(pa_context *c); /** Update the property list of the client, adding new entries. Please * note that it is highly recommended to set as much properties * initially via pa_context_new_with_proplist() as possible instead a * posteriori with this function, since that information may then be * used to route streams of the client to the right device. \since 0.9.11 */ pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata); /** Update the property list of the client, remove entries. \since 0.9.11 */ pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata); /** Return the client index this context is * identified in the server with. This is useful for usage with the * introspection functions, such as pa_context_get_client_info(). \since 0.9.11 */ uint32_t pa_context_get_index(pa_context *s); /** Create a new timer event source for the specified time (wrapper * for mainloop->time_new). \since 0.9.16 */ pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata); /** Restart a running or expired timer event source (wrapper for * mainloop->time_restart). \since 0.9.16 */ void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec); /** Return the optimal block size for passing around audio buffers. It * is recommended to allocate buffers of the size returned here when * writing audio data to playback streams, if the latency constraints * permit this. It is not recommended writing larger blocks than this * because usually they will then be split up internally into chunks * of this size. It is not recommended writing smaller blocks than * this (unless required due to latency demands) because this * increases CPU usage. If ss is NULL you will be returned the * byte-exact tile size. If you pass a valid ss, then the tile size * will be rounded down to multiple of the frame size. This is * supposed to be used in a construct such as * pa_context_get_tile_size(pa_stream_get_context(s), * pa_stream_get_sample_spec(ss)); \since 0.9.20 */ size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss); /** Load the authentication cookie from a file. This function is primarily * meant for PulseAudio's own tunnel modules, which need to load the cookie * from a custom location. Applications don't usually need to care about the * cookie at all, but if it happens that you know what the authentication * cookie is and your application needs to load it from a non-standard * location, feel free to use this function. \since 5.0 */ int pa_context_load_cookie_from_file(pa_context *c, const char *cookie_file_path); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/def.h000066400000000000000000001276171364710014100224720ustar00rootroot00000000000000#ifndef foodefhfoo #define foodefhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include /** \file * Global definitions */ PA_C_DECL_BEGIN /** The state of a connection context */ typedef enum pa_context_state { PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ PA_CONTEXT_CONNECTING, /**< A connection is being established */ PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ } pa_context_state_t; /** Return non-zero if the passed state is one of the connected states. \since 0.9.11 */ static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) { return x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING || x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY; } /** \cond fulldocs */ #define PA_CONTEXT_UNCONNECTED PA_CONTEXT_UNCONNECTED #define PA_CONTEXT_CONNECTING PA_CONTEXT_CONNECTING #define PA_CONTEXT_AUTHORIZING PA_CONTEXT_AUTHORIZING #define PA_CONTEXT_SETTING_NAME PA_CONTEXT_SETTING_NAME #define PA_CONTEXT_READY PA_CONTEXT_READY #define PA_CONTEXT_FAILED PA_CONTEXT_FAILED #define PA_CONTEXT_TERMINATED PA_CONTEXT_TERMINATED #define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD /** \endcond */ /** The state of a stream */ typedef enum pa_stream_state { PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */ PA_STREAM_CREATING, /**< The stream is being created */ PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ PA_STREAM_FAILED, /**< An error occurred that made the stream invalid */ PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ } pa_stream_state_t; /** Return non-zero if the passed state is one of the connected states. \since 0.9.11 */ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) { return x == PA_STREAM_CREATING || x == PA_STREAM_READY; } /** \cond fulldocs */ #define PA_STREAM_UNCONNECTED PA_STREAM_UNCONNECTED #define PA_STREAM_CREATING PA_STREAM_CREATING #define PA_STREAM_READY PA_STREAM_READY #define PA_STREAM_FAILED PA_STREAM_FAILED #define PA_STREAM_TERMINATED PA_STREAM_TERMINATED #define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD /** \endcond */ /** The state of an operation */ typedef enum pa_operation_state { PA_OPERATION_RUNNING, /**< The operation is still running */ PA_OPERATION_DONE, /**< The operation has completed */ PA_OPERATION_CANCELLED /**< The operation has been cancelled. Operations may get cancelled by the * application, or as a result of the context getting disconneted while the * operation is pending. */ } pa_operation_state_t; /** \cond fulldocs */ #define PA_OPERATION_RUNNING PA_OPERATION_RUNNING #define PA_OPERATION_DONE PA_OPERATION_DONE #define PA_OPERATION_CANCELED PA_OPERATION_CANCELLED #define PA_OPERATION_CANCELLED PA_OPERATION_CANCELLED /** \endcond */ /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) /** Some special flags for contexts. */ typedef enum pa_context_flags { PA_CONTEXT_NOFLAGS = 0x0000U, /**< Flag to pass when no specific options are needed (used to avoid casting) \since 0.9.19 */ PA_CONTEXT_NOAUTOSPAWN = 0x0001U, /**< Disabled autospawning of the PulseAudio daemon if required */ PA_CONTEXT_NOFAIL = 0x0002U /**< Don't fail if the daemon is not available when pa_context_connect() is called, instead enter PA_CONTEXT_CONNECTING state and wait for the daemon to appear. \since 0.9.15 */ } pa_context_flags_t; /** \cond fulldocs */ /* Allow clients to check with #ifdef for those flags */ #define PA_CONTEXT_NOAUTOSPAWN PA_CONTEXT_NOAUTOSPAWN #define PA_CONTEXT_NOFAIL PA_CONTEXT_NOFAIL /** \endcond */ /** Direction bitfield - while we currently do not expose anything bidirectional, one should test against the bit instead of the value (e.g.\ if (d & PA_DIRECTION_OUTPUT)), because we might add bidirectional stuff in the future. \since 2.0 */ typedef enum pa_direction { PA_DIRECTION_OUTPUT = 0x0001U, /**< Output direction */ PA_DIRECTION_INPUT = 0x0002U /**< Input direction */ } pa_direction_t; /** \cond fulldocs */ #define PA_DIRECTION_OUTPUT PA_DIRECTION_OUTPUT #define PA_DIRECTION_INPUT PA_DIRECTION_INPUT /** \endcond */ /** The type of device we are dealing with */ typedef enum pa_device_type { PA_DEVICE_TYPE_SINK, /**< Playback device */ PA_DEVICE_TYPE_SOURCE /**< Recording device */ } pa_device_type_t; /** \cond fulldocs */ #define PA_DEVICE_TYPE_SINK PA_DEVICE_TYPE_SINK #define PA_DEVICE_TYPE_SOURCE PA_DEVICE_TYPE_SOURCE /** \endcond */ /** The direction of a pa_stream object */ typedef enum pa_stream_direction { PA_STREAM_NODIRECTION, /**< Invalid direction */ PA_STREAM_PLAYBACK, /**< Playback stream */ PA_STREAM_RECORD, /**< Record stream */ PA_STREAM_UPLOAD /**< Sample upload stream */ } pa_stream_direction_t; /** \cond fulldocs */ #define PA_STREAM_NODIRECTION PA_STREAM_NODIRECTION #define PA_STREAM_PLAYBACK PA_STREAM_PLAYBACK #define PA_STREAM_RECORD PA_STREAM_RECORD #define PA_STREAM_UPLOAD PA_STREAM_UPLOAD /** \endcond */ /** Some special flags for stream connections. */ typedef enum pa_stream_flags { PA_STREAM_NOFLAGS = 0x0000U, /**< Flag to pass when no specific options are needed (used to avoid casting) \since 0.9.19 */ PA_STREAM_START_CORKED = 0x0001U, /**< Create the stream corked, requiring an explicit * pa_stream_cork() call to uncork it. */ PA_STREAM_INTERPOLATE_TIMING = 0x0002U, /**< Interpolate the latency for this stream. When enabled, * pa_stream_get_latency() and pa_stream_get_time() will try to * estimate the current record/playback time based on the local * time that passed since the last timing info update. Using this * option has the advantage of not requiring a whole roundtrip * when the current playback/recording time is needed. Consider * using this option when requesting latency information * frequently. This is especially useful on long latency network * connections. It makes a lot of sense to combine this option * with PA_STREAM_AUTO_TIMING_UPDATE. */ PA_STREAM_NOT_MONOTONIC = 0x0004U, /**< Don't force the time to increase monotonically. If this * option is enabled, pa_stream_get_time() will not necessarily * return always monotonically increasing time values on each * call. This may confuse applications which cannot deal with time * going 'backwards', but has the advantage that bad transport * latency estimations that caused the time to to jump ahead can * be corrected quickly, without the need to wait. (Please note * that this flag was named PA_STREAM_NOT_MONOTONOUS in releases * prior to 0.9.11. The old name is still defined too, for * compatibility reasons. */ PA_STREAM_AUTO_TIMING_UPDATE = 0x0008U, /**< If set timing update requests are issued periodically * automatically. Combined with PA_STREAM_INTERPOLATE_TIMING you * will be able to query the current time and latency with * pa_stream_get_time() and pa_stream_get_latency() at all times * without a packet round trip.*/ PA_STREAM_NO_REMAP_CHANNELS = 0x0010U, /**< Don't remap channels by their name, instead map them simply * by their index. Implies PA_STREAM_NO_REMIX_CHANNELS. Only * supported when the server is at least PA 0.9.8. It is ignored * on older servers.\since 0.9.8 */ PA_STREAM_NO_REMIX_CHANNELS = 0x0020U, /**< When remapping channels by name, don't upmix or downmix them * to related channels. Copy them into matching channels of the * device 1:1. Only supported when the server is at least PA * 0.9.8. It is ignored on older servers. \since 0.9.8 */ PA_STREAM_FIX_FORMAT = 0x0040U, /**< Use the sample format of the sink/device this stream is being * connected to, and possibly ignore the format the sample spec * contains -- but you still have to pass a valid value in it as a * hint to PulseAudio what would suit your stream best. If this is * used you should query the used sample format after creating the * stream by using pa_stream_get_sample_spec(). Also, if you * specified manual buffer metrics it is recommended to update * them with pa_stream_set_buffer_attr() to compensate for the * changed frame sizes. Only supported when the server is at least * PA 0.9.8. It is ignored on older servers. * * When creating streams with pa_stream_new_extended(), this flag has no * effect. If you specify a format with PCM encoding, and you want the * server to choose the sample format, then you should leave the sample * format unspecified in the pa_format_info object. This also means that * you can't use pa_format_info_from_sample_spec(), because that function * always sets the sample format. * * \since 0.9.8 */ PA_STREAM_FIX_RATE = 0x0080U, /**< Use the sample rate of the sink, and possibly ignore the rate * the sample spec contains. Usage similar to * PA_STREAM_FIX_FORMAT. Only supported when the server is at least * PA 0.9.8. It is ignored on older servers. * * When creating streams with pa_stream_new_extended(), this flag has no * effect. If you specify a format with PCM encoding, and you want the * server to choose the sample rate, then you should leave the rate * unspecified in the pa_format_info object. This also means that you can't * use pa_format_info_from_sample_spec(), because that function always sets * the sample rate. * * \since 0.9.8 */ PA_STREAM_FIX_CHANNELS = 0x0100, /**< Use the number of channels and the channel map of the sink, * and possibly ignore the number of channels and the map the * sample spec and the passed channel map contains. Usage similar * to PA_STREAM_FIX_FORMAT. Only supported when the server is at * least PA 0.9.8. It is ignored on older servers. * * When creating streams with pa_stream_new_extended(), this flag has no * effect. If you specify a format with PCM encoding, and you want the * server to choose the channel count and/or channel map, then you should * leave the channels and/or the channel map unspecified in the * pa_format_info object. This also means that you can't use * pa_format_info_from_sample_spec(), because that function always sets * the channel count (but if you only want to leave the channel map * unspecified, then pa_format_info_from_sample_spec() works, because it * accepts a NULL channel map). * * \since 0.9.8 */ PA_STREAM_DONT_MOVE = 0x0200U, /**< Don't allow moving of this stream to another * sink/device. Useful if you use any of the PA_STREAM_FIX_ flags * and want to make sure that resampling never takes place -- * which might happen if the stream is moved to another * sink/source with a different sample spec/channel map. Only * supported when the server is at least PA 0.9.8. It is ignored * on older servers. \since 0.9.8 */ PA_STREAM_VARIABLE_RATE = 0x0400U, /**< Allow dynamic changing of the sampling rate during playback * with pa_stream_update_sample_rate(). Only supported when the * server is at least PA 0.9.8. It is ignored on older * servers. \since 0.9.8 */ PA_STREAM_PEAK_DETECT = 0x0800U, /**< Find peaks instead of resampling. \since 0.9.11 */ PA_STREAM_START_MUTED = 0x1000U, /**< Create in muted state. If neither PA_STREAM_START_UNMUTED nor * PA_STREAM_START_MUTED it is left to the server to decide * whether to create the stream in muted or in unmuted * state. \since 0.9.11 */ PA_STREAM_ADJUST_LATENCY = 0x2000U, /**< Try to adjust the latency of the sink/source based on the * requested buffer metrics and adjust buffer metrics * accordingly. Also see pa_buffer_attr. This option may not be * specified at the same time as PA_STREAM_EARLY_REQUESTS. \since * 0.9.11 */ PA_STREAM_EARLY_REQUESTS = 0x4000U, /**< Enable compatibility mode for legacy clients that rely on a * "classic" hardware device fragment-style playback model. If * this option is set, the minreq value of the buffer metrics gets * a new meaning: instead of just specifying that no requests * asking for less new data than this value will be made to the * client it will also guarantee that requests are generated as * early as this limit is reached. This flag should only be set in * very few situations where compatibility with a fragment-based * playback model needs to be kept and the client applications * cannot deal with data requests that are delayed to the latest * moment possible. (Usually these are programs that use usleep() * or a similar call in their playback loops instead of sleeping * on the device itself.) Also see pa_buffer_attr. This option may * not be specified at the same time as * PA_STREAM_ADJUST_LATENCY. \since 0.9.12 */ PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND = 0x8000U, /**< If set this stream won't be taken into account when it is * checked whether the device this stream is connected to should * auto-suspend. \since 0.9.15 */ PA_STREAM_START_UNMUTED = 0x10000U, /**< Create in unmuted state. If neither PA_STREAM_START_UNMUTED * nor PA_STREAM_START_MUTED it is left to the server to decide * whether to create the stream in muted or in unmuted * state. \since 0.9.15 */ PA_STREAM_FAIL_ON_SUSPEND = 0x20000U, /**< If the sink/source this stream is connected to is suspended * during the creation of this stream, cause it to fail. If the * sink/source is being suspended during creation of this stream, * make sure this stream is terminated. \since 0.9.15 */ PA_STREAM_RELATIVE_VOLUME = 0x40000U, /**< If a volume is passed when this stream is created, consider * it relative to the sink's current volume, never as absolute * device volume. If this is not specified the volume will be * consider absolute when the sink is in flat volume mode, * relative otherwise. \since 0.9.20 */ PA_STREAM_PASSTHROUGH = 0x80000U /**< Used to tag content that will be rendered by passthrough sinks. * The data will be left as is and not reformatted, resampled. * \since 1.0 */ } pa_stream_flags_t; /** \cond fulldocs */ /* English is an evil language */ #define PA_STREAM_NOT_MONOTONOUS PA_STREAM_NOT_MONOTONIC /* Allow clients to check with #ifdef for those flags */ #define PA_STREAM_START_CORKED PA_STREAM_START_CORKED #define PA_STREAM_INTERPOLATE_TIMING PA_STREAM_INTERPOLATE_TIMING #define PA_STREAM_NOT_MONOTONIC PA_STREAM_NOT_MONOTONIC #define PA_STREAM_AUTO_TIMING_UPDATE PA_STREAM_AUTO_TIMING_UPDATE #define PA_STREAM_NO_REMAP_CHANNELS PA_STREAM_NO_REMAP_CHANNELS #define PA_STREAM_NO_REMIX_CHANNELS PA_STREAM_NO_REMIX_CHANNELS #define PA_STREAM_FIX_FORMAT PA_STREAM_FIX_FORMAT #define PA_STREAM_FIX_RATE PA_STREAM_FIX_RATE #define PA_STREAM_FIX_CHANNELS PA_STREAM_FIX_CHANNELS #define PA_STREAM_DONT_MOVE PA_STREAM_DONT_MOVE #define PA_STREAM_VARIABLE_RATE PA_STREAM_VARIABLE_RATE #define PA_STREAM_PEAK_DETECT PA_STREAM_PEAK_DETECT #define PA_STREAM_START_MUTED PA_STREAM_START_MUTED #define PA_STREAM_ADJUST_LATENCY PA_STREAM_ADJUST_LATENCY #define PA_STREAM_EARLY_REQUESTS PA_STREAM_EARLY_REQUESTS #define PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND #define PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND #define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME #define PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH /** \endcond */ /** Playback and record buffer metrics */ typedef struct pa_buffer_attr { uint32_t maxlength; /**< Maximum length of the buffer in bytes. Setting this to (uint32_t) -1 * will initialize this to the maximum value supported by server, * which is recommended. * * In strict low-latency playback scenarios you might want to set this to * a lower value, likely together with the PA_STREAM_ADJUST_LATENCY flag. * If you do so, you ensure that the latency doesn't grow beyond what is * acceptable for the use case, at the cost of getting more underruns if * the latency is lower than what the server can reliably handle. */ uint32_t tlength; /**< Playback only: target length of the buffer. The server tries * to assure that at least tlength bytes are always available in * the per-stream server-side playback buffer. It is recommended * to set this to (uint32_t) -1, which will initialize this to a * value that is deemed sensible by the server. However, this * value will default to something like 2s, i.e. for applications * that have specific latency requirements this value should be * set to the maximum latency that the application can deal * with. When PA_STREAM_ADJUST_LATENCY is not set this value will * influence only the per-stream playback buffer size. When * PA_STREAM_ADJUST_LATENCY is set the overall latency of the sink * plus the playback buffer size is configured to this value. Set * PA_STREAM_ADJUST_LATENCY if you are interested in adjusting the * overall latency. Don't set it if you are interested in * configuring the server-side per-stream playback buffer * size. */ uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with * playback before at least prebuf bytes are available in the * buffer. It is recommended to set this to (uint32_t) -1, which * will initialize this to the same value as tlength, whatever * that may be. Initialize to 0 to enable manual start/stop * control of the stream. This means that playback will not stop * on underrun and playback will not start automatically. Instead * pa_stream_cork() needs to be called explicitly. If you set * this value to 0 you should also set PA_STREAM_START_CORKED. */ uint32_t minreq; /**< Playback only: minimum request. The server does not request * less than minreq bytes from the client, instead waits until the * buffer is free enough to request more bytes at once. It is * recommended to set this to (uint32_t) -1, which will initialize * this to a value that is deemed sensible by the server. This * should be set to a value that gives PulseAudio enough time to * move the data from the per-stream playback buffer into the * hardware playback buffer. */ uint32_t fragsize; /**< Recording only: fragment size. The server sends data in * blocks of fragsize bytes size. Large values diminish * interactivity with other operations on the connection context * but decrease control overhead. It is recommended to set this to * (uint32_t) -1, which will initialize this to a value that is * deemed sensible by the server. However, this value will default * to something like 2s, i.e. for applications that have specific * latency requirements this value should be set to the maximum * latency that the application can deal with. If * PA_STREAM_ADJUST_LATENCY is set the overall source latency will * be adjusted according to this value. If it is not set the * source latency is left unmodified. */ } pa_buffer_attr; /** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ typedef enum pa_error_code { PA_OK = 0, /**< No error */ PA_ERR_ACCESS, /**< Access failure */ PA_ERR_COMMAND, /**< Unknown command */ PA_ERR_INVALID, /**< Invalid argument */ PA_ERR_EXIST, /**< Entity exists */ PA_ERR_NOENTITY, /**< No such entity */ PA_ERR_CONNECTIONREFUSED, /**< Connection refused */ PA_ERR_PROTOCOL, /**< Protocol error */ PA_ERR_TIMEOUT, /**< Timeout */ PA_ERR_AUTHKEY, /**< No authorization key */ PA_ERR_INTERNAL, /**< Internal error */ PA_ERR_CONNECTIONTERMINATED, /**< Connection terminated */ PA_ERR_KILLED, /**< Entity killed */ PA_ERR_INVALIDSERVER, /**< Invalid server */ PA_ERR_MODINITFAILED, /**< Module initialization failed */ PA_ERR_BADSTATE, /**< Bad state */ PA_ERR_NODATA, /**< No data */ PA_ERR_VERSION, /**< Incompatible protocol version */ PA_ERR_TOOLARGE, /**< Data too large */ PA_ERR_NOTSUPPORTED, /**< Operation not supported \since 0.9.5 */ PA_ERR_UNKNOWN, /**< The error code was unknown to the client */ PA_ERR_NOEXTENSION, /**< Extension does not exist. \since 0.9.12 */ PA_ERR_OBSOLETE, /**< Obsolete functionality. \since 0.9.15 */ PA_ERR_NOTIMPLEMENTED, /**< Missing implementation. \since 0.9.15 */ PA_ERR_FORKED, /**< The caller forked without calling execve() and tried to reuse the context. \since 0.9.15 */ PA_ERR_IO, /**< An IO error happened. \since 0.9.16 */ PA_ERR_BUSY, /**< Device or resource busy. \since 0.9.17 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ } pa_error_code_t; /** \cond fulldocs */ #define PA_OK PA_OK #define PA_ERR_ACCESS PA_ERR_ACCESS #define PA_ERR_COMMAND PA_ERR_COMMAND #define PA_ERR_INVALID PA_ERR_INVALID #define PA_ERR_EXIST PA_ERR_EXIST #define PA_ERR_NOENTITY PA_ERR_NOENTITY #define PA_ERR_CONNECTIONREFUSED PA_ERR_CONNECTIONREFUSED #define PA_ERR_PROTOCOL PA_ERR_PROTOCOL #define PA_ERR_TIMEOUT PA_ERR_TIMEOUT #define PA_ERR_AUTHKEY PA_ERR_AUTHKEY #define PA_ERR_INTERNAL PA_ERR_INTERNAL #define PA_ERR_CONNECTIONTERMINATED PA_ERR_CONNECTIONTERMINATED #define PA_ERR_KILLED PA_ERR_KILLED #define PA_ERR_INVALIDSERVER PA_ERR_INVALIDSERVER #define PA_ERR_MODINITFAILED PA_ERR_MODINITFAILED #define PA_ERR_BADSTATE PA_ERR_BADSTATE #define PA_ERR_NODATA PA_ERR_NODATA #define PA_ERR_VERSION PA_ERR_VERSION #define PA_ERR_TOOLARGE PA_ERR_TOOLARGE #define PA_ERR_NOTSUPPORTED PA_ERR_NOTSUPPORTED #define PA_ERR_UNKNOWN PA_ERR_UNKNOWN #define PA_ERR_NOEXTENSION PA_ERR_NOEXTENSION #define PA_ERR_OBSOLETE PA_ERR_OBSOLETE #define PA_ERR_NOTIMPLEMENTED PA_ERR_NOTIMPLEMENTED #define PA_ERR_FORKED PA_ERR_FORKED #define PA_ERR_MAX PA_ERR_MAX /** \endcond */ /** Subscription event mask, as used by pa_context_subscribe() */ typedef enum pa_subscription_mask { PA_SUBSCRIPTION_MASK_NULL = 0x0000U, /**< No events */ PA_SUBSCRIPTION_MASK_SINK = 0x0001U, /**< Sink events */ PA_SUBSCRIPTION_MASK_SOURCE = 0x0002U, /**< Source events */ PA_SUBSCRIPTION_MASK_SINK_INPUT = 0x0004U, /**< Sink input events */ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 0x0008U, /**< Source output events */ PA_SUBSCRIPTION_MASK_MODULE = 0x0010U, /**< Module events */ PA_SUBSCRIPTION_MASK_CLIENT = 0x0020U, /**< Client events */ PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 0x0040U, /**< Sample cache events */ PA_SUBSCRIPTION_MASK_SERVER = 0x0080U, /**< Other global server changes. */ /** \cond fulldocs */ PA_SUBSCRIPTION_MASK_AUTOLOAD = 0x0100U, /**< \deprecated Autoload table events. */ /** \endcond */ PA_SUBSCRIPTION_MASK_CARD = 0x0200U, /**< Card events. \since 0.9.15 */ PA_SUBSCRIPTION_MASK_ALL = 0x02ffU /**< Catch all events */ } pa_subscription_mask_t; /** Subscription event types, as used by pa_context_subscribe() */ typedef enum pa_subscription_event_type { PA_SUBSCRIPTION_EVENT_SINK = 0x0000U, /**< Event type: Sink */ PA_SUBSCRIPTION_EVENT_SOURCE = 0x0001U, /**< Event type: Source */ PA_SUBSCRIPTION_EVENT_SINK_INPUT = 0x0002U, /**< Event type: Sink input */ PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 0x0003U, /**< Event type: Source output */ PA_SUBSCRIPTION_EVENT_MODULE = 0x0004U, /**< Event type: Module */ PA_SUBSCRIPTION_EVENT_CLIENT = 0x0005U, /**< Event type: Client */ PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 0x0006U, /**< Event type: Sample cache item */ PA_SUBSCRIPTION_EVENT_SERVER = 0x0007U, /**< Event type: Global server change, only occurring with PA_SUBSCRIPTION_EVENT_CHANGE. */ /** \cond fulldocs */ PA_SUBSCRIPTION_EVENT_AUTOLOAD = 0x0008U, /**< \deprecated Event type: Autoload table changes. */ /** \endcond */ PA_SUBSCRIPTION_EVENT_CARD = 0x0009U, /**< Event type: Card \since 0.9.15 */ PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 0x000FU, /**< A mask to extract the event type from an event value */ PA_SUBSCRIPTION_EVENT_NEW = 0x0000U, /**< A new object was created */ PA_SUBSCRIPTION_EVENT_CHANGE = 0x0010U, /**< A property of the object was modified */ PA_SUBSCRIPTION_EVENT_REMOVE = 0x0020U, /**< An object was removed */ PA_SUBSCRIPTION_EVENT_TYPE_MASK = 0x0030U /**< A mask to extract the event operation from an event value */ } pa_subscription_event_type_t; /** Return one if an event type t matches an event mask bitfield */ #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) /** \cond fulldocs */ #define PA_SUBSCRIPTION_MASK_NULL PA_SUBSCRIPTION_MASK_NULL #define PA_SUBSCRIPTION_MASK_SINK PA_SUBSCRIPTION_MASK_SINK #define PA_SUBSCRIPTION_MASK_SOURCE PA_SUBSCRIPTION_MASK_SOURCE #define PA_SUBSCRIPTION_MASK_SINK_INPUT PA_SUBSCRIPTION_MASK_SINK_INPUT #define PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT #define PA_SUBSCRIPTION_MASK_MODULE PA_SUBSCRIPTION_MASK_MODULE #define PA_SUBSCRIPTION_MASK_CLIENT PA_SUBSCRIPTION_MASK_CLIENT #define PA_SUBSCRIPTION_MASK_SAMPLE_CACHE PA_SUBSCRIPTION_MASK_SAMPLE_CACHE #define PA_SUBSCRIPTION_MASK_SERVER PA_SUBSCRIPTION_MASK_SERVER #define PA_SUBSCRIPTION_MASK_AUTOLOAD PA_SUBSCRIPTION_MASK_AUTOLOAD #define PA_SUBSCRIPTION_MASK_CARD PA_SUBSCRIPTION_MASK_CARD #define PA_SUBSCRIPTION_MASK_ALL PA_SUBSCRIPTION_MASK_ALL #define PA_SUBSCRIPTION_EVENT_SINK PA_SUBSCRIPTION_EVENT_SINK #define PA_SUBSCRIPTION_EVENT_SOURCE PA_SUBSCRIPTION_EVENT_SOURCE #define PA_SUBSCRIPTION_EVENT_SINK_INPUT PA_SUBSCRIPTION_EVENT_SINK_INPUT #define PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT #define PA_SUBSCRIPTION_EVENT_MODULE PA_SUBSCRIPTION_EVENT_MODULE #define PA_SUBSCRIPTION_EVENT_CLIENT PA_SUBSCRIPTION_EVENT_CLIENT #define PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE #define PA_SUBSCRIPTION_EVENT_SERVER PA_SUBSCRIPTION_EVENT_SERVER #define PA_SUBSCRIPTION_EVENT_AUTOLOAD PA_SUBSCRIPTION_EVENT_AUTOLOAD #define PA_SUBSCRIPTION_EVENT_CARD PA_SUBSCRIPTION_EVENT_CARD #define PA_SUBSCRIPTION_EVENT_FACILITY_MASK PA_SUBSCRIPTION_EVENT_FACILITY_MASK #define PA_SUBSCRIPTION_EVENT_NEW PA_SUBSCRIPTION_EVENT_NEW #define PA_SUBSCRIPTION_EVENT_CHANGE PA_SUBSCRIPTION_EVENT_CHANGE #define PA_SUBSCRIPTION_EVENT_REMOVE PA_SUBSCRIPTION_EVENT_REMOVE #define PA_SUBSCRIPTION_EVENT_TYPE_MASK PA_SUBSCRIPTION_EVENT_TYPE_MASK /** \endcond */ /** A structure for all kinds of timing information of a stream. See * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The * total output latency a sample that is written with * pa_stream_write() takes to be played may be estimated by * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined * as pa_bytes_to_usec(write_index-read_index)) The output buffer * which buffer_usec relates to may be manipulated freely (with * pa_stream_write()'s seek argument, pa_stream_flush() and friends), * the buffers sink_usec and source_usec relate to are first-in * first-out (FIFO) buffers which cannot be flushed or manipulated in * any way. The total input latency a sample that is recorded takes to * be delivered to the application is: * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of * sign issues!) When connected to a monitor source sink_usec contains * the latency of the owning sink. The two latency estimations * described here are implemented in pa_stream_get_latency(). Please * note that this structure can be extended as part of evolutionary * API updates at any time in any new release.*/ typedef struct pa_timing_info { struct timeval timestamp; /**< The time when this timing info structure was current */ int synchronized_clocks; /**< Non-zero if the local and the remote machine have * synchronized clocks. If synchronized clocks are detected * transport_usec becomes much more reliable. However, the code * that detects synchronized clocks is very limited and unreliable * itself. */ pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For * playback streams and record streams connected to a monitor * source. */ pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being * delivered to the application. Only for record streams. */ pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred * to/from the daemon. For both playback and record streams. */ int playing; /**< Non-zero when the stream is currently not underrun and data * is being passed on to the device. Only for playback * streams. This field does not say whether the data is actually * already being played. To determine this check whether * since_underrun (converted to usec) is larger than sink_usec.*/ int write_index_corrupt; /**< Non-zero if write_index is not up-to-date because a local * write command that corrupted it has been issued in the time * since this latency info was current . Only write commands with * SEEK_RELATIVE_ON_READ and SEEK_RELATIVE_END can corrupt * write_index. */ int64_t write_index; /**< Current write index into the playback buffer in bytes. Think * twice before using this for seeking purposes: it might be out * of date a the time you want to use it. Consider using * PA_SEEK_RELATIVE instead. */ int read_index_corrupt; /**< Non-zero if read_index is not up-to-date because a local * pause or flush request that corrupted it has been issued in the * time since this latency info was current. */ int64_t read_index; /**< Current read index into the playback buffer in bytes. Think * twice before using this for seeking purposes: it might be out * of date a the time you want to use it. Consider using * PA_SEEK_RELATIVE_ON_READ instead. */ pa_usec_t configured_sink_usec; /**< The configured latency for the sink. \since 0.9.11 */ pa_usec_t configured_source_usec; /**< The configured latency for the source. \since 0.9.11 */ int64_t since_underrun; /**< Bytes that were handed to the sink since the last underrun * happened, or since playback started again after the last * underrun. playing will tell you which case it is. \since * 0.9.11 */ } pa_timing_info; /** A structure for the spawn api. This may be used to integrate auto * spawned daemons into your application. For more information see * pa_context_connect(). When spawning a new child process the * waitpid() is used on the child's PID. The spawn routine will not * block or ignore SIGCHLD signals, since this cannot be done in a * thread compatible way. You might have to do this in * prefork/postfork. */ typedef struct pa_spawn_api { void (*prefork)(void); /**< Is called just before the fork in the parent process. May be * NULL. */ void (*postfork)(void); /**< Is called immediately after the fork in the parent * process. May be NULL.*/ void (*atfork)(void); /**< Is called immediately after the fork in the child * process. May be NULL. It is not safe to close all file * descriptors in this function unconditionally, since a UNIX * socket (created using socketpair()) is passed to the new * process. */ } pa_spawn_api; /** Seek type for pa_stream_write(). */ typedef enum pa_seek_mode { PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */ } pa_seek_mode_t; /** \cond fulldocs */ #define PA_SEEK_RELATIVE PA_SEEK_RELATIVE #define PA_SEEK_ABSOLUTE PA_SEEK_ABSOLUTE #define PA_SEEK_RELATIVE_ON_READ PA_SEEK_RELATIVE_ON_READ #define PA_SEEK_RELATIVE_END PA_SEEK_RELATIVE_END /** \endcond */ /** Special sink flags. */ typedef enum pa_sink_flags { PA_SINK_NOFLAGS = 0x0000U, /**< Flag to pass when no specific options are needed (used to avoid casting) \since 0.9.19 */ PA_SINK_HW_VOLUME_CTRL = 0x0001U, /**< Supports hardware volume control. This is a dynamic flag and may * change at runtime after the sink has initialized */ PA_SINK_LATENCY = 0x0002U, /**< Supports latency querying */ PA_SINK_HARDWARE = 0x0004U, /**< Is a hardware sink of some kind, in contrast to * "virtual"/software sinks \since 0.9.3 */ PA_SINK_NETWORK = 0x0008U, /**< Is a networked sink of some kind. \since 0.9.7 */ PA_SINK_HW_MUTE_CTRL = 0x0010U, /**< Supports hardware mute control. This is a dynamic flag and may * change at runtime after the sink has initialized \since 0.9.11 */ PA_SINK_DECIBEL_VOLUME = 0x0020U, /**< Volume can be translated to dB with pa_sw_volume_to_dB(). This is a * dynamic flag and may change at runtime after the sink has initialized * \since 0.9.11 */ PA_SINK_FLAT_VOLUME = 0x0040U, /**< This sink is in flat volume mode, i.e.\ always the maximum of * the volume of all connected inputs. \since 0.9.15 */ PA_SINK_DYNAMIC_LATENCY = 0x0080U, /**< The latency can be adjusted dynamically depending on the * needs of the connected streams. \since 0.9.15 */ PA_SINK_SET_FORMATS = 0x0100U, /**< The sink allows setting what formats are supported by the connected * hardware. The actual functionality to do this might be provided by an * extension. \since 1.0 */ #ifdef __INCLUDED_FROM_PULSE_AUDIO /** \cond fulldocs */ /* PRIVATE: Server-side values -- do not try to use these at client-side. * The server will filter out these flags anyway, so you should never see * these flags in sinks. */ PA_SINK_SHARE_VOLUME_WITH_MASTER = 0x1000000U, /**< This sink shares the volume with the master sink (used by some filter * sinks). */ PA_SINK_DEFERRED_VOLUME = 0x2000000U, /**< The HW volume changes are syncronized with SW volume. */ /** \endcond */ #endif } pa_sink_flags_t; /** \cond fulldocs */ #define PA_SINK_HW_VOLUME_CTRL PA_SINK_HW_VOLUME_CTRL #define PA_SINK_LATENCY PA_SINK_LATENCY #define PA_SINK_HARDWARE PA_SINK_HARDWARE #define PA_SINK_NETWORK PA_SINK_NETWORK #define PA_SINK_HW_MUTE_CTRL PA_SINK_HW_MUTE_CTRL #define PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME #define PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME #define PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY #define PA_SINK_SET_FORMATS PA_SINK_SET_FORMATS #ifdef __INCLUDED_FROM_PULSE_AUDIO #define PA_SINK_CLIENT_FLAGS_MASK 0xFFFFFF #endif /** \endcond */ /** Sink state. \since 0.9.15 */ typedef enum pa_sink_state { /* enum serialized in u8 */ PA_SINK_INVALID_STATE = -1, /**< This state is used when the server does not support sink state introspection \since 0.9.15 */ PA_SINK_RUNNING = 0, /**< Running, sink is playing and used by at least one non-corked sink-input \since 0.9.15 */ PA_SINK_IDLE = 1, /**< When idle, the sink is playing but there is no non-corked sink-input attached to it \since 0.9.15 */ PA_SINK_SUSPENDED = 2, /**< When suspended, actual sink access can be closed, for instance \since 0.9.15 */ /** \cond fulldocs */ /* PRIVATE: Server-side values -- DO NOT USE THIS ON THE CLIENT * SIDE! These values are *not* considered part of the official PA * API/ABI. If you use them your application might break when PA * is upgraded. Also, please note that these values are not useful * on the client side anyway. */ PA_SINK_INIT = -2, /**< Initialization state */ PA_SINK_UNLINKED = -3 /**< The state when the sink is getting unregistered and removed from client access */ /** \endcond */ } pa_sink_state_t; /** Returns non-zero if sink is playing: running or idle. \since 0.9.15 */ static inline int PA_SINK_IS_OPENED(pa_sink_state_t x) { return x == PA_SINK_RUNNING || x == PA_SINK_IDLE; } /** Returns non-zero if sink is running. \since 1.0 */ static inline int PA_SINK_IS_RUNNING(pa_sink_state_t x) { return x == PA_SINK_RUNNING; } /** \cond fulldocs */ #define PA_SINK_INVALID_STATE PA_SINK_INVALID_STATE #define PA_SINK_RUNNING PA_SINK_RUNNING #define PA_SINK_IDLE PA_SINK_IDLE #define PA_SINK_SUSPENDED PA_SINK_SUSPENDED #define PA_SINK_INIT PA_SINK_INIT #define PA_SINK_UNLINKED PA_SINK_UNLINKED #define PA_SINK_IS_OPENED PA_SINK_IS_OPENED /** \endcond */ /** Special source flags. */ typedef enum pa_source_flags { PA_SOURCE_NOFLAGS = 0x0000U, /**< Flag to pass when no specific options are needed (used to avoid casting) \since 0.9.19 */ PA_SOURCE_HW_VOLUME_CTRL = 0x0001U, /**< Supports hardware volume control. This is a dynamic flag and may * change at runtime after the source has initialized */ PA_SOURCE_LATENCY = 0x0002U, /**< Supports latency querying */ PA_SOURCE_HARDWARE = 0x0004U, /**< Is a hardware source of some kind, in contrast to * "virtual"/software source \since 0.9.3 */ PA_SOURCE_NETWORK = 0x0008U, /**< Is a networked source of some kind. \since 0.9.7 */ PA_SOURCE_HW_MUTE_CTRL = 0x0010U, /**< Supports hardware mute control. This is a dynamic flag and may * change at runtime after the source has initialized \since 0.9.11 */ PA_SOURCE_DECIBEL_VOLUME = 0x0020U, /**< Volume can be translated to dB with pa_sw_volume_to_dB(). This is a * dynamic flag and may change at runtime after the source has initialized * \since 0.9.11 */ PA_SOURCE_DYNAMIC_LATENCY = 0x0040U, /**< The latency can be adjusted dynamically depending on the * needs of the connected streams. \since 0.9.15 */ PA_SOURCE_FLAT_VOLUME = 0x0080U, /**< This source is in flat volume mode, i.e.\ always the maximum of * the volume of all connected outputs. \since 1.0 */ #ifdef __INCLUDED_FROM_PULSE_AUDIO /** \cond fulldocs */ /* PRIVATE: Server-side values -- do not try to use these at client-side. * The server will filter out these flags anyway, so you should never see * these flags in sources. */ PA_SOURCE_SHARE_VOLUME_WITH_MASTER = 0x1000000U, /**< This source shares the volume with the master source (used by some filter * sources). */ PA_SOURCE_DEFERRED_VOLUME = 0x2000000U, /**< The HW volume changes are syncronized with SW volume. */ #endif } pa_source_flags_t; /** \cond fulldocs */ #define PA_SOURCE_HW_VOLUME_CTRL PA_SOURCE_HW_VOLUME_CTRL #define PA_SOURCE_LATENCY PA_SOURCE_LATENCY #define PA_SOURCE_HARDWARE PA_SOURCE_HARDWARE #define PA_SOURCE_NETWORK PA_SOURCE_NETWORK #define PA_SOURCE_HW_MUTE_CTRL PA_SOURCE_HW_MUTE_CTRL #define PA_SOURCE_DECIBEL_VOLUME PA_SOURCE_DECIBEL_VOLUME #define PA_SOURCE_DYNAMIC_LATENCY PA_SOURCE_DYNAMIC_LATENCY #define PA_SOURCE_FLAT_VOLUME PA_SOURCE_FLAT_VOLUME #ifdef __INCLUDED_FROM_PULSE_AUDIO #define PA_SOURCE_CLIENT_FLAGS_MASK 0xFFFFFF #endif /** \endcond */ /** Source state. \since 0.9.15 */ typedef enum pa_source_state { PA_SOURCE_INVALID_STATE = -1, /**< This state is used when the server does not support source state introspection \since 0.9.15 */ PA_SOURCE_RUNNING = 0, /**< Running, source is recording and used by at least one non-corked source-output \since 0.9.15 */ PA_SOURCE_IDLE = 1, /**< When idle, the source is still recording but there is no non-corked source-output \since 0.9.15 */ PA_SOURCE_SUSPENDED = 2, /**< When suspended, actual source access can be closed, for instance \since 0.9.15 */ /** \cond fulldocs */ /* PRIVATE: Server-side values -- DO NOT USE THIS ON THE CLIENT * SIDE! These values are *not* considered part of the official PA * API/ABI. If you use them your application might break when PA * is upgraded. Also, please note that these values are not useful * on the client side anyway. */ PA_SOURCE_INIT = -2, /**< Initialization state */ PA_SOURCE_UNLINKED = -3 /**< The state when the source is getting unregistered and removed from client access */ /** \endcond */ } pa_source_state_t; /** Returns non-zero if source is recording: running or idle. \since 0.9.15 */ static inline int PA_SOURCE_IS_OPENED(pa_source_state_t x) { return x == PA_SOURCE_RUNNING || x == PA_SOURCE_IDLE; } /** Returns non-zero if source is running \since 1.0 */ static inline int PA_SOURCE_IS_RUNNING(pa_source_state_t x) { return x == PA_SOURCE_RUNNING; } /** \cond fulldocs */ #define PA_SOURCE_INVALID_STATE PA_SOURCE_INVALID_STATE #define PA_SOURCE_RUNNING PA_SOURCE_RUNNING #define PA_SOURCE_IDLE PA_SOURCE_IDLE #define PA_SOURCE_SUSPENDED PA_SOURCE_SUSPENDED #define PA_SOURCE_INIT PA_SOURCE_INIT #define PA_SOURCE_UNLINKED PA_SOURCE_UNLINKED #define PA_SOURCE_IS_OPENED PA_SOURCE_IS_OPENED /** \endcond */ /** A generic free() like callback prototype */ typedef void (*pa_free_cb_t)(void *p); /** A stream policy/meta event requesting that an application should * cork a specific stream. See pa_stream_event_cb_t for more * information. \since 0.9.15 */ #define PA_STREAM_EVENT_REQUEST_CORK "request-cork" /** A stream policy/meta event requesting that an application should * cork a specific stream. See pa_stream_event_cb_t for more * information, \since 0.9.15 */ #define PA_STREAM_EVENT_REQUEST_UNCORK "request-uncork" /** A stream event notifying that the stream is going to be * disconnected because the underlying sink changed and no longer * supports the format that was originally negotiated. Clients need * to connect a new stream to renegotiate a format and continue * playback. \since 1.0 */ #define PA_STREAM_EVENT_FORMAT_LOST "format-lost" #ifndef __INCLUDED_FROM_PULSE_AUDIO /** Port availability / jack detection status * \since 2.0 */ typedef enum pa_port_available { PA_PORT_AVAILABLE_UNKNOWN = 0, /**< This port does not support jack detection \since 2.0 */ PA_PORT_AVAILABLE_NO = 1, /**< This port is not available, likely because the jack is not plugged in. \since 2.0 */ PA_PORT_AVAILABLE_YES = 2, /**< This port is available, likely because the jack is plugged in. \since 2.0 */ } pa_port_available_t; /** \cond fulldocs */ #define PA_PORT_AVAILABLE_UNKNOWN PA_PORT_AVAILABLE_UNKNOWN #define PA_PORT_AVAILABLE_NO PA_PORT_AVAILABLE_NO #define PA_PORT_AVAILABLE_YES PA_PORT_AVAILABLE_YES /** \endcond */ #endif PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/error.h000066400000000000000000000021751364710014100230540ustar00rootroot00000000000000#ifndef fooerrorhfoo #define fooerrorhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include /** \file * Error management */ PA_C_DECL_BEGIN /** Return a human readable error message for the specified numeric error code */ const char* pa_strerror(int error); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/ext-device-manager.h000066400000000000000000000107551364710014100253730ustar00rootroot00000000000000#ifndef foopulseextdevicemanagerhfoo #define foopulseextdevicemanagerhfoo /*** This file is part of PulseAudio. Copyright 2008 Lennart Poettering Copyright 2009 Colin Guthrie PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include /** \file * * Routines for controlling module-device-manager */ PA_C_DECL_BEGIN typedef struct pa_ext_device_manager_role_priority_info { const char *role; uint32_t priority; } pa_ext_device_manager_role_priority_info; /** Stores information about one device in the device database that is * maintained by module-device-manager. \since 0.9.21 */ typedef struct pa_ext_device_manager_info { const char *name; /**< Identifier string of the device. A string like "sink:" or similar followed by the name of the device. */ const char *description; /**< The description of the device when it was last seen, if applicable and saved */ const char *icon; /**< The icon given to the device */ uint32_t index; /**< The device index if it is currently available or PA_INVALID_INDEX */ uint32_t n_role_priorities; /**< How many role priorities do we have? */ pa_ext_device_manager_role_priority_info *role_priorities; /**< An array of role priority structures or NULL */ } pa_ext_device_manager_info; /** Callback prototype for pa_ext_device_manager_test(). \since 0.9.21 */ typedef void (*pa_ext_device_manager_test_cb_t)( pa_context *c, uint32_t version, void *userdata); /** Test if this extension module is available in the server. \since 0.9.21 */ pa_operation *pa_ext_device_manager_test( pa_context *c, pa_ext_device_manager_test_cb_t cb, void *userdata); /** Callback prototype for pa_ext_device_manager_read(). \since 0.9.21 */ typedef void (*pa_ext_device_manager_read_cb_t)( pa_context *c, const pa_ext_device_manager_info *info, int eol, void *userdata); /** Read all entries from the device database. \since 0.9.21 */ pa_operation *pa_ext_device_manager_read( pa_context *c, pa_ext_device_manager_read_cb_t cb, void *userdata); /** Sets the description for a device. \since 0.9.21 */ pa_operation *pa_ext_device_manager_set_device_description( pa_context *c, const char* device, const char* description, pa_context_success_cb_t cb, void *userdata); /** Delete entries from the device database. \since 0.9.21 */ pa_operation *pa_ext_device_manager_delete( pa_context *c, const char *const s[], pa_context_success_cb_t cb, void *userdata); /** Enable the role-based device-priority routing mode. \since 0.9.21 */ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata); /** Prefer a given device in the priority list. \since 0.9.21 */ pa_operation *pa_ext_device_manager_reorder_devices_for_role( pa_context *c, const char* role, const char** devices, pa_context_success_cb_t cb, void *userdata); /** Subscribe to changes in the device database. \since 0.9.21 */ pa_operation *pa_ext_device_manager_subscribe( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata); /** Callback prototype for pa_ext_device_manager_set_subscribe_cb(). \since 0.9.21 */ typedef void (*pa_ext_device_manager_subscribe_cb_t)( pa_context *c, void *userdata); /** Set the subscription callback that is called when * pa_ext_device_manager_subscribe() was called. \since 0.9.21 */ void pa_ext_device_manager_set_subscribe_cb( pa_context *c, pa_ext_device_manager_subscribe_cb_t cb, void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/ext-device-restore.h000066400000000000000000000073001364710014100254340ustar00rootroot00000000000000#ifndef foopulseextdevicerestorehfoo #define foopulseextdevicerestorehfoo /*** This file is part of PulseAudio. Copyright 2008 Lennart Poettering Copyright 2011 Colin Guthrie PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include /** \file * * Routines for controlling module-device-restore */ PA_C_DECL_BEGIN /** Stores information about one device in the device database that is * maintained by module-device-manager. \since 1.0 */ typedef struct pa_ext_device_restore_info { pa_device_type_t type; /**< Device type sink or source? */ uint32_t index; /**< The device index */ uint8_t n_formats; /**< How many formats do we have? */ pa_format_info **formats; /**< An array of formats (may be NULL if n_formats == 0) */ } pa_ext_device_restore_info; /** Callback prototype for pa_ext_device_restore_test(). \since 1.0 */ typedef void (*pa_ext_device_restore_test_cb_t)( pa_context *c, uint32_t version, void *userdata); /** Test if this extension module is available in the server. \since 1.0 */ pa_operation *pa_ext_device_restore_test( pa_context *c, pa_ext_device_restore_test_cb_t cb, void *userdata); /** Subscribe to changes in the device database. \since 1.0 */ pa_operation *pa_ext_device_restore_subscribe( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata); /** Callback prototype for pa_ext_device_restore_set_subscribe_cb(). \since 1.0 */ typedef void (*pa_ext_device_restore_subscribe_cb_t)( pa_context *c, pa_device_type_t type, uint32_t idx, void *userdata); /** Set the subscription callback that is called when * pa_ext_device_restore_subscribe() was called. \since 1.0 */ void pa_ext_device_restore_set_subscribe_cb( pa_context *c, pa_ext_device_restore_subscribe_cb_t cb, void *userdata); /** Callback prototype for pa_ext_device_restore_read_formats(). \since 1.0 */ typedef void (*pa_ext_device_restore_read_device_formats_cb_t)( pa_context *c, const pa_ext_device_restore_info *info, int eol, void *userdata); /** Read the formats for all present devices from the device database. \since 1.0 */ pa_operation *pa_ext_device_restore_read_formats_all( pa_context *c, pa_ext_device_restore_read_device_formats_cb_t cb, void *userdata); /** Read an entry from the device database. \since 1.0 */ pa_operation *pa_ext_device_restore_read_formats( pa_context *c, pa_device_type_t type, uint32_t idx, pa_ext_device_restore_read_device_formats_cb_t cb, void *userdata); /** Read an entry from the device database. \since 1.0 */ pa_operation *pa_ext_device_restore_save_formats( pa_context *c, pa_device_type_t type, uint32_t idx, uint8_t n_formats, pa_format_info **formats, pa_context_success_cb_t cb, void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/ext-stream-restore.h000066400000000000000000000076171364710014100255030ustar00rootroot00000000000000#ifndef foopulseextstreamrestorehfoo #define foopulseextstreamrestorehfoo /*** This file is part of PulseAudio. Copyright 2008 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include /** \file * * Routines for controlling module-stream-restore */ PA_C_DECL_BEGIN /** Stores information about one entry in the stream database that is * maintained by module-stream-restore. \since 0.9.12 */ typedef struct pa_ext_stream_restore_info { const char *name; /**< Identifier string of the stream. A string like "sink-input-by-role:" or similar followed by some arbitrary property value. */ pa_channel_map channel_map; /**< The channel map for the volume field, if applicable */ pa_cvolume volume; /**< The volume of the stream when it was seen last, if applicable and saved */ const char *device; /**< The sink/source of the stream when it was last seen, if applicable and saved */ int mute; /**< The boolean mute state of the stream when it was last seen, if applicable and saved */ } pa_ext_stream_restore_info; /** Callback prototype for pa_ext_stream_restore_test(). \since 0.9.12 */ typedef void (*pa_ext_stream_restore_test_cb_t)( pa_context *c, uint32_t version, void *userdata); /** Test if this extension module is available in the server. \since 0.9.12 */ pa_operation *pa_ext_stream_restore_test( pa_context *c, pa_ext_stream_restore_test_cb_t cb, void *userdata); /** Callback prototype for pa_ext_stream_restore_read(). \since 0.9.12 */ typedef void (*pa_ext_stream_restore_read_cb_t)( pa_context *c, const pa_ext_stream_restore_info *info, int eol, void *userdata); /** Read all entries from the stream database. \since 0.9.12 */ pa_operation *pa_ext_stream_restore_read( pa_context *c, pa_ext_stream_restore_read_cb_t cb, void *userdata); /** Store entries in the stream database. \since 0.9.12 */ pa_operation *pa_ext_stream_restore_write( pa_context *c, pa_update_mode_t mode, const pa_ext_stream_restore_info data[], unsigned n, int apply_immediately, pa_context_success_cb_t cb, void *userdata); /** Delete entries from the stream database. \since 0.9.12 */ pa_operation *pa_ext_stream_restore_delete( pa_context *c, const char *const s[], pa_context_success_cb_t cb, void *userdata); /** Subscribe to changes in the stream database. \since 0.9.12 */ pa_operation *pa_ext_stream_restore_subscribe( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata); /** Callback prototype for pa_ext_stream_restore_set_subscribe_cb(). \since 0.9.12 */ typedef void (*pa_ext_stream_restore_subscribe_cb_t)( pa_context *c, void *userdata); /** Set the subscription callback that is called when * pa_ext_stream_restore_subscribe() was called. \since 0.9.12 */ void pa_ext_stream_restore_set_subscribe_cb( pa_context *c, pa_ext_stream_restore_subscribe_cb_t cb, void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/format.h000066400000000000000000000276041364710014100232170ustar00rootroot00000000000000#ifndef fooformathfoo #define fooformathfoo /*** This file is part of PulseAudio. Copyright 2011 Intel Corporation Copyright 2011 Collabora Multimedia Copyright 2011 Arun Raghavan PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include /** \file * Utility functions for handling a stream or sink format. */ PA_C_DECL_BEGIN /** Represents the type of encoding used in a stream or accepted by a sink. \since 1.0 */ typedef enum pa_encoding { PA_ENCODING_ANY, /**< Any encoding format, PCM or compressed */ PA_ENCODING_PCM, /**< Any PCM format */ PA_ENCODING_AC3_IEC61937, /**< AC3 data encapsulated in IEC 61937 header/padding */ PA_ENCODING_EAC3_IEC61937, /**< EAC3 data encapsulated in IEC 61937 header/padding */ PA_ENCODING_MPEG_IEC61937, /**< MPEG-1 or MPEG-2 (Part 3, not AAC) data encapsulated in IEC 61937 header/padding */ PA_ENCODING_DTS_IEC61937, /**< DTS data encapsulated in IEC 61937 header/padding */ PA_ENCODING_MPEG2_AAC_IEC61937, /**< MPEG-2 AAC data encapsulated in IEC 61937 header/padding. \since 4.0 */ PA_ENCODING_MAX, /**< Valid encoding types must be less than this value */ PA_ENCODING_INVALID = -1, /**< Represents an invalid encoding */ } pa_encoding_t; /** \cond fulldocs */ #define PA_ENCODING_ANY PA_ENCODING_ANY #define PA_ENCODING_PCM PA_ENCODING_PCM #define PA_ENCODING_AC3_IEC61937 PA_ENCODING_AC3_IEC61937 #define PA_ENCODING_EAC3_IEC61937 PA_ENCODING_EAC3_IEC61937 #define PA_ENCODING_MPEG_IEC61937 PA_ENCODING_MPEG_IEC61937 #define PA_ENCODING_DTS_IEC61937 PA_ENCODING_DTS_IEC61937 #define PA_ENCODING_MPEG2_AAC_IEC61937 PA_ENCODING_MPEG2_AAC_IEC61937 #define PA_ENCODING_MAX PA_ENCODING_MAX #define PA_ENCODING_INVALID PA_ENCODING_INVALID /** \endcond */ /** Returns a printable string representing the given encoding type. \since 1.0 */ const char *pa_encoding_to_string(pa_encoding_t e) PA_GCC_CONST; /** Converts a string of the form returned by \a pa_encoding_to_string() back to a \a pa_encoding_t. \since 1.0 */ pa_encoding_t pa_encoding_from_string(const char *encoding); /** Represents the format of data provided in a stream or processed by a sink. \since 1.0 */ typedef struct pa_format_info { pa_encoding_t encoding; /**< The encoding used for the format */ pa_proplist *plist; /**< Additional encoding-specific properties such as sample rate, bitrate, etc. */ } pa_format_info; /** Allocates a new \a pa_format_info structure. Clients must initialise at least the encoding field themselves. \since 1.0 */ pa_format_info* pa_format_info_new(void); /** Returns a new \a pa_format_info struct and representing the same format as \a src. \since 1.0 */ pa_format_info* pa_format_info_copy(const pa_format_info *src); /** Frees a \a pa_format_info structure. \since 1.0 */ void pa_format_info_free(pa_format_info *f); /** Returns non-zero when the format info structure is valid. \since 1.0 */ int pa_format_info_valid(const pa_format_info *f); /** Returns non-zero when the format info structure represents a PCM (i.e.\ uncompressed data) format. \since 1.0 */ int pa_format_info_is_pcm(const pa_format_info *f); /** Returns non-zero if the format represented by \a first is a subset of * the format represented by \a second. This means that \a second must * have all the fields that \a first does, but the reverse need not * be true. This is typically expected to be used to check if a * stream's format is compatible with a given sink. In such a case, * \a first would be the sink's format and \a second would be the * stream's. \since 1.0 */ int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second); /** Maximum required string length for * pa_format_info_snprint(). Please note that this value can change * with any release without warning and without being considered API * or ABI breakage. You should not use this definition anywhere where * it might become part of an ABI. \since 1.0 */ #define PA_FORMAT_INFO_SNPRINT_MAX 256 /** Return a human-readable string representing the given format. \since 1.0 */ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f); /** Parse a human-readable string of the form generated by * \a pa_format_info_snprint() into a pa_format_info structure. \since 1.0 */ pa_format_info* pa_format_info_from_string(const char *str); /** Utility function to take a \a pa_sample_spec and generate the corresponding * \a pa_format_info. * * Note that if you want the server to choose some of the stream parameters, * for example the sample rate, so that they match the device parameters, then * you shouldn't use this function. In order to allow the server to choose * a parameter value, that parameter must be left unspecified in the * pa_format_info object, and this function always specifies all parameters. An * exception is the channel map: if you pass NULL for the channel map, then the * channel map will be left unspecified, allowing the server to choose it. * * \since 2.0 */ pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map); /** Utility function to generate a \a pa_sample_spec and \a pa_channel_map corresponding to a given \a pa_format_info. The * conversion for PCM formats is straight-forward. For non-PCM formats, if there is a fixed size-time conversion (i.e. all * IEC61937-encapsulated formats), a "fake" sample spec whose size-time conversion corresponds to this format is provided and * the channel map argument is ignored. For formats with variable size-time conversion, this function will fail. Returns a * negative integer if conversion failed and 0 on success. \since 2.0 */ int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map); /** Represents the type of value type of a property on a \ref pa_format_info. \since 2.0 */ typedef enum pa_prop_type_t { PA_PROP_TYPE_INT, /**< Integer property */ PA_PROP_TYPE_INT_RANGE, /**< Integer range property */ PA_PROP_TYPE_INT_ARRAY, /**< Integer array property */ PA_PROP_TYPE_STRING, /**< String property */ PA_PROP_TYPE_STRING_ARRAY, /**< String array property */ PA_PROP_TYPE_INVALID = -1, /**< Represents an invalid type */ } pa_prop_type_t; /** \cond fulldocs */ #define PA_PROP_TYPE_INT PA_PROP_TYPE_INT #define PA_PROP_TYPE_INT_RANGE PA_PROP_TYPE_INT_RANGE #define PA_PROP_TYPE_INT_ARRAY PA_PROP_TYPE_INT_ARRAY #define PA_PROP_TYPE_STRING PA_PROP_TYPE_STRING #define PA_PROP_TYPE_STRING_ARRAY PA_PROP_TYPE_STRING_ARRAY #define PA_PROP_TYPE_INVALID PA_PROP_TYPE_INVALID /** \endcond */ /** Gets the type of property \a key in a given \ref pa_format_info. \since 2.0 */ pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key); /** Gets an integer property from the given format info. Returns 0 on success and a negative integer on failure. \since 2.0 */ int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v); /** Gets an integer range property from the given format info. Returns 0 on success and a negative integer on failure. * \since 2.0 */ int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max); /** Gets an integer array property from the given format info. \a values contains the values and \a n_values contains the * number of elements. The caller must free \a values using \ref pa_xfree. Returns 0 on success and a negative integer on * failure. \since 2.0 */ int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values); /** Gets a string property from the given format info. The caller must free the returned string using \ref pa_xfree. Returns * 0 on success and a negative integer on failure. \since 2.0 */ int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v); /** Gets a string array property from the given format info. \a values contains the values and \a n_values contains * the number of elements. The caller must free \a values using \ref pa_format_info_free_string_array. Returns 0 on success and * a negative integer on failure. \since 2.0 */ int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values); /** Frees a string array returned by \ref pa_format_info_get_prop_string_array. \since 2.0 */ void pa_format_info_free_string_array(char **values, int n_values); /** Sets an integer property on the given format info. \since 1.0 */ void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value); /** Sets a property with a list of integer values on the given format info. \since 1.0 */ void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values); /** Sets a property which can have any value in a given integer range on the given format info. \since 1.0 */ void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max); /** Sets a string property on the given format info. \since 1.0 */ void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value); /** Sets a property with a list of string values on the given format info. \since 1.0 */ void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values); /** Convenience method to set the sample format as a property on the given * format. * * Note for PCM: If the sample format is left unspecified in the pa_format_info * object, then the server will select the stream sample format. In that case * the stream sample format will most likely match the device sample format, * meaning that sample format conversion will be avoided. * * \since 1.0 */ void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf); /** Convenience method to set the sampling rate as a property on the given * format. * * Note for PCM: If the sample rate is left unspecified in the pa_format_info * object, then the server will select the stream sample rate. In that case the * stream sample rate will most likely match the device sample rate, meaning * that sample rate conversion will be avoided. * * \since 1.0 */ void pa_format_info_set_rate(pa_format_info *f, int rate); /** Convenience method to set the number of channels as a property on the given * format. * * Note for PCM: If the channel count is left unspecified in the pa_format_info * object, then the server will select the stream channel count. In that case * the stream channel count will most likely match the device channel count, * meaning that up/downmixing will be avoided. * * \since 1.0 */ void pa_format_info_set_channels(pa_format_info *f, int channels); /** Convenience method to set the channel map as a property on the given * format. * * Note for PCM: If the channel map is left unspecified in the pa_format_info * object, then the server will select the stream channel map. In that case the * stream channel map will most likely match the device channel map, meaning * that remixing will be avoided. * * \since 1.0 */ void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/gccmacro.h000066400000000000000000000071361364710014100235030ustar00rootroot00000000000000#ifndef foopulsegccmacrohfoo #define foopulsegccmacrohfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ /** \file * GCC attribute macros */ #if defined(__GNUC__) #ifdef __MINGW32__ /* libintl overrides printf with a #define. As this breaks this attribute, * it has a workaround. However the workaround isn't enabled for MINGW * builds (only cygwin) */ #define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (__printf__, a, b))) #else #define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) #endif #else /** If we're in GNU C, use some magic for detecting invalid format strings */ #define PA_GCC_PRINTF_ATTR(a,b) #endif #if defined(__GNUC__) && (__GNUC__ >= 4) #define PA_GCC_SENTINEL __attribute__ ((sentinel)) #else /** Macro for usage of GCC's sentinel compilation warnings */ #define PA_GCC_SENTINEL #endif #ifdef __GNUC__ #define PA_GCC_NORETURN __attribute__((noreturn)) #else /** Macro for no-return functions */ #define PA_GCC_NORETURN #endif #ifdef __GNUC__ #define PA_GCC_UNUSED __attribute__ ((unused)) #else /** Macro for not used function, variable or parameter */ #define PA_GCC_UNUSED #endif #ifdef __GNUC__ #define PA_GCC_DESTRUCTOR __attribute__ ((destructor)) #else /** Call this function when process terminates */ #define PA_GCC_DESTRUCTOR #endif #ifndef PA_GCC_PURE #ifdef __GNUC__ #define PA_GCC_PURE __attribute__ ((pure)) #else /** This function's return value depends only the arguments list and global state **/ #define PA_GCC_PURE #endif #endif #ifndef PA_GCC_CONST #ifdef __GNUC__ #define PA_GCC_CONST __attribute__ ((const)) #else /** This function's return value depends only the arguments list (stricter version of PA_GCC_PURE) **/ #define PA_GCC_CONST #endif #endif #ifndef PA_GCC_DEPRECATED #ifdef __GNUC__ #define PA_GCC_DEPRECATED __attribute__ ((deprecated)) #else /** This function is deprecated **/ #define PA_GCC_DEPRECATED #endif #endif #ifndef PA_GCC_PACKED #ifdef __GNUC__ #define PA_GCC_PACKED __attribute__ ((packed)) #else /** Structure shall be packed in memory **/ #define PA_GCC_PACKED #endif #endif #ifndef PA_GCC_ALLOC_SIZE #if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3) #define PA_GCC_ALLOC_SIZE(x) __attribute__ ((__alloc_size__(x))) #define PA_GCC_ALLOC_SIZE2(x,y) __attribute__ ((__alloc_size__(x,y))) #else /** Macro for usage of GCC's alloc_size attribute */ #define PA_GCC_ALLOC_SIZE(x) /** Macro for usage of GCC's alloc_size attribute */ #define PA_GCC_ALLOC_SIZE2(x,y) #endif #endif #ifndef PA_GCC_MALLOC #ifdef __GNUC__ #define PA_GCC_MALLOC __attribute__ ((malloc)) #else /** Macro for usage of GCC's malloc attribute */ #define PA_GCC_MALLOC #endif #endif #ifndef PA_GCC_WEAKREF #if defined(__GNUC__) && defined(__ELF__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ > 1)) || (__GNUC__ > 4)) /** Macro for usage of GCC's weakref attribute */ #define PA_GCC_WEAKREF(x) __attribute__((weakref(#x))) #endif #endif #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/glib-mainloop.h000066400000000000000000000041331364710014100244500ustar00rootroot00000000000000#ifndef fooglibmainloophfoo #define fooglibmainloophfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include /** \page glib-mainloop GLIB Main Loop Bindings * * \section overv_sec Overview * * The GLIB main loop bindings are extremely easy to use. All that is * required is to create a pa_glib_mainloop object using * pa_glib_mainloop_new(). When the main loop abstraction is needed, it is * provided by pa_glib_mainloop_get_api(). * */ /** \file * GLIB main loop support * * See also \subpage glib-mainloop */ PA_C_DECL_BEGIN /** An opaque GLIB main loop object */ typedef struct pa_glib_mainloop pa_glib_mainloop; /** Create a new GLIB main loop object for the specified GLIB main * loop context. Takes an argument c for the * GMainContext to use. If c is NULL the default context is used. */ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); /** Free the GLIB main loop object */ void pa_glib_mainloop_free(pa_glib_mainloop* g); /** Return the abstract main loop API vtable for the GLIB main loop object. No need to free the API as it is owned by the loop and is destroyed when the loop is freed. */ pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/introspect.h000066400000000000000000001222621364710014100241150ustar00rootroot00000000000000#ifndef foointrospecthfoo #define foointrospecthfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include #include #include #include #include /** \page introspect Server Query and Control * * \section overv_sec Overview * * Sometimes it is necessary to query and modify global settings in the * server. For this, PulseAudio has the introspection API. It can list sinks, * sources, samples and other aspects of the server. It can also modify the * attributes of the server that will affect operations on a global level, * and not just the application's context. * * \section query_sec Querying * * All querying is done through callbacks. This approach is necessary to * maintain an asynchronous design. The client will request the information * and some time later, the server will respond with the desired data. * * Some objects can have multiple instances on the server. When requesting all * of these at once, the callback will be called multiple times, once for * each object. When the list has been exhausted, the callback will be called * without an information structure and the eol parameter set to a positive * value. * * Note that even if a single object is requested, and not the entire list, * the terminating call will still be made. * * If an error occurs, the callback will be invoked without an information * structure and eol set to a negative value.. * * Data members in the information structures are only valid during the * duration of the callback. If they are required after the callback is * finished, a deep copy of the information structure must be performed. * * \subsection server_subsec Server Information * * The server can be queried about its name, the environment it's running on * and the currently active global defaults. Calling * pa_context_get_server_info() provides access to a pa_server_info structure * containing all of these. * * \subsection memstat_subsec Memory Usage * * Statistics about memory usage can be fetched using pa_context_stat(), * giving a pa_stat_info structure. * * \subsection sinksrc_subsec Sinks and Sources * * The server can have an arbitrary number of sinks and sources. Each sink * and source have both an index and a name associated with it. As such, * there are three ways to get access to them: * * \li By index - pa_context_get_sink_info_by_index() / * pa_context_get_source_info_by_index() * \li By name - pa_context_get_sink_info_by_name() / * pa_context_get_source_info_by_name() * \li All - pa_context_get_sink_info_list() / * pa_context_get_source_info_list() * * All three method use the same callback and will provide a pa_sink_info or * pa_source_info structure. * * \subsection siso_subsec Sink Inputs and Source Outputs * * Sink inputs and source outputs are the representations of the client ends * of streams inside the server. I.e. they connect a client stream to one of * the global sinks or sources. * * Sink inputs and source outputs only have an index to identify them. As * such, there are only two ways to get information about them: * * \li By index - pa_context_get_sink_input_info() / * pa_context_get_source_output_info() * \li All - pa_context_get_sink_input_info_list() / * pa_context_get_source_output_info_list() * * The structure returned is the pa_sink_input_info or pa_source_output_info * structure. * * \subsection samples_subsec Samples * * The list of cached samples can be retrieved from the server. Three methods * exist for querying the sample cache list: * * \li By index - pa_context_get_sample_info_by_index() * \li By name - pa_context_get_sample_info_by_name() * \li All - pa_context_get_sample_info_list() * * Note that this only retrieves information about the sample, not the sample * data itself. * * \subsection module_subsec Driver Modules * * PulseAudio driver modules are identified by index and are retrieved using either * pa_context_get_module_info() or pa_context_get_module_info_list(). The * information structure is called pa_module_info. * * \subsection client_subsec Clients * * PulseAudio clients are also identified by index and are retrieved using * either pa_context_get_client_info() or pa_context_get_client_info_list(). * The information structure is called pa_client_info. * * \section ctrl_sec Control * * Some parts of the server are only possible to read, but most can also be * modified in different ways. Note that these changes will affect all * connected clients and not just the one issuing the request. * * \subsection sinksrc_subsec Sinks and Sources * * The most common change one would want to apply to sinks and sources is to * modify the volume of the audio. Identically to how sinks and sources can * be queried, there are two ways of identifying them: * * \li By index - pa_context_set_sink_volume_by_index() / * pa_context_set_source_volume_by_index() * \li By name - pa_context_set_sink_volume_by_name() / * pa_context_set_source_volume_by_name() * * It is also possible to mute a sink or source: * * \li By index - pa_context_set_sink_mute_by_index() / * pa_context_set_source_mute_by_index() * \li By name - pa_context_set_sink_mute_by_name() / * pa_context_set_source_mute_by_name() * * \subsection siso_subsec Sink Inputs and Source Outputs * * If an application desires to modify the volume of just a single stream * (commonly one of its own streams), this can be done by setting the volume * of its associated sink input or source output, using * pa_context_set_sink_input_volume() or pa_context_set_source_output_volume(). * * It is also possible to remove sink inputs and source outputs, terminating * the streams associated with them: * * \li Sink input - pa_context_kill_sink_input() * \li Source output - pa_context_kill_source_output() * * It is strongly recommended that all volume changes are done as a direct * result of user input. With automated requests, such as those resulting * from misguided attempts of crossfading, PulseAudio can store the stream * volume at an inappropriate moment and restore it later. Besides, such * attempts lead to OSD popups in some desktop environments. * * As a special case of the general rule above, it is recommended that your * application leaves the task of saving and restoring the volume of its * streams to PulseAudio and does not attempt to do it by itself. PulseAudio * really knows better about events such as stream moving or headphone * plugging that would make the volume stored by the application inapplicable * to the new configuration. * * Another important case where setting a sink input volume may be a bad idea * is related to interpreters that interpret potentially untrusted scripts. * PulseAudio relies on your application not making malicious requests (such * as repeatedly setting the volume to 100%). Thus, script interpreters that * represent a security boundary must sandbox volume-changing requests coming * from their scripts. In the worst case, it may be necessary to apply the * script-requested volume to the script-produced sounds by altering the * samples in the script interpreter and not touching the sink or sink input * volume as seen by PulseAudio. * * If an application changes any volume, it should also listen to changes of * the same volume originating from outside the application (e.g., from the * system mixer application) and update its user interface accordingly. Use * \ref subscribe to get such notifications. * * \subsection module_subsec Modules * * Server modules can be remotely loaded and unloaded using * pa_context_load_module() and pa_context_unload_module(). * * \subsection client_subsec Clients * * The only operation supported on clients is the possibility of kicking * them off the server using pa_context_kill_client(). */ /** \file * * Routines for daemon introspection. * * See also \subpage introspect */ PA_C_DECL_BEGIN /** @{ \name Sinks */ /** Stores information about a specific port of a sink. Please * note that this structure can be extended as part of evolutionary * API updates at any time in any new release. \since 0.9.16 */ typedef struct pa_sink_port_info { const char *name; /**< Name of this port */ const char *description; /**< Description of this port */ uint32_t priority; /**< The higher this value is, the more useful this port is as a default. */ int available; /**< A flags (see #pa_port_available), indicating availability status of this port. \since 2.0 */ } pa_sink_port_info; /** Stores information about sinks. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_sink_info { const char *name; /**< Name of the sink */ uint32_t index; /**< Index of the sink */ const char *description; /**< Description of this sink */ pa_sample_spec sample_spec; /**< Sample spec of this sink */ pa_channel_map channel_map; /**< Channel map */ uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX. */ pa_cvolume volume; /**< Volume of the sink */ int mute; /**< Mute switch of the sink */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink. */ const char *monitor_source_name; /**< The name of the monitor source. */ pa_usec_t latency; /**< Length of queued audio in the output buffer. */ const char *driver; /**< Driver name */ pa_sink_flags_t flags; /**< Flags */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ pa_usec_t configured_latency; /**< The latency this device has been configured to. \since 0.9.11 */ pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the output device. \since 0.9.15 */ pa_sink_state_t state; /**< State \since 0.9.15 */ uint32_t n_volume_steps; /**< Number of volume steps for sinks which do not support arbitrary volumes. \since 0.9.15 */ uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */ uint32_t n_ports; /**< Number of entries in port array \since 0.9.16 */ pa_sink_port_info** ports; /**< Array of available ports, or NULL. Array is terminated by an entry set to NULL. The number of entries is stored in n_ports. \since 0.9.16 */ pa_sink_port_info* active_port; /**< Pointer to active port in the array, or NULL. \since 0.9.16 */ uint8_t n_formats; /**< Number of formats supported by the sink. \since 1.0 */ pa_format_info **formats; /**< Array of formats supported by the sink. \since 1.0 */ } pa_sink_info; /** Callback prototype for pa_context_get_sink_info_by_name() and friends */ typedef void (*pa_sink_info_cb_t)(pa_context *c, const pa_sink_info *i, int eol, void *userdata); /** Get information about a sink by its name */ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata); /** Get information about a sink by its index */ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata); /** Get the complete sink list */ pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); /** Set the volume of a sink device specified by its index */ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the volume of a sink device specified by its name */ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the mute switch of a sink device specified by its index */ pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); /** Set the mute switch of a sink device specified by its name */ pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); /** Suspend/Resume a sink. \since 0.9.7 */ pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata); /** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */ pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); /** Change the profile of a sink. \since 0.9.16 */ pa_operation* pa_context_set_sink_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata); /** Change the profile of a sink. \since 0.9.15 */ pa_operation* pa_context_set_sink_port_by_name(pa_context *c, const char*name, const char*port, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Sources */ /** Stores information about a specific port of a source. Please * note that this structure can be extended as part of evolutionary * API updates at any time in any new release. \since 0.9.16 */ typedef struct pa_source_port_info { const char *name; /**< Name of this port */ const char *description; /**< Description of this port */ uint32_t priority; /**< The higher this value is, the more useful this port is as a default. */ int available; /**< A flags (see #pa_port_available), indicating availability status of this port. \since 2.0 */ } pa_source_port_info; /** Stores information about sources. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_source_info { const char *name; /**< Name of the source */ uint32_t index; /**< Index of the source */ const char *description; /**< Description of this source */ pa_sample_spec sample_spec; /**< Sample spec of this source */ pa_channel_map channel_map; /**< Channel map */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX. */ pa_cvolume volume; /**< Volume of the source */ int mute; /**< Mute switch of the sink */ uint32_t monitor_of_sink; /**< If this is a monitor source, the index of the owning sink, otherwise PA_INVALID_INDEX. */ const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX. */ pa_usec_t latency; /**< Length of filled record buffer of this source. */ const char *driver; /**< Driver name */ pa_source_flags_t flags; /**< Flags */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ pa_usec_t configured_latency; /**< The latency this device has been configured to. \since 0.9.11 */ pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the input device. \since 0.9.15 */ pa_source_state_t state; /**< State \since 0.9.15 */ uint32_t n_volume_steps; /**< Number of volume steps for sources which do not support arbitrary volumes. \since 0.9.15 */ uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */ uint32_t n_ports; /**< Number of entries in port array \since 0.9.16 */ pa_source_port_info** ports; /**< Array of available ports, or NULL. Array is terminated by an entry set to NULL. The number of entries is stored in n_ports. \since 0.9.16 */ pa_source_port_info* active_port; /**< Pointer to active port in the array, or NULL. \since 0.9.16 */ uint8_t n_formats; /**< Number of formats supported by the source. \since 1.0 */ pa_format_info **formats; /**< Array of formats supported by the source. \since 1.0 */ } pa_source_info; /** Callback prototype for pa_context_get_source_info_by_name() and friends */ typedef void (*pa_source_info_cb_t)(pa_context *c, const pa_source_info *i, int eol, void *userdata); /** Get information about a source by its name */ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata); /** Get information about a source by its index */ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata); /** Get the complete source list */ pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); /** Set the volume of a source device specified by its index */ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the volume of a source device specified by its name */ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the mute switch of a source device specified by its index */ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); /** Set the mute switch of a source device specified by its name */ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); /** Suspend/Resume a source. \since 0.9.7 */ pa_operation* pa_context_suspend_source_by_name(pa_context *c, const char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata); /** Suspend/Resume a source. If idx is PA_INVALID_INDEX, all sources will be suspended. \since 0.9.7 */ pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); /** Change the profile of a source. \since 0.9.16 */ pa_operation* pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata); /** Change the profile of a source. \since 0.9.15 */ pa_operation* pa_context_set_source_port_by_name(pa_context *c, const char*name, const char*port, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Server */ /** Server information. Please note that this structure can be * extended as part of evolutionary API updates at any time in any new * release. */ typedef struct pa_server_info { const char *user_name; /**< User name of the daemon process */ const char *host_name; /**< Host name the daemon is running on */ const char *server_version; /**< Version string of the daemon */ const char *server_name; /**< Server package name (usually "pulseaudio") */ pa_sample_spec sample_spec; /**< Default sample specification */ const char *default_sink_name; /**< Name of default sink. */ const char *default_source_name; /**< Name of default source. */ uint32_t cookie; /**< A random cookie for identifying this instance of PulseAudio. */ pa_channel_map channel_map; /**< Default channel map. \since 0.9.15 */ } pa_server_info; /** Callback prototype for pa_context_get_server_info() */ typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); /** Get some information about the server */ pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); /** @} */ /** @{ \name Modules */ /** Stores information about modules. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_module_info { uint32_t index; /**< Index of the module */ const char*name, /**< Name of the module */ *argument; /**< Argument string of the module */ uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ /** \cond fulldocs */ int auto_unload; /**< \deprecated Non-zero if this is an autoloaded module. */ /** \endcond */ pa_proplist *proplist; /**< Property list \since 0.9.15 */ } pa_module_info; /** Callback prototype for pa_context_get_module_info() and friends */ typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata); /** Get some information about a module by its index */ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata); /** Get the complete list of currently loaded modules */ pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata); /** Callback prototype for pa_context_load_module() */ typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); /** Load a module. */ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); /** Unload a module. */ pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Clients */ /** Stores information about clients. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX. */ const char *driver; /**< Driver name */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ } pa_client_info; /** Callback prototype for pa_context_get_client_info() and friends */ typedef void (*pa_client_info_cb_t) (pa_context *c, const pa_client_info*i, int eol, void *userdata); /** Get information about a client by its index */ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata); /** Get the complete client list */ pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); /** Kill a client. */ pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Cards */ /** \deprecated Superseded by pa_card_profile_info2 \since 0.9.15 */ typedef struct pa_card_profile_info { const char *name; /**< Name of this profile */ const char *description; /**< Description of this profile */ uint32_t n_sinks; /**< Number of sinks this profile would create */ uint32_t n_sources; /**< Number of sources this profile would create */ uint32_t priority; /**< The higher this value is, the more useful this profile is as a default. */ } pa_card_profile_info; /** Stores information about a specific profile of a card. Please * note that this structure can be extended as part of evolutionary * API updates at any time in any new release. \since 5.0 */ typedef struct pa_card_profile_info2 { const char *name; /**< Name of this profile */ const char *description; /**< Description of this profile */ uint32_t n_sinks; /**< Number of sinks this profile would create */ uint32_t n_sources; /**< Number of sources this profile would create */ uint32_t priority; /**< The higher this value is, the more useful this profile is as a default. */ int available; /**< Is this profile available? If this is zero, meaning "unavailable", * then it makes no sense to try to activate this profile. If this is * non-zero, it's still not a guarantee that activating the profile will * result in anything useful, it just means that the server isn't aware of * any reason why the profile would definitely be useless. \since 5.0 */ } pa_card_profile_info2; /** Stores information about a specific port of a card. Please * note that this structure can be extended as part of evolutionary * API updates at any time in any new release. \since 2.0 */ typedef struct pa_card_port_info { const char *name; /**< Name of this port */ const char *description; /**< Description of this port */ uint32_t priority; /**< The higher this value is, the more useful this port is as a default. */ int available; /**< A #pa_port_available enum, indicating availability status of this port. */ int direction; /**< A #pa_direction enum, indicating the direction of this port. */ uint32_t n_profiles; /**< Number of entries in profile array */ pa_card_profile_info** profiles; /**< \deprecated Superseded by profiles2 */ pa_proplist *proplist; /**< Property list */ int64_t latency_offset; /**< Latency offset of the port that gets added to the sink/source latency when the port is active. \since 3.0 */ pa_card_profile_info2** profiles2; /**< Array of pointers to available profiles, or NULL. Array is terminated by an entry set to NULL. \since 5.0 */ } pa_card_port_info; /** Stores information about cards. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. \since 0.9.15 */ typedef struct pa_card_info { uint32_t index; /**< Index of this card */ const char *name; /**< Name of this card */ uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX. */ const char *driver; /**< Driver name */ uint32_t n_profiles; /**< Number of entries in profile array */ pa_card_profile_info* profiles; /**< \deprecated Superseded by profiles2 */ pa_card_profile_info* active_profile; /**< \deprecated Superseded by active_profile2 */ pa_proplist *proplist; /**< Property list */ uint32_t n_ports; /**< Number of entries in port array */ pa_card_port_info **ports; /**< Array of pointers to ports, or NULL. Array is terminated by an entry set to NULL. */ pa_card_profile_info2** profiles2; /**< Array of pointers to available profiles, or NULL. Array is terminated by an entry set to NULL. \since 5.0 */ pa_card_profile_info2* active_profile2; /**< Pointer to active profile in the array, or NULL. \since 5.0 */ } pa_card_info; /** Callback prototype for pa_context_get_card_info_...() \since 0.9.15 */ typedef void (*pa_card_info_cb_t) (pa_context *c, const pa_card_info*i, int eol, void *userdata); /** Get information about a card by its index \since 0.9.15 */ pa_operation* pa_context_get_card_info_by_index(pa_context *c, uint32_t idx, pa_card_info_cb_t cb, void *userdata); /** Get information about a card by its name \since 0.9.15 */ pa_operation* pa_context_get_card_info_by_name(pa_context *c, const char *name, pa_card_info_cb_t cb, void *userdata); /** Get the complete card list \since 0.9.15 */ pa_operation* pa_context_get_card_info_list(pa_context *c, pa_card_info_cb_t cb, void *userdata); /** Change the profile of a card. \since 0.9.15 */ pa_operation* pa_context_set_card_profile_by_index(pa_context *c, uint32_t idx, const char*profile, pa_context_success_cb_t cb, void *userdata); /** Change the profile of a card. \since 0.9.15 */ pa_operation* pa_context_set_card_profile_by_name(pa_context *c, const char*name, const char*profile, pa_context_success_cb_t cb, void *userdata); /** Set the latency offset of a port. \since 3.0 */ pa_operation* pa_context_set_port_latency_offset(pa_context *c, const char *card_name, const char *port_name, int64_t offset, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Sink Inputs */ /** Stores information about sink inputs. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_sink_input_info { uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module. */ uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client. */ uint32_t sink; /**< Index of the connected sink */ pa_sample_spec sample_spec; /**< The sample specification of the sink input. */ pa_channel_map channel_map; /**< Channel map */ pa_cvolume volume; /**< The volume of this sink input. */ pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_timing_info for details. */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_timing_info for details. */ const char *resample_method; /**< The resampling method used by this sink input. */ const char *driver; /**< Driver name */ int mute; /**< Stream muted \since 0.9.7 */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ int corked; /**< Stream corked \since 1.0 */ int has_volume; /**< Stream has volume. If not set, then the meaning of this struct's volume member is unspecified. \since 1.0 */ int volume_writable; /**< The volume can be set. If not set, the volume can still change even though clients can't control the volume. \since 1.0 */ pa_format_info *format; /**< Stream format information. \since 1.0 */ } pa_sink_input_info; /** Callback prototype for pa_context_get_sink_input_info() and friends */ typedef void (*pa_sink_input_info_cb_t) (pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); /** Get some information about a sink input by its index */ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); /** Get the complete sink input list */ pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); /** Move the specified sink input to a different sink. \since 0.9.5 */ pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, const char *sink_name, pa_context_success_cb_t cb, void* userdata); /** Move the specified sink input to a different sink. \since 0.9.5 */ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata); /** Set the volume of a sink input stream */ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the mute switch of a sink input stream \since 0.9.7 */ pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); /** Kill a sink input. */ pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Source Outputs */ /** Stores information about source outputs. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_source_output_info { uint32_t index; /**< Index of the source output */ const char *name; /**< Name of the source output */ uint32_t owner_module; /**< Index of the module this source output belongs to, or PA_INVALID_INDEX when it does not belong to any module. */ uint32_t client; /**< Index of the client this source output belongs to, or PA_INVALID_INDEX when it does not belong to any client. */ uint32_t source; /**< Index of the connected source */ pa_sample_spec sample_spec; /**< The sample specification of the source output */ pa_channel_map channel_map; /**< Channel map */ pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_timing_info for details. */ pa_usec_t source_usec; /**< Latency of the source device, see pa_timing_info for details. */ const char *resample_method; /**< The resampling method used by this source output. */ const char *driver; /**< Driver name */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ int corked; /**< Stream corked \since 1.0 */ pa_cvolume volume; /**< The volume of this source output \since 1.0 */ int mute; /**< Stream muted \since 1.0 */ int has_volume; /**< Stream has volume. If not set, then the meaning of this struct's volume member is unspecified. \since 1.0 */ int volume_writable; /**< The volume can be set. If not set, the volume can still change even though clients can't control the volume. \since 1.0 */ pa_format_info *format; /**< Stream format information. \since 1.0 */ } pa_source_output_info; /** Callback prototype for pa_context_get_source_output_info() and friends */ typedef void (*pa_source_output_info_cb_t) (pa_context *c, const pa_source_output_info *i, int eol, void *userdata); /** Get information about a source output by its index */ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata); /** Get the complete list of source outputs */ pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata); /** Move the specified source output to a different source. \since 0.9.5 */ pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, const char *source_name, pa_context_success_cb_t cb, void* userdata); /** Move the specified source output to a different source. \since 0.9.5 */ pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata); /** Set the volume of a source output stream \since 1.0 */ pa_operation* pa_context_set_source_output_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); /** Set the mute switch of a source output stream \since 1.0 */ pa_operation* pa_context_set_source_output_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); /** Kill a source output. */ pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); /** @} */ /** @{ \name Statistics */ /** Memory block statistics. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_stat_info { uint32_t memblock_total; /**< Currently allocated memory blocks */ uint32_t memblock_total_size; /**< Current total size of allocated memory blocks */ uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon. */ uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon. */ uint32_t scache_size; /**< Total size of all sample cache entries. */ } pa_stat_info; /** Callback prototype for pa_context_stat() */ typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *userdata); /** Get daemon memory block statistics */ pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); /** @} */ /** @{ \name Cached Samples */ /** Stores information about sample cache entries. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_sample_info { uint32_t index; /**< Index of this entry */ const char *name; /**< Name of this entry */ pa_cvolume volume; /**< Default volume of this entry */ pa_sample_spec sample_spec; /**< Sample specification of the sample */ pa_channel_map channel_map; /**< The channel map */ pa_usec_t duration; /**< Duration of this entry */ uint32_t bytes; /**< Length of this sample in bytes. */ int lazy; /**< Non-zero when this is a lazy cache entry. */ const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. */ pa_proplist *proplist; /**< Property list for this sample. \since 0.9.11 */ } pa_sample_info; /** Callback prototype for pa_context_get_sample_info_by_name() and friends */ typedef void (*pa_sample_info_cb_t)(pa_context *c, const pa_sample_info *i, int eol, void *userdata); /** Get information about a sample by its name */ pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata); /** Get information about a sample by its index */ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata); /** Get the complete list of samples stored in the daemon. */ pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata); /** @} */ /** \cond fulldocs */ /** @{ \name Autoload Entries */ /** \deprecated Type of an autoload entry. */ typedef enum pa_autoload_type { PA_AUTOLOAD_SINK = 0, PA_AUTOLOAD_SOURCE = 1 } pa_autoload_type_t; /** \deprecated Stores information about autoload entries. Please note that this structure * can be extended as part of evolutionary API updates at any time in * any new release. */ typedef struct pa_autoload_info { uint32_t index; /**< Index of this autoload entry */ const char *name; /**< Name of the sink or source */ pa_autoload_type_t type; /**< Type of the autoload entry */ const char *module; /**< Module name to load */ const char *argument; /**< Argument string for module */ } pa_autoload_info; /** \deprecated Callback prototype for pa_context_get_autoload_info_by_name() and friends */ typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata); /** \deprecated Get info about a specific autoload entry. */ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) PA_GCC_DEPRECATED; /** \deprecated Get info about a specific autoload entry. */ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) PA_GCC_DEPRECATED; /** \deprecated Get the complete list of autoload entries. */ pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) PA_GCC_DEPRECATED; /** \deprecated Add a new autoload entry. */ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata) PA_GCC_DEPRECATED; /** \deprecated Remove an autoload entry. */ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) PA_GCC_DEPRECATED; /** \deprecated Remove an autoload entry. */ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) PA_GCC_DEPRECATED; /** @} */ /** \endcond */ PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/mainloop-api.h000066400000000000000000000136011364710014100243040ustar00rootroot00000000000000#ifndef foomainloopapihfoo #define foomainloopapihfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include /** \file * * Main loop abstraction layer. Both the PulseAudio core and the * PulseAudio client library use a main loop abstraction layer. Due to * this it is possible to embed PulseAudio into other * applications easily. Two main loop implementations are * currently available: * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) * \li A wrapper around the GLIB main loop. Use this to embed PulseAudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) * * The structure pa_mainloop_api is used as vtable for the main loop abstraction. * * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available through \ref mainloop-signal.h. * */ PA_C_DECL_BEGIN /** An abstract mainloop API vtable */ typedef struct pa_mainloop_api pa_mainloop_api; /** A bitmask for IO events */ typedef enum pa_io_event_flags { PA_IO_EVENT_NULL = 0, /**< No event */ PA_IO_EVENT_INPUT = 1, /**< Input event */ PA_IO_EVENT_OUTPUT = 2, /**< Output event */ PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ PA_IO_EVENT_ERROR = 8 /**< Error event */ } pa_io_event_flags_t; /** An opaque IO event source object */ typedef struct pa_io_event pa_io_event; /** An IO event callback prototype \since 0.9.3 */ typedef void (*pa_io_event_cb_t)(pa_mainloop_api*ea, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata); /** A IO event destroy callback prototype \ since 0.9.3 */ typedef void (*pa_io_event_destroy_cb_t)(pa_mainloop_api*a, pa_io_event *e, void *userdata); /** An opaque timer event source object */ typedef struct pa_time_event pa_time_event; /** A time event callback prototype \since 0.9.3 */ typedef void (*pa_time_event_cb_t)(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata); /** A time event destroy callback prototype \ since 0.9.3 */ typedef void (*pa_time_event_destroy_cb_t)(pa_mainloop_api*a, pa_time_event *e, void *userdata); /** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ typedef struct pa_defer_event pa_defer_event; /** A defer event callback prototype \since 0.9.3 */ typedef void (*pa_defer_event_cb_t)(pa_mainloop_api*a, pa_defer_event* e, void *userdata); /** A defer event destroy callback prototype \ since 0.9.3 */ typedef void (*pa_defer_event_destroy_cb_t)(pa_mainloop_api*a, pa_defer_event *e, void *userdata); /** An abstract mainloop API vtable */ struct pa_mainloop_api { /** A pointer to some private, arbitrary data of the main loop implementation */ void *userdata; /** Create a new IO event source object */ pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata); /** Enable or disable IO events on this object */ void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); /** Free a IO event source object */ void (*io_free)(pa_io_event* e); /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ void (*io_set_destroy)(pa_io_event *e, pa_io_event_destroy_cb_t cb); /** Create a new timer event source object for the specified Unix time */ pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata); /** Restart a running or expired timer event source with a new Unix time */ void (*time_restart)(pa_time_event* e, const struct timeval *tv); /** Free a deferred timer event source object */ void (*time_free)(pa_time_event* e); /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ void (*time_set_destroy)(pa_time_event *e, pa_time_event_destroy_cb_t cb); /** Create a new deferred event source object */ pa_defer_event* (*defer_new)(pa_mainloop_api*a, pa_defer_event_cb_t cb, void *userdata); /** Enable or disable a deferred event source temporarily */ void (*defer_enable)(pa_defer_event* e, int b); /** Free a deferred event source object */ void (*defer_free)(pa_defer_event* e); /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ void (*defer_set_destroy)(pa_defer_event *e, pa_defer_event_destroy_cb_t cb); /** Exit the main loop and return the specified retval*/ void (*quit)(pa_mainloop_api*a, int retval); }; /** Run the specified callback function once from the main loop using an anonymous defer event. Note that this performs * multiple mainloop operations non-atomically. If, for example, you are using a \ref pa_threaded_mainloop, you will need to * take the mainloop lock before this call. */ void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/mainloop-signal.h000066400000000000000000000046671364710014100250240ustar00rootroot00000000000000#ifndef foomainloopsignalhfoo #define foomainloopsignalhfoo /*** This file is part of PulseAudio. Copyright 2004-2008 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include PA_C_DECL_BEGIN /** \file * UNIX signal support for main loops. In contrast to other * main loop event sources such as timer and IO events, UNIX signal * support requires modification of the global process * environment. Due to this the generic main loop abstraction layer as * defined in \ref mainloop-api.h doesn't have direct support for UNIX * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. */ /** An opaque UNIX signal event source object */ typedef struct pa_signal_event pa_signal_event; /** Callback prototype for signal events */ typedef void (*pa_signal_cb_t) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata); /** Destroy callback prototype for signal events */ typedef void (*pa_signal_destroy_cb_t) (pa_mainloop_api *api, pa_signal_event*e, void *userdata); /** Initialize the UNIX signal subsystem and bind it to the specified main loop */ int pa_signal_init(pa_mainloop_api *api); /** Cleanup the signal subsystem */ void pa_signal_done(void); /** Create a new UNIX signal event source object */ pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t callback, void *userdata); /** Free a UNIX signal event source object */ void pa_signal_free(pa_signal_event *e); /** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t callback); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/mainloop.h000066400000000000000000000116001364710014100235320ustar00rootroot00000000000000#ifndef foomainloophfoo #define foomainloophfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include PA_C_DECL_BEGIN struct pollfd; /** \page mainloop Main Loop * * \section overv_sec Overview * * The built-in main loop implementation is based on the poll() system call. * It supports the functions defined in the main loop abstraction and very * little else. * * The main loop is created using pa_mainloop_new() and destroyed using * pa_mainloop_free(). To get access to the main loop abstraction, * pa_mainloop_get_api() is used. * * \section iter_sec Iteration * * The main loop is designed around the concept of iterations. Each iteration * consists of three steps that repeat during the application's entire * lifetime: * * -# Prepare - Build a list of file descriptors * that need to be monitored and calculate the next timeout. * -# Poll - Execute the actual poll() system call. * -# Dispatch - Dispatch any events that have fired. * * When using the main loop, the application can either execute each * iteration, one at a time, using pa_mainloop_iterate(), or let the library * iterate automatically using pa_mainloop_run(). * * \section thread_sec Threads * * The main loop functions are designed to be thread safe, but the objects * are not. What this means is that multiple main loops can be used, but only * one object per thread. * */ /** \file * * A minimal main loop implementation based on the C library's poll() * function. Using the routines defined herein you may create a simple * main loop supporting the generic main loop abstraction layer as * defined in \ref mainloop-api.h. This implementation is thread safe * as long as you access the main loop object from a single thread only. * * See also \subpage mainloop */ /** An opaque main loop object */ typedef struct pa_mainloop pa_mainloop; /** Allocate a new main loop object */ pa_mainloop *pa_mainloop_new(void); /** Free a main loop object */ void pa_mainloop_free(pa_mainloop* m); /** Prepare for a single iteration of the main loop. Returns a negative value on error or exit request. timeout specifies a maximum timeout for the subsequent poll, or -1 for blocking behaviour. .*/ int pa_mainloop_prepare(pa_mainloop *m, int timeout); /** Execute the previously prepared poll. Returns a negative value on error.*/ int pa_mainloop_poll(pa_mainloop *m); /** Dispatch timeout, io and deferred events from the previously executed poll. Returns a negative value on error. On success returns the number of source dispatched. */ int pa_mainloop_dispatch(pa_mainloop *m); /** Return the return value as specified with the main loop's quit() routine. */ int pa_mainloop_get_retval(pa_mainloop *m); /** Run a single iteration of the main loop. This is a convenience function for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). Returns a negative value on error or exit request. If block is nonzero, block for events if none are queued. Optionally return the return value as specified with the main loop's quit() routine in the integer variable retval points to. On success returns the number of sources dispatched in this iteration. */ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); /** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ int pa_mainloop_run(pa_mainloop *m, int *retval); /** Return the abstract main loop abstraction layer vtable for this main loop. No need to free the API as it is owned by the loop and is destroyed when the loop is freed. */ pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); /** Shutdown the main loop */ void pa_mainloop_quit(pa_mainloop *m, int r); /** Interrupt a running poll (for threaded systems) */ void pa_mainloop_wakeup(pa_mainloop *m); /** Generic prototype of a poll() like function */ typedef int (*pa_poll_func)(struct pollfd *ufds, unsigned long nfds, int timeout, void*userdata); /** Change the poll() implementation */ void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/operation.h000066400000000000000000000044331364710014100237220ustar00rootroot00000000000000#ifndef foooperationhfoo #define foooperationhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include /** \file * Asynchronous operations */ PA_C_DECL_BEGIN /** An asynchronous operation object */ typedef struct pa_operation pa_operation; /** A callback for operation state changes */ typedef void (*pa_operation_notify_cb_t) (pa_operation *o, void *userdata); /** Increase the reference count by one */ pa_operation *pa_operation_ref(pa_operation *o); /** Decrease the reference count by one */ void pa_operation_unref(pa_operation *o); /** Cancel the operation. Beware! This will not necessarily cancel the * execution of the operation on the server side. However it will make * sure that the callback associated with this operation will not be * called anymore, effectively disabling the operation from the client * side's view. */ void pa_operation_cancel(pa_operation *o); /** Return the current status of the operation */ pa_operation_state_t pa_operation_get_state(pa_operation *o); /** Set the callback function that is called when the operation state * changes. Usually this is not necessary, since the functions that * create pa_operation objects already take a callback that is called * when the operation finishes. Registering a state change callback is * mainly useful, if you want to get called back also if the operation * gets cancelled. \since 4.0 */ void pa_operation_set_state_callback(pa_operation *o, pa_operation_notify_cb_t cb, void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/proplist.h000066400000000000000000000527531364710014100236060ustar00rootroot00000000000000#ifndef foopulseproplisthfoo #define foopulseproplisthfoo /*** This file is part of PulseAudio. Copyright 2007 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include /** \file * Property list constants and functions */ PA_C_DECL_BEGIN /** For streams: localized media name, formatted as UTF-8. E.g. "Guns'N'Roses: Civil War".*/ #define PA_PROP_MEDIA_NAME "media.name" /** For streams: localized media title if applicable, formatted as UTF-8. E.g. "Civil War" */ #define PA_PROP_MEDIA_TITLE "media.title" /** For streams: localized media artist if applicable, formatted as UTF-8. E.g. "Guns'N'Roses" */ #define PA_PROP_MEDIA_ARTIST "media.artist" /** For streams: localized media copyright string if applicable, formatted as UTF-8. E.g. "Evil Record Corp." */ #define PA_PROP_MEDIA_COPYRIGHT "media.copyright" /** For streams: localized media generator software string if applicable, formatted as UTF-8. E.g. "Foocrop AudioFrobnicator" */ #define PA_PROP_MEDIA_SOFTWARE "media.software" /** For streams: media language if applicable, in standard POSIX format. E.g. "de_DE" */ #define PA_PROP_MEDIA_LANGUAGE "media.language" /** For streams: source filename if applicable, in URI format or local path. E.g. "/home/lennart/music/foobar.ogg" */ #define PA_PROP_MEDIA_FILENAME "media.filename" /** \cond fulldocs */ /** For streams: icon for the media. A binary blob containing PNG image data */ #define PA_PROP_MEDIA_ICON "media.icon" /** \endcond */ /** For streams: an XDG icon name for the media. E.g. "audio-x-mp3" */ #define PA_PROP_MEDIA_ICON_NAME "media.icon_name" /** For streams: logic role of this media. One of the strings "video", "music", "game", "event", "phone", "animation", "production", "a11y", "test" */ #define PA_PROP_MEDIA_ROLE "media.role" /** For streams: the name of a filter that is desired, e.g.\ "echo-cancel" or "equalizer-sink". PulseAudio may choose to not apply the filter if it does not make sense (for example, applying echo-cancellation on a Bluetooth headset probably does not make sense. \since 1.0 */ #define PA_PROP_FILTER_WANT "filter.want" /** For streams: the name of a filter that is desired, e.g.\ "echo-cancel" or "equalizer-sink". Differs from PA_PROP_FILTER_WANT in that it forces PulseAudio to apply the filter, regardless of whether PulseAudio thinks it makes sense to do so or not. If this is set, PA_PROP_FILTER_WANT is ignored. In other words, you almost certainly do not want to use this. \since 1.0 */ #define PA_PROP_FILTER_APPLY "filter.apply" /** For streams: the name of a filter that should specifically suppressed (i.e.\ overrides PA_PROP_FILTER_WANT). Useful for the times that PA_PROP_FILTER_WANT is automatically added (e.g. echo-cancellation for phone streams when $VOIP_APP does it's own, internal AEC) \since 1.0 */ #define PA_PROP_FILTER_SUPPRESS "filter.suppress" /** For event sound streams: XDG event sound name. e.g.\ "message-new-email" (Event sound streams are those with media.role set to "event") */ #define PA_PROP_EVENT_ID "event.id" /** For event sound streams: localized human readable one-line description of the event, formatted as UTF-8. E.g. "Email from lennart@example.com received." */ #define PA_PROP_EVENT_DESCRIPTION "event.description" /** For event sound streams: absolute horizontal mouse position on the screen if the event sound was triggered by a mouse click, integer formatted as text string. E.g. "865" */ #define PA_PROP_EVENT_MOUSE_X "event.mouse.x" /** For event sound streams: absolute vertical mouse position on the screen if the event sound was triggered by a mouse click, integer formatted as text string. E.g. "432" */ #define PA_PROP_EVENT_MOUSE_Y "event.mouse.y" /** For event sound streams: relative horizontal mouse position on the screen if the event sound was triggered by a mouse click, float formatted as text string, ranging from 0.0 (left side of the screen) to 1.0 (right side of the screen). E.g. "0.65" */ #define PA_PROP_EVENT_MOUSE_HPOS "event.mouse.hpos" /** For event sound streams: relative vertical mouse position on the screen if the event sound was triggered by a mouse click, float formatted as text string, ranging from 0.0 (top of the screen) to 1.0 (bottom of the screen). E.g. "0.43" */ #define PA_PROP_EVENT_MOUSE_VPOS "event.mouse.vpos" /** For event sound streams: mouse button that triggered the event if applicable, integer formatted as string with 0=left, 1=middle, 2=right. E.g. "0" */ #define PA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button" /** For streams that belong to a window on the screen: localized window title. E.g. "Totem Music Player" */ #define PA_PROP_WINDOW_NAME "window.name" /** For streams that belong to a window on the screen: a textual id for identifying a window logically. E.g. "org.gnome.Totem.MainWindow" */ #define PA_PROP_WINDOW_ID "window.id" /** \cond fulldocs */ /** For streams that belong to a window on the screen: window icon. A binary blob containing PNG image data */ #define PA_PROP_WINDOW_ICON "window.icon" /** \endcond */ /** For streams that belong to a window on the screen: an XDG icon name for the window. E.g. "totem" */ #define PA_PROP_WINDOW_ICON_NAME "window.icon_name" /** For streams that belong to a window on the screen: absolute horizontal window position on the screen, integer formatted as text string. E.g. "865". \since 0.9.17 */ #define PA_PROP_WINDOW_X "window.x" /** For streams that belong to a window on the screen: absolute vertical window position on the screen, integer formatted as text string. E.g. "343". \since 0.9.17 */ #define PA_PROP_WINDOW_Y "window.y" /** For streams that belong to a window on the screen: window width on the screen, integer formatted as text string. e.g. "365". \since 0.9.17 */ #define PA_PROP_WINDOW_WIDTH "window.width" /** For streams that belong to a window on the screen: window height on the screen, integer formatted as text string. E.g. "643". \since 0.9.17 */ #define PA_PROP_WINDOW_HEIGHT "window.height" /** For streams that belong to a window on the screen: relative position of the window center on the screen, float formatted as text string, ranging from 0.0 (left side of the screen) to 1.0 (right side of the screen). E.g. "0.65". \since 0.9.17 */ #define PA_PROP_WINDOW_HPOS "window.hpos" /** For streams that belong to a window on the screen: relative position of the window center on the screen, float formatted as text string, ranging from 0.0 (top of the screen) to 1.0 (bottom of the screen). E.g. "0.43". \since 0.9.17 */ #define PA_PROP_WINDOW_VPOS "window.vpos" /** For streams that belong to a window on the screen: if the windowing system supports multiple desktops, a comma separated list of indexes of the desktops this window is visible on. If this property is an empty string, it is visible on all desktops (i.e. 'sticky'). The first desktop is 0. E.g. "0,2,3" \since 0.9.18 */ #define PA_PROP_WINDOW_DESKTOP "window.desktop" /** For streams that belong to an X11 window on the screen: the X11 display string. E.g. ":0.0" */ #define PA_PROP_WINDOW_X11_DISPLAY "window.x11.display" /** For streams that belong to an X11 window on the screen: the X11 screen the window is on, an integer formatted as string. E.g. "0" */ #define PA_PROP_WINDOW_X11_SCREEN "window.x11.screen" /** For streams that belong to an X11 window on the screen: the X11 monitor the window is on, an integer formatted as string. E.g. "0" */ #define PA_PROP_WINDOW_X11_MONITOR "window.x11.monitor" /** For streams that belong to an X11 window on the screen: the window XID, an integer formatted as string. E.g. "25632" */ #define PA_PROP_WINDOW_X11_XID "window.x11.xid" /** For clients/streams: localized human readable application name. E.g. "Totem Music Player" */ #define PA_PROP_APPLICATION_NAME "application.name" /** For clients/streams: a textual id for identifying an application logically. E.g. "org.gnome.Totem" */ #define PA_PROP_APPLICATION_ID "application.id" /** For clients/streams: a version string, e.g.\ "0.6.88" */ #define PA_PROP_APPLICATION_VERSION "application.version" /** \cond fulldocs */ /** For clients/streams: application icon. A binary blob containing PNG image data */ #define PA_PROP_APPLICATION_ICON "application.icon" /** \endcond */ /** For clients/streams: an XDG icon name for the application. E.g. "totem" */ #define PA_PROP_APPLICATION_ICON_NAME "application.icon_name" /** For clients/streams: application language if applicable, in standard POSIX format. E.g. "de_DE" */ #define PA_PROP_APPLICATION_LANGUAGE "application.language" /** For clients/streams on UNIX: application process PID, an integer formatted as string. E.g. "4711" */ #define PA_PROP_APPLICATION_PROCESS_ID "application.process.id" /** For clients/streams: application process name. E.g. "totem" */ #define PA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary" /** For clients/streams: application user name. E.g. "lennart" */ #define PA_PROP_APPLICATION_PROCESS_USER "application.process.user" /** For clients/streams: host name the application runs on. E.g. "omega" */ #define PA_PROP_APPLICATION_PROCESS_HOST "application.process.host" /** For clients/streams: the D-Bus host id the application runs on. E.g. "543679e7b01393ed3e3e650047d78f6e" */ #define PA_PROP_APPLICATION_PROCESS_MACHINE_ID "application.process.machine_id" /** For clients/streams: an id for the login session the application runs in. On Unix the value of $XDG_SESSION_ID. E.g. "5" */ #define PA_PROP_APPLICATION_PROCESS_SESSION_ID "application.process.session_id" /** For devices: device string in the underlying audio layer's format. E.g. "surround51:0" */ #define PA_PROP_DEVICE_STRING "device.string" /** For devices: API this device is access with. E.g. "alsa" */ #define PA_PROP_DEVICE_API "device.api" /** For devices: localized human readable device one-line description. E.g. "Foobar Industries USB Headset 2000+ Ultra" */ #define PA_PROP_DEVICE_DESCRIPTION "device.description" /** For devices: bus path to the device in the OS' format. E.g. "/sys/bus/pci/devices/0000:00:1f.2" */ #define PA_PROP_DEVICE_BUS_PATH "device.bus_path" /** For devices: serial number if applicable. E.g. "4711-0815-1234" */ #define PA_PROP_DEVICE_SERIAL "device.serial" /** For devices: vendor ID if applicable. E.g. 1274 */ #define PA_PROP_DEVICE_VENDOR_ID "device.vendor.id" /** For devices: vendor name if applicable. E.g. "Foocorp Heavy Industries" */ #define PA_PROP_DEVICE_VENDOR_NAME "device.vendor.name" /** For devices: product ID if applicable. E.g. 4565 */ #define PA_PROP_DEVICE_PRODUCT_ID "device.product.id" /** For devices: product name if applicable. E.g. "SuperSpeakers 2000 Pro" */ #define PA_PROP_DEVICE_PRODUCT_NAME "device.product.name" /** For devices: device class. One of "sound", "modem", "monitor", "filter" */ #define PA_PROP_DEVICE_CLASS "device.class" /** For devices: form factor if applicable. One of "internal", "speaker", "handset", "tv", "webcam", "microphone", "headset", "headphone", "hands-free", "car", "hifi", "computer", "portable" */ #define PA_PROP_DEVICE_FORM_FACTOR "device.form_factor" /** For devices: bus of the device if applicable. One of "isa", "pci", "usb", "firewire", "bluetooth" */ #define PA_PROP_DEVICE_BUS "device.bus" /** \cond fulldocs */ /** For devices: icon for the device. A binary blob containing PNG image data */ #define PA_PROP_DEVICE_ICON "device.icon" /** \endcond */ /** For devices: an XDG icon name for the device. E.g. "sound-card-speakers-usb" */ #define PA_PROP_DEVICE_ICON_NAME "device.icon_name" /** For devices: access mode of the device if applicable. One of "mmap", "mmap_rewrite", "serial" */ #define PA_PROP_DEVICE_ACCESS_MODE "device.access_mode" /** For filter devices: master device id if applicable. */ #define PA_PROP_DEVICE_MASTER_DEVICE "device.master_device" /** For devices: buffer size in bytes, integer formatted as string. */ #define PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE "device.buffering.buffer_size" /** For devices: fragment size in bytes, integer formatted as string. */ #define PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE "device.buffering.fragment_size" /** For devices: profile identifier for the profile this devices is in. E.g. "analog-stereo", "analog-surround-40", "iec958-stereo", ...*/ #define PA_PROP_DEVICE_PROFILE_NAME "device.profile.name" /** For devices: intended use. A space separated list of roles (see PA_PROP_MEDIA_ROLE) this device is particularly well suited for, due to latency, quality or form factor. \since 0.9.16 */ #define PA_PROP_DEVICE_INTENDED_ROLES "device.intended_roles" /** For devices: human readable one-line description of the profile this device is in. E.g. "Analog Stereo", ... */ #define PA_PROP_DEVICE_PROFILE_DESCRIPTION "device.profile.description" /** For modules: the author's name, formatted as UTF-8 string. E.g. "Lennart Poettering" */ #define PA_PROP_MODULE_AUTHOR "module.author" /** For modules: a human readable one-line description of the module's purpose formatted as UTF-8. E.g. "Frobnicate sounds with a flux compensator" */ #define PA_PROP_MODULE_DESCRIPTION "module.description" /** For modules: a human readable usage description of the module's arguments formatted as UTF-8. */ #define PA_PROP_MODULE_USAGE "module.usage" /** For modules: a version string for the module. E.g. "0.9.15" */ #define PA_PROP_MODULE_VERSION "module.version" /** For PCM formats: the sample format used as returned by pa_sample_format_to_string() \since 1.0 */ #define PA_PROP_FORMAT_SAMPLE_FORMAT "format.sample_format" /** For all formats: the sample rate (unsigned integer) \since 1.0 */ #define PA_PROP_FORMAT_RATE "format.rate" /** For all formats: the number of channels (unsigned integer) \since 1.0 */ #define PA_PROP_FORMAT_CHANNELS "format.channels" /** For PCM formats: the channel map of the stream as returned by pa_channel_map_snprint() \since 1.0 */ #define PA_PROP_FORMAT_CHANNEL_MAP "format.channel_map" /** A property list object. Basically a dictionary with ASCII strings * as keys and arbitrary data as values. \since 0.9.11 */ typedef struct pa_proplist pa_proplist; /** Allocate a property list. \since 0.9.11 */ pa_proplist* pa_proplist_new(void); /** Free the property list. \since 0.9.11 */ void pa_proplist_free(pa_proplist* p); /** Returns a non-zero value if the key is valid. \since 3.0 */ int pa_proplist_key_valid(const char *key); /** Append a new string entry to the property list, possibly * overwriting an already existing entry with the same key. An * internal copy of the data passed is made. Will accept only valid * UTF-8. \since 0.9.11 */ int pa_proplist_sets(pa_proplist *p, const char *key, const char *value); /** Append a new string entry to the property list, possibly * overwriting an already existing entry with the same key. An * internal copy of the data passed is made. Will accept only valid * UTF-8. The string passed in must contain a '='. Left hand side of * the '=' is used as key name, the right hand side as string * data. \since 0.9.16 */ int pa_proplist_setp(pa_proplist *p, const char *pair); /** Append a new string entry to the property list, possibly * overwriting an already existing entry with the same key. An * internal copy of the data passed is made. Will accept only valid * UTF-8. The data can be passed as printf()-style format string with * arguments. \since 0.9.11 */ int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) PA_GCC_PRINTF_ATTR(3,4); /** Append a new arbitrary data entry to the property list, possibly * overwriting an already existing entry with the same key. An * internal copy of the data passed is made. \since 0.9.11 */ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes); /** Return a string entry for the specified key. Will return NULL if * the data is not valid UTF-8. Will return a NUL-terminated string in * an internally allocated buffer. The caller should make a copy of * the data before accessing the property list again. \since 0.9.11 */ const char *pa_proplist_gets(pa_proplist *p, const char *key); /** Store the value for the specified key in \a data. Will store a * NUL-terminated string for string entries. The \a data pointer returned will * point to an internally allocated buffer. The caller should make a * copy of the data before the property list is accessed again. \since * 0.9.11 */ int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes); /** Update mode enum for pa_proplist_update(). \since 0.9.11 */ typedef enum pa_update_mode { PA_UPDATE_SET /**< Replace the entire property list with the new one. Don't keep * any of the old data around. */, PA_UPDATE_MERGE /**< Merge new property list into the existing one, not replacing * any old entries if they share a common key with the new * property list. */, PA_UPDATE_REPLACE /**< Merge new property list into the existing one, replacing all * old entries that share a common key with the new property * list. */ } pa_update_mode_t; /** \cond fulldocs */ #define PA_UPDATE_SET PA_UPDATE_SET #define PA_UPDATE_MERGE PA_UPDATE_MERGE #define PA_UPDATE_REPLACE PA_UPDATE_REPLACE /** \endcond */ /** Merge property list "other" into "p", adhering the merge mode as * specified in "mode". \since 0.9.11 */ void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, const pa_proplist *other); /** Removes a single entry from the property list, identified be the * specified key name. \since 0.9.11 */ int pa_proplist_unset(pa_proplist *p, const char *key); /** Similar to pa_proplist_unset() but takes an array of keys to * remove. The array should be terminated by a NULL pointer. Returns -1 * on failure, otherwise the number of entries actually removed (which * might even be 0, if there were no matching entries to * remove). \since 0.9.11 */ int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]); /** Iterate through the property list. The user should allocate a * state variable of type void* and initialize it with NULL. A pointer * to this variable should then be passed to pa_proplist_iterate() * which should be called in a loop until it returns NULL which * signifies EOL. The property list should not be modified during * iteration through the list -- with the exception of deleting the * current entry. On each invocation this function will return the * key string for the next entry. The keys in the property list do not * have any particular order. \since 0.9.11 */ const char *pa_proplist_iterate(pa_proplist *p, void **state); /** Format the property list nicely as a human readable string. This * works very much like pa_proplist_to_string_sep() and uses a newline * as separator and appends one final one. Call pa_xfree() on the * result. \since 0.9.11 */ char *pa_proplist_to_string(pa_proplist *p); /** Format the property list nicely as a human readable string and * choose the separator. Call pa_xfree() on the result. \since * 0.9.15 */ char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep); /** Allocate a new property list and assign key/value from a human * readable string. \since 0.9.15 */ pa_proplist *pa_proplist_from_string(const char *str); /** Returns 1 if an entry for the specified key exists in the * property list. \since 0.9.11 */ int pa_proplist_contains(pa_proplist *p, const char *key); /** Remove all entries from the property list object. \since 0.9.11 */ void pa_proplist_clear(pa_proplist *p); /** Allocate a new property list and copy over every single entry from * the specified list. \since 0.9.11 */ pa_proplist* pa_proplist_copy(const pa_proplist *p); /** Return the number of entries in the property list. \since 0.9.15 */ unsigned pa_proplist_size(pa_proplist *p); /** Returns 0 when the proplist is empty, positive otherwise \since 0.9.15 */ int pa_proplist_isempty(pa_proplist *p); /** Return non-zero when a and b have the same keys and values. * \since 0.9.16 */ int pa_proplist_equal(pa_proplist *a, pa_proplist *b); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/pulseaudio.h000066400000000000000000000121721364710014100240730ustar00rootroot00000000000000#ifndef foopulseaudiohfoo #define foopulseaudiohfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** \file * Include all libpulse header files at once. The following files are * included: \ref mainloop-api.h, \ref sample.h, \ref def.h, \ref * context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, \ref * scache.h, \ref version.h, \ref error.h, \ref channelmap.h, \ref * operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref proplist.h, * \ref timeval.h, \ref rtclock.h and \ref mainloop-signal.h at * once */ /** \mainpage * * \section intro_sec Introduction * * This document describes the client API for the PulseAudio sound * server. The API comes in two flavours to accommodate different styles * of applications and different needs in complexity: * * \li The complete but somewhat complicated to use asynchronous API * \li The simplified, easy to use, but limited synchronous API * * All strings in PulseAudio are in the UTF-8 encoding, regardless of current * locale. Some functions will filter invalid sequences from the string, some * will simply fail. To ensure reliable behaviour, make sure everything you * pass to the API is already in UTF-8. * \section simple_sec Simple API * * Use this if you develop your program in synchronous style and just * need a way to play or record data on the sound server. See * \subpage simple for more details. * * \section async_sec Asynchronous API * * Use this if you develop your programs in asynchronous, event loop * based style or if you want to use the advanced features of the * PulseAudio API. A guide can be found in \subpage async. * * By using the built-in threaded main loop, it is possible to achieve a * pseudo-synchronous API, which can be useful in synchronous applications * where the simple API is insufficient. See the \ref async page for * details. * * \section thread_sec Threads * * The PulseAudio client libraries are not designed to be directly * thread-safe. They are however designed to be reentrant and * threads-aware. * * To use the libraries in a threaded environment, you must assure that * all objects are only used in one thread at a time. Normally, this means * that all objects belonging to a single context must be accessed from the * same thread. * * The included main loop implementation is also not thread safe. Take care * to make sure event objects are not manipulated when any other code is * using the main loop. * * \section error_sec Error Handling * * Every function should explicitly document how errors are reported to * the caller. Unfortunately, currently a lot of that documentation is * missing. Here is an overview of the general conventions used. * * The PulseAudio API indicates error conditions by returning a negative * integer value or a NULL pointer. On success, zero or a positive integer * value or a valid pointer is returned. * * Functions of the \ref simple generally return -1 or NULL on failure and * can optionally store an error code (see ::pa_error_code) using a pointer * argument. * * Functions of the \ref async return an negative error code or NULL on * failure (see ::pa_error_code). In the later case, pa_context_errno() * can be used to obtain the error code of the last failed operation. * * An error code can be turned into a human readable message using * pa_strerror(). * * \section pkgconfig pkg-config * * The PulseAudio libraries provide pkg-config snippets for the different * modules: * * \li libpulse - The asynchronous API and the internal main loop implementation. * \li libpulse-mainloop-glib - GLIB 2.x main loop bindings. * \li libpulse-simple - The simple PulseAudio API. */ #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/rtclock.h000066400000000000000000000022531364710014100233610ustar00rootroot00000000000000#ifndef foortclockfoo #define foortclockfoo /*** This file is part of PulseAudio. Copyright 2004-2009 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include /** \file * Monotonic clock utilities. */ PA_C_DECL_BEGIN /** Return the current monotonic system time in usec, if such a clock * is available. If it is not available this will return the * wallclock time instead. \since 0.9.16 */ pa_usec_t pa_rtclock_now(void); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/sample.h000066400000000000000000000321641364710014100232050ustar00rootroot00000000000000#ifndef foosamplehfoo #define foosamplehfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include /** \page sample Sample Format Specifications * * \section overv_sec Overview * * PulseAudio is capable of handling a multitude of sample formats, rates * and channels, transparently converting and mixing them as needed. * * \section format_sec Sample Format * * PulseAudio supports the following sample formats: * * \li PA_SAMPLE_U8 - Unsigned 8 bit integer PCM. * \li PA_SAMPLE_S16LE - Signed 16 integer bit PCM, little endian. * \li PA_SAMPLE_S16BE - Signed 16 integer bit PCM, big endian. * \li PA_SAMPLE_FLOAT32LE - 32 bit IEEE floating point PCM, little endian. * \li PA_SAMPLE_FLOAT32BE - 32 bit IEEE floating point PCM, big endian. * \li PA_SAMPLE_ALAW - 8 bit a-Law. * \li PA_SAMPLE_ULAW - 8 bit mu-Law. * \li PA_SAMPLE_S32LE - Signed 32 bit integer PCM, little endian. * \li PA_SAMPLE_S32BE - Signed 32 bit integer PCM, big endian. * \li PA_SAMPLE_S24LE - Signed 24 bit integer PCM packed, little endian. * \li PA_SAMPLE_S24BE - Signed 24 bit integer PCM packed, big endian. * \li PA_SAMPLE_S24_32LE - Signed 24 bit integer PCM in LSB of 32 bit words, little endian. * \li PA_SAMPLE_S24_32BE - Signed 24 bit integer PCM in LSB of 32 bit words, big endian. * * The floating point sample formats have the range from -1.0 to 1.0. * * The sample formats that are sensitive to endianness have convenience * macros for native endian (NE), and reverse endian (RE). * * \section rate_sec Sample Rates * * PulseAudio supports any sample rate between 1 Hz and 192000 Hz. There is no * point trying to exceed the sample rate of the output device though as the * signal will only get downsampled, consuming CPU on the machine running the * server. * * \section chan_sec Channels * * PulseAudio supports up to 32 individual channels. The order of the * channels is up to the application, but they must be continuous. To map * channels to speakers, see \ref channelmap. * * \section calc_sec Calculations * * The PulseAudio library contains a number of convenience functions to do * calculations on sample formats: * * \li pa_bytes_per_second() - The number of bytes one second of audio will * take given a sample format. * \li pa_frame_size() - The size, in bytes, of one frame (i.e. one set of * samples, one for each channel). * \li pa_sample_size() - The size, in bytes, of one sample. * \li pa_bytes_to_usec() - Calculate the time it would take to play a buffer * of a certain size. * * \section util_sec Convenience Functions * * The library also contains a couple of other convenience functions: * * \li pa_sample_spec_valid() - Tests if a sample format specification is * valid. * \li pa_sample_spec_equal() - Tests if the sample format specifications are * identical. * \li pa_sample_format_to_string() - Return a textual description of a * sample format. * \li pa_parse_sample_format() - Parse a text string into a sample format. * \li pa_sample_spec_snprint() - Create a textual description of a complete * sample format specification. * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MiB). */ /** \file * Constants and routines for sample type handling * * See also \subpage sample */ PA_C_DECL_BEGIN #if !defined(WORDS_BIGENDIAN) #if defined(__BYTE_ORDER) #if __BYTE_ORDER == __BIG_ENDIAN #define WORDS_BIGENDIAN #endif #endif /* On Sparc, WORDS_BIGENDIAN needs to be set if _BIG_ENDIAN is defined. */ #if defined(__sparc__) && defined(_BIG_ENDIAN) #define WORDS_BIGENDIAN #endif #endif /** Maximum number of allowed channels */ #define PA_CHANNELS_MAX 32U /** Maximum allowed sample rate */ #define PA_RATE_MAX (48000U*4U) /** Sample format */ typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0 */ PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1.0 to 1.0 */ PA_SAMPLE_S32LE, /**< Signed 32 Bit PCM, little endian (PC) */ PA_SAMPLE_S32BE, /**< Signed 32 Bit PCM, big endian */ PA_SAMPLE_S24LE, /**< Signed 24 Bit PCM packed, little endian (PC). \since 0.9.15 */ PA_SAMPLE_S24BE, /**< Signed 24 Bit PCM packed, big endian. \since 0.9.15 */ PA_SAMPLE_S24_32LE, /**< Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC). \since 0.9.15 */ PA_SAMPLE_S24_32BE, /**< Signed 24 Bit PCM in LSB of 32 Bit words, big endian. \since 0.9.15 */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_INVALID = -1 /**< An invalid value */ } pa_sample_format_t; #ifdef WORDS_BIGENDIAN /** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE /** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE /** Signed 32 Bit PCM, native endian */ #define PA_SAMPLE_S32NE PA_SAMPLE_S32BE /** Signed 24 Bit PCM packed, native endian. \since 0.9.15 */ #define PA_SAMPLE_S24NE PA_SAMPLE_S24BE /** Signed 24 Bit PCM in LSB of 32 Bit words, native endian. \since 0.9.15 */ #define PA_SAMPLE_S24_32NE PA_SAMPLE_S24_32BE /** Signed 16 Bit PCM reverse endian */ #define PA_SAMPLE_S16RE PA_SAMPLE_S16LE /** 32 Bit IEEE floating point, reverse endian */ #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE /** Signed 32 Bit PCM, reverse endian */ #define PA_SAMPLE_S32RE PA_SAMPLE_S32LE /** Signed 24 Bit PCM, packed reverse endian. \since 0.9.15 */ #define PA_SAMPLE_S24RE PA_SAMPLE_S24LE /** Signed 24 Bit PCM, in LSB of 32 Bit words, reverse endian. \since 0.9.15 */ #define PA_SAMPLE_S24_32RE PA_SAMPLE_S24_32LE #else /** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE /** 32 Bit IEEE floating point, native endian */ #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE /** Signed 32 Bit PCM, native endian */ #define PA_SAMPLE_S32NE PA_SAMPLE_S32LE /** Signed 24 Bit PCM packed, native endian. \since 0.9.15 */ #define PA_SAMPLE_S24NE PA_SAMPLE_S24LE /** Signed 24 Bit PCM in LSB of 32 Bit words, native endian. \since 0.9.15 */ #define PA_SAMPLE_S24_32NE PA_SAMPLE_S24_32LE /** Signed 16 Bit PCM, reverse endian */ #define PA_SAMPLE_S16RE PA_SAMPLE_S16BE /** 32 Bit IEEE floating point, reverse endian */ #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE /** Signed 32 Bit PCM, reverse endian */ #define PA_SAMPLE_S32RE PA_SAMPLE_S32BE /** Signed 24 Bit PCM, packed reverse endian. \since 0.9.15 */ #define PA_SAMPLE_S24RE PA_SAMPLE_S24BE /** Signed 24 Bit PCM, in LSB of 32 Bit words, reverse endian. \since 0.9.15 */ #define PA_SAMPLE_S24_32RE PA_SAMPLE_S24_32BE #endif /** A Shortcut for PA_SAMPLE_FLOAT32NE */ #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE /** \cond fulldocs */ /* Allow clients to check with #ifdef for these sample formats */ #define PA_SAMPLE_U8 PA_SAMPLE_U8 #define PA_SAMPLE_ALAW PA_SAMPLE_ALAW #define PA_SAMPLE_ULAW PA_SAMPLE_ULAW #define PA_SAMPLE_S16LE PA_SAMPLE_S16LE #define PA_SAMPLE_S16BE PA_SAMPLE_S16BE #define PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32LE #define PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE #define PA_SAMPLE_S32LE PA_SAMPLE_S32LE #define PA_SAMPLE_S32BE PA_SAMPLE_S32BE #define PA_SAMPLE_S24LE PA_SAMPLE_S24LE #define PA_SAMPLE_S24BE PA_SAMPLE_S24BE #define PA_SAMPLE_S24_32LE PA_SAMPLE_S24_32LE #define PA_SAMPLE_S24_32BE PA_SAMPLE_S24_32BE /** \endcond */ /** A sample format and attribute specification */ typedef struct pa_sample_spec { pa_sample_format_t format; /**< The sample format */ uint32_t rate; /**< The sample rate. (e.g. 44100) */ uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ } pa_sample_spec; /** Type for usec specifications (unsigned). Always 64 bit. */ typedef uint64_t pa_usec_t; /** Return the amount of bytes playback of a second of audio with the specified sample type takes */ size_t pa_bytes_per_second(const pa_sample_spec *spec) PA_GCC_PURE; /** Return the size of a frame with the specific sample type */ size_t pa_frame_size(const pa_sample_spec *spec) PA_GCC_PURE; /** Return the size of a sample with the specific sample type */ size_t pa_sample_size(const pa_sample_spec *spec) PA_GCC_PURE; /** Similar to pa_sample_size() but take a sample format instead of a * full sample spec. \since 0.9.15 */ size_t pa_sample_size_of_format(pa_sample_format_t f) PA_GCC_PURE; /** Calculate the time the specified bytes take to play with the * specified sample type. The return value will always be rounded * down for non-integral return values. */ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) PA_GCC_PURE; /** Calculates the number of bytes that are required for the specified * time. The return value will always be rounded down for non-integral * return values. \since 0.9 */ size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) PA_GCC_PURE; /** Initialize the specified sample spec and return a pointer to * it. The sample spec will have a defined state but * pa_sample_spec_valid() will fail for it. \since 0.9.13 */ pa_sample_spec* pa_sample_spec_init(pa_sample_spec *spec); /** Return non-zero if the given integer is a valid sample format. \since 5.0 */ int pa_sample_format_valid(unsigned format) PA_GCC_PURE; /** Return non-zero if the rate is within the supported range. \since 5.0 */ int pa_sample_rate_valid(uint32_t rate) PA_GCC_PURE; /** Return non-zero if the channel count is within the supported range. * \since 5.0 */ int pa_channels_valid(uint8_t channels) PA_GCC_PURE; /** Return non-zero when the sample type specification is valid */ int pa_sample_spec_valid(const pa_sample_spec *spec) PA_GCC_PURE; /** Return non-zero when the two sample type specifications match */ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) PA_GCC_PURE; /** Return a descriptive string for the specified sample format. \since 0.8 */ const char *pa_sample_format_to_string(pa_sample_format_t f) PA_GCC_PURE; /** Parse a sample format text. Inverse of pa_sample_format_to_string() */ pa_sample_format_t pa_parse_sample_format(const char *format) PA_GCC_PURE; /** Maximum required string length for * pa_sample_spec_snprint(). Please note that this value can change * with any release without warning and without being considered API * or ABI breakage. You should not use this definition anywhere where * it might become part of an ABI. */ #define PA_SAMPLE_SPEC_SNPRINT_MAX 32 /** Pretty print a sample type specification to a string */ char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); /** Maximum required string length for pa_bytes_snprint(). Please note * that this value can change with any release without warning and * without being considered API or ABI breakage. You should not use * this definition anywhere where it might become part of an * ABI. \since 0.9.16 */ #define PA_BYTES_SNPRINT_MAX 11 /** Pretty print a byte size value (i.e.\ "2.5 MiB") */ char* pa_bytes_snprint(char *s, size_t l, unsigned v); /** Return 1 when the specified format is little endian, return -1 * when endianness does not apply to this format. \since 0.9.16 */ int pa_sample_format_is_le(pa_sample_format_t f) PA_GCC_PURE; /** Return 1 when the specified format is big endian, return -1 when * endianness does not apply to this format. \since 0.9.16 */ int pa_sample_format_is_be(pa_sample_format_t f) PA_GCC_PURE; #ifdef WORDS_BIGENDIAN #define pa_sample_format_is_ne(f) pa_sample_format_is_be(f) #define pa_sample_format_is_re(f) pa_sample_format_is_le(f) #else /** Return 1 when the specified format is native endian, return -1 * when endianness does not apply to this format. \since 0.9.16 */ #define pa_sample_format_is_ne(f) pa_sample_format_is_le(f) /** Return 1 when the specified format is reverse endian, return -1 * when endianness does not apply to this format. \since 0.9.16 */ #define pa_sample_format_is_re(f) pa_sample_format_is_be(f) #endif PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/scache.h000066400000000000000000000123661364710014100231540ustar00rootroot00000000000000#ifndef fooscachehfoo #define fooscachehfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include /** \page scache Sample Cache * * \section overv_sec Overview * * The sample cache provides a simple way of overcoming high network latencies * and reducing bandwidth. Instead of streaming a sound precisely when it * should be played, it is stored on the server and only the command to start * playing it needs to be sent. * * \section create_sec Creation * * To create a sample, the normal stream API is used (see \ref streams). The * function pa_stream_connect_upload() will make sure the stream is stored as * a sample on the server. * * To complete the upload, pa_stream_finish_upload() is called and the sample * will receive the same name as the stream. If the upload should be aborted, * simply call pa_stream_disconnect(). * * \section play_sec Playing samples * * To play back a sample, simply call pa_context_play_sample(): * * \code * pa_operation *o; * * o = pa_context_play_sample(my_context, * "sample2", // Name of my sample * NULL, // Use default sink * PA_VOLUME_NORM, // Full volume * NULL, // Don't need a callback * NULL * ); * if (o) * pa_operation_unref(o); * \endcode * * \section rem_sec Removing samples * * When a sample is no longer needed, it should be removed on the server to * save resources. The sample is deleted using pa_context_remove_sample(). */ /** \file * All sample cache related routines * * See also \subpage scache */ PA_C_DECL_BEGIN /** Callback prototype for pa_context_play_sample_with_proplist(). The * idx value is the index of the sink input object, or * PA_INVALID_INDEX on failure. \since 0.9.11 */ typedef void (*pa_context_play_sample_cb_t)(pa_context *c, uint32_t idx, void *userdata); /** Make this stream a sample upload stream */ int pa_stream_connect_upload(pa_stream *s, size_t length); /** Finish the sample upload, the stream name will become the sample * name. You cancel a sample upload by issuing * pa_stream_disconnect() */ int pa_stream_finish_upload(pa_stream *s); /** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); /** Play a sample from the sample cache to the specified device. If * the latter is NULL use the default sink. Returns an operation * object */ pa_operation* pa_context_play_sample( pa_context *c /**< Context */, const char *name /**< Name of the sample to play */, const char *dev /**< Sink to play this sample on */, pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here PA_VOLUME_INVALID which will leave the decision about the volume to the server side which is a good idea. */ , pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */, void *userdata /**< Userdata to pass to the callback */); /** Play a sample from the sample cache to the specified device, * allowing specification of a property list for the playback * stream. If the latter is NULL use the default sink. Returns an * operation object. \since 0.9.11 */ pa_operation* pa_context_play_sample_with_proplist( pa_context *c /**< Context */, const char *name /**< Name of the sample to play */, const char *dev /**< Sink to play this sample on */, pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here PA_VOLUME_INVALID which will leave the decision about the volume to the server side which is a good idea. */ , pa_proplist *proplist /**< Property list for this sound. The property list of the cached entry will be merged into this property list */, pa_context_play_sample_cb_t cb /**< Call this function after successfully starting playback, or NULL */, void *userdata /**< Userdata to pass to the callback */); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/simple.h000066400000000000000000000136301364710014100232120ustar00rootroot00000000000000#ifndef foosimplehfoo #define foosimplehfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include /** \page simple Simple API * * \section overv_sec Overview * * The simple API is designed for applications with very basic sound * playback or capture needs. It can only support a single stream per * connection and has no support for handling of complex features like * events, channel mappings and volume control. It is, however, very simple * to use and quite sufficient for many programs. * * \section conn_sec Connecting * * The first step before using the sound system is to connect to the * server. This is normally done this way: * * \code * pa_simple *s; * pa_sample_spec ss; * * ss.format = PA_SAMPLE_S16NE; * ss.channels = 2; * ss.rate = 44100; * * s = pa_simple_new(NULL, // Use the default server. * "Fooapp", // Our application's name. * PA_STREAM_PLAYBACK, * NULL, // Use the default device. * "Music", // Description of our stream. * &ss, // Our sample format. * NULL, // Use default channel map * NULL, // Use default buffering attributes. * NULL, // Ignore error code. * ); * \endcode * * At this point a connected object is returned, or NULL if there was a * problem connecting. * * \section transfer_sec Transferring data * * Once the connection is established to the server, data can start flowing. * Using the connection is very similar to the normal read() and write() * system calls. The main difference is that they're called pa_simple_read() * and pa_simple_write(). Note that these operations always block. * * \section ctrl_sec Buffer control * * \li pa_simple_get_latency() - Will return the total latency of * the playback or record pipeline, respectively. * \li pa_simple_flush() - Will throw away all data currently in buffers. * * If a playback stream is used then the following operation is available: * * \li pa_simple_drain() - Will wait for all sent data to finish playing. * * \section cleanup_sec Cleanup * * Once playback or capture is complete, the connection should be closed * and resources freed. This is done through: * * \code * pa_simple_free(s); * \endcode */ /** \file * A simple but limited synchronous playback and recording * API. This is a synchronous, simplified wrapper around the standard * asynchronous API. * * See also \subpage simple */ /** \example pacat-simple.c * A simple playback tool using the simple API */ /** \example parec-simple.c * A simple recording tool using the simple API */ PA_C_DECL_BEGIN /** \struct pa_simple * An opaque simple connection object */ typedef struct pa_simple pa_simple; /** Create a new connection to the server. */ pa_simple* pa_simple_new( const char *server, /**< Server name, or NULL for default */ const char *name, /**< A descriptive name for this client (application name, ...) */ pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ const char *dev, /**< Sink (resp. source) name, or NULL for default */ const char *stream_name, /**< A descriptive name for this stream (application name, song title, ...) */ const pa_sample_spec *ss, /**< The sample type to use */ const pa_channel_map *map, /**< The channel map to use, or NULL for default */ const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ ); /** Close and free the connection to the server. The connection object becomes invalid when this is called. */ void pa_simple_free(pa_simple *s); /** Write some data to the server. */ int pa_simple_write(pa_simple *s, const void *data, size_t bytes, int *error); /** Wait until all data already written is played by the daemon. */ int pa_simple_drain(pa_simple *s, int *error); /** Read some data from the server. This function blocks until \a bytes amount * of data has been received from the server, or until an error occurs. * Returns a negative value on failure. */ int pa_simple_read( pa_simple *s, /**< The connection object. */ void *data, /**< A pointer to a buffer. */ size_t bytes, /**< The number of bytes to read. */ int *error /**< A pointer where the error code is stored when the function returns * a negative value. It is OK to pass NULL here. */ ); /** Return the playback or record latency. */ pa_usec_t pa_simple_get_latency(pa_simple *s, int *error); /** Flush the playback or record buffer. This discards any audio in the buffer. */ int pa_simple_flush(pa_simple *s, int *error); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/stream.h000066400000000000000000001227031364710014100232160ustar00rootroot00000000000000#ifndef foostreamhfoo #define foostreamhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include #include #include #include #include /** \page streams Audio Streams * * \section overv_sec Overview * * Audio streams form the central functionality of the sound server. Data is * routed, converted and mixed from several sources before it is passed along * to a final output. Currently, there are three forms of audio streams: * * \li Playback streams - Data flows from the client to the server. * \li Record streams - Data flows from the server to the client. * \li Upload streams - Similar to playback streams, but the data is stored in * the sample cache. See \ref scache for more information * about controlling the sample cache. * * \section create_sec Creating * * To access a stream, a pa_stream object must be created using * pa_stream_new() or pa_stream_new_extended(). pa_stream_new() is for PCM * streams only, while pa_stream_new_extended() can be used for both PCM and * compressed audio streams. At this point the application must specify what * stream format(s) it supports. See \ref sample and \ref channelmap for more * information on the stream format parameters. FIXME: Those references only * talk about PCM parameters, we should also have an overview page for how the * pa_format_info based stream format configuration works. Bug filed: * https://bugs.freedesktop.org/show_bug.cgi?id=72265 * * This first step will only create a client-side object, representing the * stream. To use the stream, a server-side object must be created and * associated with the local object. Depending on which type of stream is * desired, a different function is needed: * * \li Playback stream - pa_stream_connect_playback() * \li Record stream - pa_stream_connect_record() * \li Upload stream - pa_stream_connect_upload() (see \ref scache) * * Similar to how connections are done in contexts, connecting a stream will * not generate a pa_operation object. Also like contexts, the application * should register a state change callback, using * pa_stream_set_state_callback(), and wait for the stream to enter an active * state. * * Note: there is a user-controllable slider in mixer applications such as * pavucontrol corresponding to each of the created streams. Multiple * (especially identically named) volume sliders for the same application might * confuse the user. Also, the server supports only a limited number of * simultaneous streams. Because of this, it is not always appropriate to * create multiple streams in one application that needs to output multiple * sounds. The rough guideline is: if there is no use case that would require * separate user-initiated volume changes for each stream, perform the mixing * inside the application. * * \subsection bufattr_subsec Buffer Attributes * * Playback and record streams always have a server-side buffer as * part of the data flow. The size of this buffer needs to be chosen * in a compromise between low latency and sensitivity for buffer * overflows/underruns. * * The buffer metrics may be controlled by the application. They are * described with a pa_buffer_attr structure which contains a number * of fields: * * \li maxlength - The absolute maximum number of bytes that can be * stored in the buffer. If this value is exceeded * then data will be lost. It is recommended to pass * (uint32_t) -1 here which will cause the server to * fill in the maximum possible value. * * \li tlength - The target fill level of the playback buffer. The * server will only send requests for more data as long * as the buffer has less than this number of bytes of * data. If you pass (uint32_t) -1 (which is * recommended) here the server will choose the longest * target buffer fill level possible to minimize the * number of necessary wakeups and maximize drop-out * safety. This can exceed 2s of buffering. For * low-latency applications or applications where * latency matters you should pass a proper value here. * * \li prebuf - Number of bytes that need to be in the buffer before * playback will commence. Start of playback can be * forced using pa_stream_trigger() even though the * prebuffer size hasn't been reached. If a buffer * underrun occurs, this prebuffering will be again * enabled. If the playback shall never stop in case of a * buffer underrun, this value should be set to 0. In * that case the read index of the output buffer * overtakes the write index, and hence the fill level of * the buffer is negative. If you pass (uint32_t) -1 here * (which is recommended) the server will choose the same * value as tlength here. * * \li minreq - Minimum number of free bytes in the playback * buffer before the server will request more data. It is * recommended to fill in (uint32_t) -1 here. This value * influences how much time the sound server has to move * data from the per-stream server-side playback buffer * to the hardware playback buffer. * * \li fragsize - Maximum number of bytes that the server will push in * one chunk for record streams. If you pass (uint32_t) * -1 (which is recommended) here, the server will * choose the longest fragment setting possible to * minimize the number of necessary wakeups and * maximize drop-out safety. This can exceed 2s of * buffering. For low-latency applications or * applications where latency matters you should pass a * proper value here. * * If PA_STREAM_ADJUST_LATENCY is set, then the tlength/fragsize * parameters will be interpreted slightly differently than described * above when passed to pa_stream_connect_record() and * pa_stream_connect_playback(): the overall latency that is comprised * of both the server side playback buffer length, the hardware * playback buffer length and additional latencies will be adjusted in * a way that it matches tlength resp. fragsize. Set * PA_STREAM_ADJUST_LATENCY if you want to control the overall * playback latency for your stream. Unset it if you want to control * only the latency induced by the server-side, rewritable playback * buffer. The server will try to fulfill the client's latency requests * as good as possible. However if the underlying hardware cannot * change the hardware buffer length or only in a limited range, the * actually resulting latency might be different from what the client * requested. Thus, for synchronization clients always need to check * the actual measured latency via pa_stream_get_latency() or a * similar call, and not make any assumptions about the latency * available. The function pa_stream_get_buffer_attr() will always * return the actual size of the server-side per-stream buffer in * tlength/fragsize, regardless whether PA_STREAM_ADJUST_LATENCY is * set or not. * * The server-side per-stream playback buffers are indexed by a write and a read * index. The application writes to the write index and the sound * device reads from the read index. The read index is increased * monotonically, while the write index may be freely controlled by * the application. Subtracting the read index from the write index * will give you the current fill level of the buffer. The read/write * indexes are 64bit values and measured in bytes, they will never * wrap. The current read/write index may be queried using * pa_stream_get_timing_info() (see below for more information). In * case of a buffer underrun the read index is equal or larger than * the write index. Unless the prebuf value is 0, PulseAudio will * temporarily pause playback in such a case, and wait until the * buffer is filled up to prebuf bytes again. If prebuf is 0, the * read index may be larger than the write index, in which case * silence is played. If the application writes data to indexes lower * than the read index, the data is immediately lost. * * \section transfer_sec Transferring Data * * Once the stream is up, data can start flowing between the client and the * server. Two different access models can be used to transfer the data: * * \li Asynchronous - The application register a callback using * pa_stream_set_write_callback() and * pa_stream_set_read_callback() to receive notifications * that data can either be written or read. * \li Polled - Query the library for available data/space using * pa_stream_writable_size() and pa_stream_readable_size() and * transfer data as needed. The sizes are stored locally, in the * client end, so there is no delay when reading them. * * It is also possible to mix the two models freely. * * Once there is data/space available, it can be transferred using either * pa_stream_write() for playback, or pa_stream_peek() / pa_stream_drop() for * record. Make sure you do not overflow the playback buffers as data will be * dropped. * * \section bufctl_sec Buffer Control * * The transfer buffers can be controlled through a number of operations: * * \li pa_stream_cork() - Start or stop the playback or recording. * \li pa_stream_trigger() - Start playback immediately and do not wait for * the buffer to fill up to the set trigger level. * \li pa_stream_prebuf() - Reenable the playback trigger level. * \li pa_stream_drain() - Wait for the playback buffer to go empty. Will * return a pa_operation object that will indicate when * the buffer is completely drained. * \li pa_stream_flush() - Drop all data from the playback or record buffer. Do not * wait for it to finish playing. * * \section seek_modes Seeking in the Playback Buffer * * A client application may freely seek in the playback buffer. To * accomplish that the pa_stream_write() function takes a seek mode * and an offset argument. The seek mode is one of: * * \li PA_SEEK_RELATIVE - seek relative to the current write index * \li PA_SEEK_ABSOLUTE - seek relative to the beginning of the playback buffer, (i.e. the first that was ever played in the stream) * \li PA_SEEK_RELATIVE_ON_READ - seek relative to the current read index. Use this to write data to the output buffer that should be played as soon as possible * \li PA_SEEK_RELATIVE_END - seek relative to the last byte ever written. * * If an application just wants to append some data to the output * buffer, PA_SEEK_RELATIVE and an offset of 0 should be used. * * After a call to pa_stream_write() the write index will be left at * the position right after the last byte of the written data. * * \section latency_sec Latency * * A major problem with networked audio is the increased latency caused by * the network. To remedy this, PulseAudio supports an advanced system of * monitoring the current latency. * * To get the raw data needed to calculate latencies, call * pa_stream_get_timing_info(). This will give you a pa_timing_info * structure that contains everything that is known about the server * side buffer transport delays and the backend active in the * server. (Besides other things it contains the write and read index * values mentioned above.) * * This structure is updated every time a * pa_stream_update_timing_info() operation is executed. (i.e. before * the first call to this function the timing information structure is * not available!) Since it is a lot of work to keep this structure * up-to-date manually, PulseAudio can do that automatically for you: * if PA_STREAM_AUTO_TIMING_UPDATE is passed when connecting the * stream PulseAudio will automatically update the structure every * 100ms and every time a function is called that might invalidate the * previously known timing data (such as pa_stream_write() or * pa_stream_flush()). Please note however, that there always is a * short time window when the data in the timing information structure * is out-of-date. PulseAudio tries to mark these situations by * setting the write_index_corrupt and read_index_corrupt fields * accordingly. * * The raw timing data in the pa_timing_info structure is usually hard * to deal with. Therefore a simpler interface is available: * you can call pa_stream_get_time() or pa_stream_get_latency(). The * former will return the current playback time of the hardware since * the stream has been started. The latter returns the overall time a sample * that you write now takes to be played by the hardware. These two * functions base their calculations on the same data that is returned * by pa_stream_get_timing_info(). Hence the same rules for keeping * the timing data up-to-date apply here. In case the write or read * index is corrupted, these two functions will fail with * -PA_ERR_NODATA set. * * Since updating the timing info structure usually requires a full * network round trip and some applications monitor the timing very * often PulseAudio offers a timing interpolation system. If * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, * pa_stream_get_time() and pa_stream_get_latency() will try to * interpolate the current playback time/latency by estimating the * number of samples that have been played back by the hardware since * the last regular timing update. It is especially useful to combine * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable * you to monitor the current playback time/latency very precisely and * very frequently without requiring a network round trip every time. * * \section flow_sec Overflow and underflow * * Even with the best precautions, buffers will sometime over - or * underflow. To handle this gracefully, the application can be * notified when this happens. Callbacks are registered using * pa_stream_set_overflow_callback() and * pa_stream_set_underflow_callback(). * * \section sync_streams Synchronizing Multiple Playback Streams * * PulseAudio allows applications to fully synchronize multiple * playback streams that are connected to the same output device. That * means the streams will always be played back sample-by-sample * synchronously. If stream operations like pa_stream_cork() are * issued on one of the synchronized streams, they are simultaneously * issued on the others. * * To synchronize a stream to another, just pass the "master" stream * as last argument to pa_stream_connect_playback(). To make sure that * the freshly created stream doesn't start playback right-away, make * sure to pass PA_STREAM_START_CORKED and -- after all streams have * been created -- uncork them all with a single call to * pa_stream_cork() for the master stream. * * To make sure that a particular stream doesn't stop to play when a * server side buffer underrun happens on it while the other * synchronized streams continue playing and hence deviate, you need to * pass a "prebuf" pa_buffer_attr of 0 when connecting it. * * \section disc_sec Disconnecting * * When a stream has served is purpose it must be disconnected with * pa_stream_disconnect(). If you only unreference it, then it will live on * and eat resources both locally and on the server until you disconnect the * context. * */ /** \file * Audio streams for input, output and sample upload * * See also \subpage streams */ PA_C_DECL_BEGIN /** An opaque stream for playback or recording */ typedef struct pa_stream pa_stream; /** A generic callback for operation completion */ typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); /** A generic request callback */ typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t nbytes, void *userdata); /** A generic notification callback */ typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); /** A callback for asynchronous meta/policy event messages. Well known * event names are PA_STREAM_EVENT_REQUEST_CORK and * PA_STREAM_EVENT_REQUEST_UNCORK. The set of defined events can be * extended at any time. Also, server modules may introduce additional * message types so make sure that your callback function ignores messages * it doesn't know. \since 0.9.15 */ typedef void (*pa_stream_event_cb_t)(pa_stream *p, const char *name, pa_proplist *pl, void *userdata); /** Create a new, unconnected stream with the specified name and * sample type. It is recommended to use pa_stream_new_with_proplist() * instead and specify some initial properties. */ pa_stream* pa_stream_new( pa_context *c /**< The context to create this stream in */, const char *name /**< A name for this stream */, const pa_sample_spec *ss /**< The desired sample format */, const pa_channel_map *map /**< The desired channel map, or NULL for default */); /** Create a new, unconnected stream with the specified name and * sample type, and specify the initial stream property * list. \since 0.9.11 */ pa_stream* pa_stream_new_with_proplist( pa_context *c /**< The context to create this stream in */, const char *name /**< A name for this stream */, const pa_sample_spec *ss /**< The desired sample format */, const pa_channel_map *map /**< The desired channel map, or NULL for default */, pa_proplist *p /**< The initial property list */); /** Create a new, unconnected stream with the specified name, the set of formats * this client can provide, and an initial list of properties. While * connecting, the server will select the most appropriate format which the * client must then provide. \since 1.0 */ pa_stream *pa_stream_new_extended( pa_context *c /**< The context to create this stream in */, const char *name /**< A name for this stream */, pa_format_info * const * formats /**< The list of formats that can be provided */, unsigned int n_formats /**< The number of formats being passed in */, pa_proplist *p /**< The initial property list */); /** Decrease the reference counter by one. */ void pa_stream_unref(pa_stream *s); /** Increase the reference counter by one. */ pa_stream *pa_stream_ref(pa_stream *s); /** Return the current state of the stream. */ pa_stream_state_t pa_stream_get_state(pa_stream *p); /** Return the context this stream is attached to. */ pa_context* pa_stream_get_context(pa_stream *p); /** Return the sink input resp.\ source output index this stream is * identified in the server with. This is useful with the * introspection functions such as pa_context_get_sink_input_info() * or pa_context_get_source_output_info(). */ uint32_t pa_stream_get_index(pa_stream *s); /** Return the index of the sink or source this stream is connected to * in the server. This is useful with the introspection * functions such as pa_context_get_sink_info_by_index() or * pa_context_get_source_info_by_index(). * * Please note that streams may be moved between sinks/sources and thus * it is recommended to use pa_stream_set_moved_callback() to be notified * about this. This function will return with -PA_ERR_NOTSUPPORTED when the * server is older than 0.9.8. \since 0.9.8 */ uint32_t pa_stream_get_device_index(pa_stream *s); /** Return the name of the sink or source this stream is connected to * in the server. This is useful with the introspection * functions such as pa_context_get_sink_info_by_name() * or pa_context_get_source_info_by_name(). * * Please note that streams may be moved between sinks/sources and thus * it is recommended to use pa_stream_set_moved_callback() to be notified * about this. This function will return with -PA_ERR_NOTSUPPORTED when the * server is older than 0.9.8. \since 0.9.8 */ const char *pa_stream_get_device_name(pa_stream *s); /** Return 1 if the sink or source this stream is connected to has * been suspended. This will return 0 if not, and a negative value on * error. This function will return with -PA_ERR_NOTSUPPORTED when the * server is older than 0.9.8. \since 0.9.8 */ int pa_stream_is_suspended(pa_stream *s); /** Return 1 if the this stream has been corked. This will return 0 if * not, and a negative value on error. \since 0.9.11 */ int pa_stream_is_corked(pa_stream *s); /** Connect the stream to a sink. It is strongly recommended to pass * NULL in both \a dev and \a volume and to set neither * PA_STREAM_START_MUTED nor PA_STREAM_START_UNMUTED -- unless these * options are directly dependent on user input or configuration. * * If you follow this rule then the sound server will have the full * flexibility to choose the device, volume and mute status * automatically, based on server-side policies, heuristics and stored * information from previous uses. Also the server may choose to * reconfigure audio devices to make other sinks/sources or * capabilities available to be able to accept the stream. * * Before 0.9.20 it was not defined whether the \a volume parameter was * interpreted relative to the sink's current volume or treated as * an absolute device volume. Since 0.9.20 it is an absolute volume when * the sink is in flat volume mode, and relative otherwise, thus * making sure the volume passed here has always the same semantics as * the volume passed to pa_context_set_sink_input_volume(). It is possible * to figure out whether flat volume mode is in effect for a given sink * by calling pa_context_get_sink_info_by_name(). * * Since 5.0, it's possible to specify a single-channel volume even if the * stream has multiple channels. In that case the same volume is applied to all * channels. */ int pa_stream_connect_playback( pa_stream *s /**< The stream to connect to a sink */, const char *dev /**< Name of the sink to connect to, or NULL for default */ , const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, pa_stream_flags_t flags /**< Additional flags, or 0 for default */, const pa_cvolume *volume /**< Initial volume, or NULL for default */, pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream */); /** Connect the stream to a source. */ int pa_stream_connect_record( pa_stream *s /**< The stream to connect to a source */ , const char *dev /**< Name of the source to connect to, or NULL for default */, const pa_buffer_attr *attr /**< Buffer attributes, or NULL for default */, pa_stream_flags_t flags /**< Additional flags, or 0 for default */); /** Disconnect a stream from a source/sink. */ int pa_stream_disconnect(pa_stream *s); /** Prepare writing data to the server (for playback streams). This * function may be used to optimize the number of memory copies when * doing playback ("zero-copy"). It is recommended to call this * function before each call to pa_stream_write(). * * Pass in the address to a pointer and an address of the number of * bytes you want to write. On return the two values will contain a * pointer where you can place the data to write and the maximum number * of bytes you can write. \a *nbytes can be smaller or have the same * value as you passed in. You need to be able to handle both cases. * Accessing memory beyond the returned \a *nbytes value is invalid. * Accessing the memory returned after the following pa_stream_write() * or pa_stream_cancel_write() is invalid. * * On invocation only \a *nbytes needs to be initialized, on return both * *data and *nbytes will be valid. If you place (size_t) -1 in *nbytes * on invocation the memory size will be chosen automatically (which is * recommended to do). After placing your data in the memory area * returned, call pa_stream_write() with \a data set to an address * within this memory area and an \a nbytes value that is smaller or * equal to what was returned by this function to actually execute the * write. * * An invocation of pa_stream_write() should follow "quickly" on * pa_stream_begin_write(). It is not recommended letting an unbounded * amount of time pass after calling pa_stream_begin_write() and * before calling pa_stream_write(). If you want to cancel a * previously called pa_stream_begin_write() without calling * pa_stream_write() use pa_stream_cancel_write(). Calling * pa_stream_begin_write() twice without calling pa_stream_write() or * pa_stream_cancel_write() in between will return exactly the same * \a data pointer and \a nbytes values. \since 0.9.16 */ int pa_stream_begin_write( pa_stream *p, void **data, size_t *nbytes); /** Reverses the effect of pa_stream_begin_write() dropping all data * that has already been placed in the memory area returned by * pa_stream_begin_write(). Only valid to call if * pa_stream_begin_write() was called before and neither * pa_stream_cancel_write() nor pa_stream_write() have been called * yet. Accessing the memory previously returned by * pa_stream_begin_write() after this call is invalid. Any further * explicit freeing of the memory area is not necessary. \since * 0.9.16 */ int pa_stream_cancel_write( pa_stream *p); /** Write some data to the server (for playback streams). * If \a free_cb is non-NULL this routine is called when all data has * been written out. An internal reference to the specified data is * kept, the data is not copied. If NULL, the data is copied into an * internal buffer. * * The client may freely seek around in the output buffer. For * most applications it is typical to pass 0 and PA_SEEK_RELATIVE * as values for the arguments \a offset and \a seek. After the write * call succeeded the write index will be at the position after where * this chunk of data has been written to. * * As an optimization for avoiding needless memory copies you may call * pa_stream_begin_write() before this call and then place your audio * data directly in the memory area returned by that call. Then, pass * a pointer to that memory area to pa_stream_write(). After the * invocation of pa_stream_write() the memory area may no longer be * accessed. Any further explicit freeing of the memory area is not * necessary. It is OK to write the memory area returned by * pa_stream_begin_write() only partially with this call, skipping * bytes both at the end and at the beginning of the reserved memory * area.*/ int pa_stream_write( pa_stream *p /**< The stream to use */, const void *data /**< The data to write */, size_t nbytes /**< The length of the data to write in bytes */, pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */, int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); /** Read the next fragment from the buffer (for recording streams). * If there is data at the current read index, \a data will point to * the actual data and \a nbytes will contain the size of the data in * bytes (which can be less or more than a complete fragment). * * If there is no data at the current read index, it means that either * the buffer is empty or it contains a hole (that is, the write index * is ahead of the read index but there's no data where the read index * points at). If the buffer is empty, \a data will be NULL and * \a nbytes will be 0. If there is a hole, \a data will be NULL and * \a nbytes will contain the length of the hole. * * Use pa_stream_drop() to actually remove the data from the buffer * and move the read index forward. pa_stream_drop() should not be * called if the buffer is empty, but it should be called if there is * a hole. */ int pa_stream_peek( pa_stream *p /**< The stream to use */, const void **data /**< Pointer to pointer that will point to data */, size_t *nbytes /**< The length of the data read in bytes */); /** Remove the current fragment on record streams. It is invalid to do this without first * calling pa_stream_peek(). */ int pa_stream_drop(pa_stream *p); /** Return the number of bytes that may be written using pa_stream_write(). */ size_t pa_stream_writable_size(pa_stream *p); /** Return the number of bytes that may be read using pa_stream_peek(). */ size_t pa_stream_readable_size(pa_stream *p); /** Drain a playback stream. Use this for notification when the * playback buffer is empty after playing all the audio in the buffer. * Please note that only one drain operation per stream may be issued * at a time. */ pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Request a timing info structure update for a stream. Use * pa_stream_get_timing_info() to get access to the raw timing data, * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned * up values. */ pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); /** Set the callback function that is called whenever the state of the stream changes. */ void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called when new data may be * written to the stream. */ void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); /** Set the callback function that is called when new data is available from the stream. */ void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); /** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) */ void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Return at what position the latest underflow occurred, or -1 if this information is not * known (e.g.\ if no underflow has occurred, or server is older than 1.0). * Can be used inside the underflow callback to get information about the current underflow. * (Only for playback streams) \since 1.0 */ int64_t pa_stream_get_underflow_index(pa_stream *p); /** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) */ void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called when a the server starts * playback after an underrun or on initial startup. This only informs * that audio is flowing again, it is no indication that audio started * to reach the speakers already. (Only for playback streams) \since * 0.9.11 */ void pa_stream_set_started_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called whenever a latency * information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE * streams only. (Only for playback streams) */ void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called whenever the stream is * moved to a different sink/source. Use pa_stream_get_device_name() or * pa_stream_get_device_index() to query the new sink/source. This * notification is only generated when the server is at least * 0.9.8. \since 0.9.8 */ void pa_stream_set_moved_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called whenever the sink/source * this stream is connected to is suspended or resumed. Use * pa_stream_is_suspended() to query the new suspend status. Please * note that the suspend status might also change when the stream is * moved between devices. Thus if you call this function you very * likely want to call pa_stream_set_moved_callback() too. This * notification is only generated when the server is at least * 0.9.8. \since 0.9.8 */ void pa_stream_set_suspended_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Set the callback function that is called whenever a meta/policy * control event is received. \since 0.9.15 */ void pa_stream_set_event_callback(pa_stream *p, pa_stream_event_cb_t cb, void *userdata); /** Set the callback function that is called whenever the buffer * attributes on the server side change. Please note that the buffer * attributes can change when moving a stream to a different * sink/source too, hence if you use this callback you should use * pa_stream_set_moved_callback() as well. \since 0.9.15 */ void pa_stream_set_buffer_attr_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); /** Pause (or resume) playback of this stream temporarily. Available * on both playback and recording streams. If \a b is 1 the stream is * paused. If \a b is 0 the stream is resumed. The pause/resume operation * is executed as quickly as possible. If a cork is very quickly * followed by an uncork or the other way round, this might not * actually have any effect on the stream that is output. You can use * pa_stream_is_corked() to find out whether the stream is currently * paused or not. Normally a stream will be created in uncorked * state. If you pass PA_STREAM_START_CORKED as a flag when connecting * the stream, it will be created in corked state. */ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); /** Flush the playback or record buffer of this stream. This discards any audio data * in the buffer. Most of the time you're better off using the parameter * \a seek of pa_stream_write() instead of this function. */ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Reenable prebuffering if specified in the pa_buffer_attr * structure. Available for playback streams only. */ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Request immediate start of playback on this stream. This disables * prebuffering temporarily if specified in the pa_buffer_attr structure. * Available for playback streams only. */ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Rename the stream. */ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); /** Return the current playback/recording time. This is based on the * data in the timing info structure returned by * pa_stream_get_timing_info(). * * This function will usually only return new data if a timing info * update has been received. Only if timing interpolation has been * requested (PA_STREAM_INTERPOLATE_TIMING) the data from the last * timing update is used for an estimation of the current * playback/recording time based on the local time that passed since * the timing info structure has been acquired. * * The time value returned by this function is guaranteed to increase * monotonically (the returned value is always greater * or equal to the value returned by the last call). This behaviour * can be disabled by using PA_STREAM_NOT_MONOTONIC. This may be * desirable to better deal with bad estimations of transport * latencies, but may have strange effects if the application is not * able to deal with time going 'backwards'. * * The time interpolator activated by PA_STREAM_INTERPOLATE_TIMING * favours 'smooth' time graphs over accurate ones to improve the * smoothness of UI operations that are tied to the audio clock. If * accuracy is more important to you, you might need to estimate your * timing based on the data from pa_stream_get_timing_info() yourself * or not work with interpolated timing at all and instead always * query the server side for the most up to date timing with * pa_stream_update_timing_info(). * * If no timing information has been * received yet this call will return -PA_ERR_NODATA. For more details * see pa_stream_get_timing_info(). */ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec); /** Determine the total stream latency. This function is based on * pa_stream_get_time(). * * The latency is stored in \a *r_usec. In case the stream is a * monitoring stream the result can be negative, i.e. the captured * samples are not yet played. In this case \a *negative is set to 1. * * If no timing information has been received yet, this call will * return -PA_ERR_NODATA. On success, it will return 0. * * For more details see pa_stream_get_timing_info() and * pa_stream_get_time(). */ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative); /** Return the latest raw timing data structure. The returned pointer * refers to an internal read-only instance of the timing * structure. The user should make a copy of this structure if he * wants to modify it. An in-place update to this data structure may * be requested using pa_stream_update_timing_info(). * * If no timing information has been received before (i.e. by * requesting pa_stream_update_timing_info() or by using * PA_STREAM_AUTO_TIMING_UPDATE), this function will fail with * -PA_ERR_NODATA. * * Please note that the write_index member field (and only this field) * is updated on each pa_stream_write() call, not just when a timing * update has been received. */ const pa_timing_info* pa_stream_get_timing_info(pa_stream *s); /** Return a pointer to the stream's sample specification. */ const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); /** Return a pointer to the stream's channel map. */ const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); /** Return a pointer to the stream's format. \since 1.0 */ const pa_format_info* pa_stream_get_format_info(pa_stream *s); /** Return the per-stream server-side buffer metrics of the * stream. Only valid after the stream has been connected successfully * and if the server is at least PulseAudio 0.9. This will return the * actual configured buffering metrics, which may differ from what was * requested during pa_stream_connect_record() or * pa_stream_connect_playback(). This call will always return the * actual per-stream server-side buffer metrics, regardless whether * PA_STREAM_ADJUST_LATENCY is set or not. \since 0.9.0 */ const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); /** Change the buffer metrics of the stream during playback. The * server might have chosen different buffer metrics then * requested. The selected metrics may be queried with * pa_stream_get_buffer_attr() as soon as the callback is called. Only * valid after the stream has been connected successfully and if the * server is at least PulseAudio 0.9.8. Please be aware of the * slightly different semantics of the call depending whether * PA_STREAM_ADJUST_LATENCY is set or not. \since 0.9.8 */ pa_operation *pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata); /** Change the stream sampling rate during playback. You need to pass * PA_STREAM_VARIABLE_RATE in the flags parameter of * pa_stream_connect_playback() if you plan to use this function. Only valid * after the stream has been connected successfully and if the server * is at least PulseAudio 0.9.8. \since 0.9.8 */ pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata); /** Update the property list of the sink input/source output of this * stream, adding new entries. Please note that it is highly * recommended to set as many properties initially via * pa_stream_new_with_proplist() as possible instead a posteriori with * this function, since that information may be used to route * this stream to the right device. \since 0.9.11 */ pa_operation *pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata); /** Update the property list of the sink input/source output of this * stream, remove entries. \since 0.9.11 */ pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata); /** For record streams connected to a monitor source: monitor only a * very specific sink input of the sink. This function needs to be * called before pa_stream_connect_record() is called. \since * 0.9.11 */ int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx); /** Return the sink input index previously set with * pa_stream_set_monitor_stream(). * \since 0.9.11 */ uint32_t pa_stream_get_monitor_stream(pa_stream *s); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/subscribe.h000066400000000000000000000060751364710014100237070ustar00rootroot00000000000000#ifndef foosubscribehfoo #define foosubscribehfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include /** \page subscribe Event Subscription * * \section overv_sec Overview * * The application can be notified, asynchronously, whenever the internal * layout of the server changes. Possible notifications are described in the * \ref pa_subscription_event_type and \ref pa_subscription_mask * enumerations. * * The application sets the notification mask using pa_context_subscribe() * and the function that will be called whenever a notification occurs using * pa_context_set_subscribe_callback(). * * The callback will be called with a \ref pa_subscription_event_type_t * representing the event that caused the callback. Clients can examine what * object changed using \ref PA_SUBSCRIPTION_EVENT_FACILITY_MASK. The actual * event type can then be extracted with \ref PA_SUBSCRIPTION_EVENT_TYPE_MASK. * Please note that the masked values are integers, not flags (so you will * check the object/event type using a comparison not a binary AND). For * example, the callback might look something like: * @verbatim void my_subscription_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) { if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { ... a source was added, let's do stuff! ... } } } @endverbatim */ /** \file * Daemon introspection event subscription subsystem. * * See also \subpage subscribe */ PA_C_DECL_BEGIN /** Subscription event callback prototype */ typedef void (*pa_context_subscribe_cb_t)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); /** Enable event notification */ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); /** Set the context specific call back function that is called whenever the state of the daemon changes */ void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/thread-mainloop.h000066400000000000000000000274361364710014100250150ustar00rootroot00000000000000#ifndef foothreadmainloophfoo #define foothreadmainloophfoo /*** This file is part of PulseAudio. Copyright 2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include PA_C_DECL_BEGIN /** \page threaded_mainloop Threaded Main Loop * * \section overv_sec Overview * * The threaded main loop implementation is a special version of the primary * main loop implementation (see \ref mainloop). For the basic design, see * its documentation. * * The added feature in the threaded main loop is that it spawns a new thread * that runs the real main loop. This allows a synchronous application to use * the asynchronous API without risking to stall the PulseAudio library. * * \section creat_sec Creation * * A pa_threaded_mainloop object is created using pa_threaded_mainloop_new(). * This will only allocate the required structures though, so to use it the * thread must also be started. This is done through * pa_threaded_mainloop_start(), after which you can start using the main loop. * * \section destr_sec Destruction * * When the PulseAudio connection has been terminated, the thread must be * stopped and the resources freed. Stopping the thread is done using * pa_threaded_mainloop_stop(), which must be called without the lock (see * below) held. When that function returns, the thread is stopped and the * pa_threaded_mainloop object can be freed using pa_threaded_mainloop_free(). * * \section lock_sec Locking * * Since the PulseAudio API doesn't allow concurrent accesses to objects, * a locking scheme must be used to guarantee safe usage. The threaded main * loop API provides such a scheme through the functions * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock(). * * The lock is recursive, so it's safe to use it multiple times from the same * thread. Just make sure you call pa_threaded_mainloop_unlock() the same * number of times you called pa_threaded_mainloop_lock(). * * The lock needs to be held whenever you call any PulseAudio function that * uses an object associated with this main loop. Make sure you do not hold * on to the lock more than necessary though, as the threaded main loop stops * while the lock is held. * * Example: * * \code * void my_check_stream_func(pa_threaded_mainloop *m, pa_stream *s) { * pa_stream_state_t state; * * pa_threaded_mainloop_lock(m); * * state = pa_stream_get_state(s); * * pa_threaded_mainloop_unlock(m); * * if (state == PA_STREAM_READY) * printf("Stream is ready!"); * else * printf("Stream is not ready!"); * } * \endcode * * \section cb_sec Callbacks * * Callbacks in PulseAudio are asynchronous, so they require extra care when * using them together with a threaded main loop. * * The easiest way to turn the callback based operations into synchronous * ones, is to simply wait for the callback to be called and continue from * there. This is the approach chosen in PulseAudio's threaded API. * * \subsection basic_subsec Basic callbacks * * For the basic case, where all that is required is to wait for the callback * to be invoked, the code should look something like this: * * Example: * * \code * static void my_drain_callback(pa_stream *s, int success, void *userdata) { * pa_threaded_mainloop *m; * * m = userdata; * assert(m); * * pa_threaded_mainloop_signal(m, 0); * } * * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { * pa_operation *o; * * pa_threaded_mainloop_lock(m); * * o = pa_stream_drain(s, my_drain_callback, m); * assert(o); * * while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) * pa_threaded_mainloop_wait(m); * * pa_operation_unref(o); * * pa_threaded_mainloop_unlock(m); * } * \endcode * * The main function, my_drain_stream_func(), will wait for the callback to * be called using pa_threaded_mainloop_wait(). * * If your application is multi-threaded, then this waiting must be * done inside a while loop. The reason for this is that multiple * threads might be using pa_threaded_mainloop_wait() at the same * time. Each thread must therefore verify that it was its callback * that was invoked. Also the underlying OS synchronization primitives * are usually not free of spurious wake-ups, so a * pa_threaded_mainloop_wait() must be called within a loop even if * you have only one thread waiting. * * The callback, my_drain_callback(), indicates to the main function that it * has been called using pa_threaded_mainloop_signal(). * * As you can see, pa_threaded_mainloop_wait() may only be called with * the lock held. The same thing is true for pa_threaded_mainloop_signal(), * but as the lock is held before the callback is invoked, you do not have to * deal with that. * * The functions will not dead lock because the wait function will release * the lock before waiting and then regrab it once it has been signalled. * For those of you familiar with threads, the behaviour is that of a * condition variable. * * \subsection data_subsec Data callbacks * * For many callbacks, simply knowing that they have been called is * insufficient. The callback also receives some data that is desired. To * access this data safely, we must extend our example a bit: * * \code * static volatile int *drain_result = NULL; * * static void my_drain_callback(pa_stream*s, int success, void *userdata) { * pa_threaded_mainloop *m; * * m = userdata; * assert(m); * * drain_result = &success; * * pa_threaded_mainloop_signal(m, 1); * } * * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { * pa_operation *o; * * pa_threaded_mainloop_lock(m); * * o = pa_stream_drain(s, my_drain_callback, m); * assert(o); * * while (drain_result == NULL) * pa_threaded_mainloop_wait(m); * * pa_operation_unref(o); * * if (*drain_result) * printf("Success!"); * else * printf("Bitter defeat..."); * * pa_threaded_mainloop_accept(m); * * pa_threaded_mainloop_unlock(m); * } * \endcode * * The example is a bit silly as it would probably have been easier to just * copy the contents of success, but for larger data structures this can be * wasteful. * * The difference here compared to the basic callback is the value 1 passed * to pa_threaded_mainloop_signal() and the call to * pa_threaded_mainloop_accept(). What will happen is that * pa_threaded_mainloop_signal() will signal the main function and then wait. * The main function is then free to use the data in the callback until * pa_threaded_mainloop_accept() is called, which will allow the callback * to continue. * * Note that pa_threaded_mainloop_accept() must be called some time between * exiting the while loop and unlocking the main loop! Failure to do so will * result in a race condition. I.e. it is not ok to release the lock and * regrab it before calling pa_threaded_mainloop_accept(). * * \subsection async_subsec Asynchronous callbacks * * PulseAudio also has callbacks that are completely asynchronous, meaning * that they can be called at any time. The threaded main loop API provides * the locking mechanism to handle concurrent accesses, but nothing else. * Applications will have to handle communication from the callback to the * main program through their own mechanisms. * * The callbacks that are completely asynchronous are: * * \li State callbacks for contexts, streams, etc. * \li Subscription notifications */ /** \file * * A thread based event loop implementation based on pa_mainloop. The * event loop is run in a helper thread in the background. A few * synchronization primitives are available to access the objects * attached to the event loop safely. * * See also \subpage threaded_mainloop */ /** An opaque threaded main loop object */ typedef struct pa_threaded_mainloop pa_threaded_mainloop; /** Allocate a new threaded main loop object. You have to call * pa_threaded_mainloop_start() before the event loop thread starts * running. */ pa_threaded_mainloop *pa_threaded_mainloop_new(void); /** Free a threaded main loop object. If the event loop thread is * still running, terminate it with pa_threaded_mainloop_stop() * first. */ void pa_threaded_mainloop_free(pa_threaded_mainloop* m); /** Start the event loop thread. */ int pa_threaded_mainloop_start(pa_threaded_mainloop *m); /** Terminate the event loop thread cleanly. Make sure to unlock the * mainloop object before calling this function. */ void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); /** Lock the event loop object, effectively blocking the event loop * thread from processing events. You can use this to enforce * exclusive access to all objects attached to the event loop. This * lock is recursive. This function may not be called inside the event * loop thread. Events that are dispatched from the event loop thread * are executed with this lock held. */ void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); /** Unlock the event loop object, inverse of pa_threaded_mainloop_lock() */ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); /** Wait for an event to be signalled by the event loop thread. You * can use this to pass data from the event loop thread to the main * thread in a synchronized fashion. This function may not be called * inside the event loop thread. Prior to this call the event loop * object needs to be locked using pa_threaded_mainloop_lock(). While * waiting the lock will be released. Immediately before returning it * will be acquired again. This function may spuriously wake up even * without pa_threaded_mainloop_signal() being called. You need to * make sure to handle that! */ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); /** Signal all threads waiting for a signalling event in * pa_threaded_mainloop_wait(). If wait_for_release is non-zero, do * not return before the signal was accepted by a * pa_threaded_mainloop_accept() call. While waiting for that condition * the event loop object is unlocked. */ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept); /** Accept a signal from the event thread issued with * pa_threaded_mainloop_signal(). This call should only be used in * conjunction with pa_threaded_mainloop_signal() with a non-zero * wait_for_accept value. */ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); /** Return the return value as specified with the main loop's * pa_mainloop_quit() routine. */ int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); /** Return the main loop abstraction layer vtable for this main loop. * There is no need to free this object as it is owned by the loop * and is destroyed when the loop is freed. */ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); /** Returns non-zero when called from within the event loop thread. \since 0.9.7 */ int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m); /** Sets the name of the thread. \since 5.0 */ void pa_threaded_mainloop_set_name(pa_threaded_mainloop *m, const char *name); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/timeval.h000066400000000000000000000060601364710014100233610ustar00rootroot00000000000000#ifndef footimevalhfoo #define footimevalhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include /** \file * Utility functions for handling timeval calculations */ PA_C_DECL_BEGIN /** The number of milliseconds in a second */ #define PA_MSEC_PER_SEC ((pa_usec_t) 1000ULL) /** The number of microseconds in a second */ #define PA_USEC_PER_SEC ((pa_usec_t) 1000000ULL) /** The number of nanoseconds in a second */ #define PA_NSEC_PER_SEC ((unsigned long long) 1000000000ULL) /** The number of microseconds in a millisecond */ #define PA_USEC_PER_MSEC ((pa_usec_t) 1000ULL) /** The number of nanoseconds in a millisecond */ #define PA_NSEC_PER_MSEC ((unsigned long long) 1000000ULL) /** The number of nanoseconds in a microsecond */ #define PA_NSEC_PER_USEC ((unsigned long long) 1000ULL) /** Invalid time in usec. \since 0.9.15 */ #define PA_USEC_INVALID ((pa_usec_t) -1) /** Biggest time in usec. \since 0.9.18 */ #define PA_USEC_MAX ((pa_usec_t) -2) struct timeval; /** Return the current wallclock timestamp, just like UNIX gettimeofday(). */ struct timeval *pa_gettimeofday(struct timeval *tv); /** Calculate the difference between the two specified timeval * structs. */ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) PA_GCC_PURE; /** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwise */ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) PA_GCC_PURE; /** Return the time difference between now and the specified timestamp */ pa_usec_t pa_timeval_age(const struct timeval *tv); /** Add the specified time in microseconds to the specified timeval structure */ struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); /** Subtract the specified time in microseconds to the specified timeval structure. \since 0.9.11 */ struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v); /** Store the specified usec value in the timeval struct. \since 0.9.7 */ struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v); /** Load the specified tv value and return it in usec. \since 0.9.7 */ pa_usec_t pa_timeval_load(const struct timeval *tv); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/utf8.h000066400000000000000000000040571364710014100226120ustar00rootroot00000000000000#ifndef fooutf8hfoo #define fooutf8hfoo /*** This file is part of PulseAudio. Copyright 2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include /** \file * UTF-8 validation functions */ PA_C_DECL_BEGIN /** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ char *pa_utf8_valid(const char *str) PA_GCC_PURE; /** Test if the specified strings qualifies as valid 7-bit ASCII. Return the string if so, otherwise NULL. \since 0.9.15 */ char *pa_ascii_valid(const char *str) PA_GCC_PURE; /** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ char *pa_utf8_filter(const char *str); /** Filter all invalid ASCII characters from the specified string, returning a new fully ASCII valid string. Don't forget to free the returned string with pa_xfree(). \since 0.9.15 */ char *pa_ascii_filter(const char *str); /** Convert a UTF-8 string to the current locale. Free the string using pa_xfree(). */ char* pa_utf8_to_locale (const char *str); /** Convert a string in the current locale to UTF-8. Free the string using pa_xfree(). */ char* pa_locale_to_utf8 (const char *str); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/util.h000066400000000000000000000035241364710014100226770ustar00rootroot00000000000000#ifndef fooutilhfoo #define fooutilhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include /** \file * Assorted utility functions */ PA_C_DECL_BEGIN /** Return the current username in the specified string buffer. */ char *pa_get_user_name(char *s, size_t l); /** Return the current hostname in the specified buffer. */ char *pa_get_host_name(char *s, size_t l); /** Return the fully qualified domain name in s */ char *pa_get_fqdn(char *s, size_t l); /** Return the home directory of the current user */ char *pa_get_home_dir(char *s, size_t l); /** Return the binary file name of the current process. This is not * supported on all architectures, in which case NULL is returned. */ char *pa_get_binary_name(char *s, size_t l); /** Return a pointer to the filename inside a path (which is the last * component). If passed NULL will return NULL. */ char *pa_path_get_filename(const char *p); /** Wait t milliseconds */ int pa_msleep(unsigned long t); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/version.h000066400000000000000000000046051364710014100234100ustar00rootroot00000000000000#ifndef fooversionhfoo /*-*-C-*-*/ #define fooversionhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ /* WARNING: Make sure to edit the real source file version.h.in! */ #include /** \file * Define header version */ PA_C_DECL_BEGIN /** Return the version of the header files. Keep in mind that this is a macro and not a function, so it is impossible to get the pointer of it. */ #define pa_get_headers_version() ("5.0.0") /** Return the version of the library the current application is * linked to. */ const char* pa_get_library_version(void); /** The current API version. Version 6 relates to Polypaudio * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have * PA_API_VERSION undefined. Please note that this is only ever * increased on incompatible API changes! */ #define PA_API_VERSION 12 /** The current protocol version. Version 8 relates to Polypaudio * 0.8/PulseAudio 0.9. */ #define PA_PROTOCOL_VERSION 29 /** The major version of PA. \since 0.9.15 */ #define PA_MAJOR 5 /** The minor version of PA. \since 0.9.15 */ #define PA_MINOR 0 /** The micro version of PA (will always be 0 from v1.0 onwards). \since 0.9.15 */ #define PA_MICRO 0 /** Evaluates to TRUE if the PulseAudio library version is equal or * newer than the specified. \since 0.9.16 */ #define PA_CHECK_VERSION(major,minor,micro) \ ((PA_MAJOR > (major)) || \ (PA_MAJOR == (major) && PA_MINOR > (minor)) || \ (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro))) PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/volume.h000066400000000000000000000473721364710014100232420ustar00rootroot00000000000000#ifndef foovolumehfoo #define foovolumehfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering Copyright 2006 Pierre Ossman for Cendio AB PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include #include /** \page volume Volume Control * * \section overv_sec Overview * * Sinks, sources, sink inputs and samples can all have their own volumes. * To deal with these, The PulseAudio library contains a number of functions * that ease handling. * * The basic volume type in PulseAudio is the \ref pa_volume_t type. Most of * the time, applications will use the aggregated pa_cvolume structure that * can store the volume of all channels at once. * * Volumes commonly span between muted (0%), and normal (100%). It is possible * to set volumes to higher than 100%, but clipping might occur. * * There is no single well-defined meaning attached to the 100% volume for a * sink input. In fact, it depends on the server configuration. With flat * volumes enabled (the default in most Linux distributions), it means the * maximum volume that the sound hardware is capable of, which is usually so * high that you absolutely must not set sink input volume to 100% unless the * the user explicitly requests that (note that usually you shouldn't set the * volume anyway if the user doesn't explicitly request it, instead, let * PulseAudio decide the volume for the sink input). With flat volumes disabled * (the default in Ubuntu), the sink input volume is relative to the sink * volume, so 100% sink input volume means that the sink input is played at the * current sink volume level. In this case 100% is often a good default volume * for a sink input, although you still should let PulseAudio decide the * default volume. It is possible to figure out whether flat volume mode is in * effect for a given sink by calling pa_context_get_sink_info_by_name(). * * \section calc_sec Calculations * * The volumes in PulseAudio are logarithmic in nature and applications * shouldn't perform calculations with them directly. Instead, they should * be converted to and from either dB or a linear scale: * * \li dB - pa_sw_volume_from_dB() / pa_sw_volume_to_dB() * \li Linear - pa_sw_volume_from_linear() / pa_sw_volume_to_linear() * * For simple multiplication, pa_sw_volume_multiply() and * pa_sw_cvolume_multiply() can be used. * * Calculations can only be reliably performed on software volumes * as it is commonly unknown what scale hardware volumes relate to. * * The functions described above are only valid when used with * software volumes. Hence it is usually a better idea to treat all * volume values as opaque with a range from PA_VOLUME_MUTED (0%) to * PA_VOLUME_NORM (100%) and to refrain from any calculations with * them. * * \section conv_sec Convenience Functions * * To handle the pa_cvolume structure, the PulseAudio library provides a * number of convenience functions: * * \li pa_cvolume_valid() - Tests if a pa_cvolume structure is valid. * \li pa_cvolume_equal() - Tests if two pa_cvolume structures are identical. * \li pa_cvolume_channels_equal_to() - Tests if all channels of a pa_cvolume * structure have a given volume. * \li pa_cvolume_is_muted() - Tests if all channels of a pa_cvolume * structure are muted. * \li pa_cvolume_is_norm() - Tests if all channels of a pa_cvolume structure * are at a normal volume. * \li pa_cvolume_set() - Set the first n channels of a pa_cvolume structure to * a certain volume. * \li pa_cvolume_reset() - Set the first n channels of a pa_cvolume structure * to a normal volume. * \li pa_cvolume_mute() - Set the first n channels of a pa_cvolume structure * to a muted volume. * \li pa_cvolume_avg() - Return the average volume of all channels. * \li pa_cvolume_snprint() - Pretty print a pa_cvolume structure. */ /** \file * Constants and routines for volume handling * * See also \subpage volume */ PA_C_DECL_BEGIN /** Volume specification: * PA_VOLUME_MUTED: silence; * < PA_VOLUME_NORM: decreased volume; * PA_VOLUME_NORM: normal volume; * > PA_VOLUME_NORM: increased volume */ typedef uint32_t pa_volume_t; /** Normal volume (100%, 0 dB) */ #define PA_VOLUME_NORM ((pa_volume_t) 0x10000U) /** Muted (minimal valid) volume (0%, -inf dB) */ #define PA_VOLUME_MUTED ((pa_volume_t) 0U) /** Maximum valid volume we can store. \since 0.9.15 */ #define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX/2) /** Recommended maximum volume to show in user facing UIs. * Note: UIs should deal gracefully with volumes greater than this value * and not cause feedback loops etc. - i.e. if the volume is more than * this, the UI should not limit it and push the limited value back to * the server. \since 0.9.23 */ #define PA_VOLUME_UI_MAX (pa_sw_volume_from_dB(+11.0)) /** Special 'invalid' volume. \since 0.9.16 */ #define PA_VOLUME_INVALID ((pa_volume_t) UINT32_MAX) /** Check if volume is valid. \since 1.0 */ #define PA_VOLUME_IS_VALID(v) ((v) <= PA_VOLUME_MAX) /** Clamp volume to the permitted range. \since 1.0 */ #define PA_CLAMP_VOLUME(v) (PA_CLAMP_UNLIKELY((v), PA_VOLUME_MUTED, PA_VOLUME_MAX)) /** A structure encapsulating a per-channel volume */ typedef struct pa_cvolume { uint8_t channels; /**< Number of channels */ pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ } pa_cvolume; /** Return non-zero when *a == *b */ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE; /** Initialize the specified volume and return a pointer to * it. The sample spec will have a defined state but * pa_cvolume_valid() will fail for it. \since 0.9.13 */ pa_cvolume* pa_cvolume_init(pa_cvolume *a); /** Set the volume of the first n channels to PA_VOLUME_NORM */ #define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) /** Set the volume of the first n channels to PA_VOLUME_MUTED */ #define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) /** Set the volume of the specified number of channels to the volume v */ pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); /** Maximum length of the strings returned by * pa_cvolume_snprint(). Please note that this value can change with * any release without warning and without being considered API or ABI * breakage. You should not use this definition anywhere where it * might become part of an ABI.*/ #define PA_CVOLUME_SNPRINT_MAX 320 /** Pretty print a volume structure */ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); /** Maximum length of the strings returned by * pa_sw_cvolume_snprint_dB(). Please note that this value can change with * any release without warning and without being considered API or ABI * breakage. You should not use this definition anywhere where it * might become part of an ABI. \since 0.9.13 */ #define PA_SW_CVOLUME_SNPRINT_DB_MAX 448 /** Pretty print a volume structure but show dB values. \since 0.9.13 */ char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c); /** Maximum length of the strings returned by pa_cvolume_snprint_verbose(). * Please note that this value can change with any release without warning and * without being considered API or ABI breakage. You should not use this * definition anywhere where it might become part of an ABI. \since 5.0 */ #define PA_CVOLUME_SNPRINT_VERBOSE_MAX 1984 /** Pretty print a volume structure in a verbose way. The volume for each * channel is printed in several formats: the raw pa_volume_t value, * percentage, and if print_dB is non-zero, also the dB value. If map is not * NULL, the channel names will be printed. \since 5.0 */ char *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB); /** Maximum length of the strings returned by * pa_volume_snprint(). Please note that this value can change with * any release without warning and without being considered API or ABI * breakage. You should not use this definition anywhere where it * might become part of an ABI. \since 0.9.15 */ #define PA_VOLUME_SNPRINT_MAX 10 /** Pretty print a volume \since 0.9.15 */ char *pa_volume_snprint(char *s, size_t l, pa_volume_t v); /** Maximum length of the strings returned by * pa_sw_volume_snprint_dB(). Please note that this value can change with * any release without warning and without being considered API or ABI * breakage. You should not use this definition anywhere where it * might become part of an ABI. \since 0.9.15 */ #define PA_SW_VOLUME_SNPRINT_DB_MAX 10 /** Pretty print a volume but show dB values. \since 0.9.15 */ char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v); /** Maximum length of the strings returned by pa_volume_snprint_verbose(). * Please note that this value can change with any release without warning and * withou being considered API or ABI breakage. You should not use this * definition anywhere where it might become part of an ABI. \since 5.0 */ #define PA_VOLUME_SNPRINT_VERBOSE_MAX 35 /** Pretty print a volume in a verbose way. The volume is printed in several * formats: the raw pa_volume_t value, percentage, and if print_dB is non-zero, * also the dB value. \since 5.0 */ char *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB); /** Return the average volume of all channels */ pa_volume_t pa_cvolume_avg(const pa_cvolume *a) PA_GCC_PURE; /** Return the average volume of all channels that are included in the * specified channel map with the specified channel position mask. If * cm is NULL this call is identical to pa_cvolume_avg(). If no * channel is selected the returned value will be * PA_VOLUME_MUTED. \since 0.9.16 */ pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE; /** Return the maximum volume of all channels. \since 0.9.12 */ pa_volume_t pa_cvolume_max(const pa_cvolume *a) PA_GCC_PURE; /** Return the maximum volume of all channels that are included in the * specified channel map with the specified channel position mask. If * cm is NULL this call is identical to pa_cvolume_max(). If no * channel is selected the returned value will be PA_VOLUME_MUTED. * \since 0.9.16 */ pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE; /** Return the minimum volume of all channels. \since 0.9.16 */ pa_volume_t pa_cvolume_min(const pa_cvolume *a) PA_GCC_PURE; /** Return the minimum volume of all channels that are included in the * specified channel map with the specified channel position mask. If * cm is NULL this call is identical to pa_cvolume_min(). If no * channel is selected the returned value will be PA_VOLUME_MUTED. * \since 0.9.16 */ pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE; /** Return non-zero when the passed cvolume structure is valid */ int pa_cvolume_valid(const pa_cvolume *v) PA_GCC_PURE; /** Return non-zero if the volume of all channels is equal to the specified value */ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) PA_GCC_PURE; /** Return 1 if the specified volume has all channels muted */ #define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) /** Return 1 if the specified volume has all channels on normal level */ #define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) /** Multiply two volume specifications, return the result. This uses * PA_VOLUME_NORM as neutral element of multiplication. This is only * valid for software volumes! */ pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST; /** Multiply two per-channel volumes and return the result in * *dest. This is only valid for software volumes! a, b and dest may * point to the same structure. */ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); /** Multiply a per-channel volume with a scalar volume and return the * result in *dest. This is only valid for software volumes! a * and dest may point to the same structure. \since * 0.9.16 */ pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b); /** Divide two volume specifications, return the result. This uses * PA_VOLUME_NORM as neutral element of division. This is only valid * for software volumes! If a division by zero is tried the result * will be 0. \since 0.9.13 */ pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) PA_GCC_CONST; /** Divide two per-channel volumes and return the result in * *dest. This is only valid for software volumes! a, b * and dest may point to the same structure. \since 0.9.13 */ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); /** Divide a per-channel volume by a scalar volume and return the * result in *dest. This is only valid for software volumes! a * and dest may point to the same structure. \since * 0.9.16 */ pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b); /** Convert a decibel value to a volume (amplitude, not power). This is only valid for software volumes! */ pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST; /** Convert a volume to a decibel value (amplitude, not power). This is only valid for software volumes! */ double pa_sw_volume_to_dB(pa_volume_t v) PA_GCC_CONST; /** Convert a linear factor to a volume. 0.0 and less is muted while * 1.0 is PA_VOLUME_NORM. This is only valid for software volumes! */ pa_volume_t pa_sw_volume_from_linear(double v) PA_GCC_CONST; /** Convert a volume to a linear factor. This is only valid for software volumes! */ double pa_sw_volume_to_linear(pa_volume_t v) PA_GCC_CONST; #ifdef INFINITY #define PA_DECIBEL_MININFTY ((double) -INFINITY) #else /** This floor value is used as minus infinity when using pa_sw_volume_to_dB() / pa_sw_volume_from_dB(). */ #define PA_DECIBEL_MININFTY ((double) -200.0) #endif /** Remap a volume from one channel mapping to a different channel mapping. \since 0.9.12 */ pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to); /** Return non-zero if the specified volume is compatible with the * specified sample spec. \since 0.9.13 */ int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) PA_GCC_PURE; /** Return non-zero if the specified volume is compatible with the * specified sample spec. \since 0.9.15 */ int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) PA_GCC_PURE; /** Calculate a 'balance' value for the specified volume with the * specified channel map. The return value will range from -1.0f * (left) to +1.0f (right). If no balance value is applicable to this * channel map the return value will always be 0.0f. See * pa_channel_map_can_balance(). \since 0.9.15 */ float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) PA_GCC_PURE; /** Adjust the 'balance' value for the specified volume with the * specified channel map. v will be modified in place and * returned. The balance is a value between -1.0f and +1.0f. This * operation might not be reversible! Also, after this call * pa_cvolume_get_balance() is not guaranteed to actually return the * requested balance value (e.g. when the input volume was zero anyway for * all channels). If no balance value is applicable to * this channel map the volume will not be modified. See * pa_channel_map_can_balance(). \since 0.9.15 */ pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance); /** Calculate a 'fade' value (i.e.\ 'balance' between front and rear) * for the specified volume with the specified channel map. The return * value will range from -1.0f (rear) to +1.0f (left). If no fade * value is applicable to this channel map the return value will * always be 0.0f. See pa_channel_map_can_fade(). \since 0.9.15 */ float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) PA_GCC_PURE; /** Adjust the 'fade' value (i.e.\ 'balance' between front and rear) * for the specified volume with the specified channel map. v will be * modified in place and returned. The balance is a value between * -1.0f and +1.0f. This operation might not be reversible! Also, * after this call pa_cvolume_get_fade() is not guaranteed to actually * return the requested fade value (e.g. when the input volume was * zero anyway for all channels). If no fade value is applicable to * this channel map the volume will not be modified. See * pa_channel_map_can_fade(). \since 0.9.15 */ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade); /** Scale the passed pa_cvolume structure so that the maximum volume * of all channels equals max. The proportions between the channel * volumes are kept. \since 0.9.15 */ pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max); /** Scale the passed pa_cvolume structure so that the maximum volume * of all channels selected via cm/mask equals max. This also modifies * the volume of those channels that are unmasked. The proportions * between the channel volumes are kept. \since 0.9.16 */ pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask); /** Set the passed volume to all channels at the specified channel * position. Will return the updated volume struct, or NULL if there * is no channel at the position specified. You can check if a channel * map includes a specific position by calling * pa_channel_map_has_position(). \since 0.9.16 */ pa_cvolume* pa_cvolume_set_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v); /** Get the maximum volume of all channels at the specified channel * position. Will return 0 if there is no channel at the position * specified. You can check if a channel map includes a specific * position by calling pa_channel_map_has_position(). \since 0.9.16 */ pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE; /** This goes through all channels in a and b and sets the * corresponding channel in dest to the greater volume of both. a, b * and dest may point to the same structure. \since 0.9.16 */ pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); /** Increase the volume passed in by 'inc', but not exceeding 'limit'. * The proportions between the channels are kept. \since 0.9.19 */ pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit); /** Increase the volume passed in by 'inc'. The proportions between * the channels are kept. \since 0.9.16 */ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc); /** Decrease the volume passed in by 'dec'. The proportions between * the channels are kept. \since 0.9.16 */ pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec); PA_C_DECL_END #endif apulse-0.1.13/3rdparty/pulseaudio-headers/pulse/xmalloc.h000066400000000000000000000067261364710014100233700ustar00rootroot00000000000000#ifndef foomemoryhfoo #define foomemoryhfoo /*** This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include #include #include #include #include #include #include /** \file * Memory allocation functions. */ PA_C_DECL_BEGIN /** Allocate the specified number of bytes, just like malloc() does. However, in case of OOM, terminate */ void* pa_xmalloc(size_t l) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE(1); /** Same as pa_xmalloc(), but initialize allocated memory to 0 */ void *pa_xmalloc0(size_t l) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE(1); /** The combination of pa_xmalloc() and realloc() */ void *pa_xrealloc(void *ptr, size_t size) PA_GCC_ALLOC_SIZE(2); /** Free allocated memory */ void pa_xfree(void *p); /** Duplicate the specified string, allocating memory with pa_xmalloc() */ char *pa_xstrdup(const char *s) PA_GCC_MALLOC; /** Duplicate the specified string, but truncate after l characters */ char *pa_xstrndup(const char *s, size_t l) PA_GCC_MALLOC; /** Duplicate the specified memory block */ void* pa_xmemdup(const void *p, size_t l) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE(2); /** Internal helper for pa_xnew() */ static void* _pa_xnew_internal(size_t n, size_t k) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE2(1,2); static inline void* _pa_xnew_internal(size_t n, size_t k) { assert(n < INT_MAX/k); return pa_xmalloc(n*k); } /** Allocate n new structures of the specified type. */ #define pa_xnew(type, n) ((type*) _pa_xnew_internal((n), sizeof(type))) /** Internal helper for pa_xnew0() */ static void* _pa_xnew0_internal(size_t n, size_t k) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE2(1,2); static inline void* _pa_xnew0_internal(size_t n, size_t k) { assert(n < INT_MAX/k); return pa_xmalloc0(n*k); } /** Same as pa_xnew() but set the memory to zero */ #define pa_xnew0(type, n) ((type*) _pa_xnew0_internal((n), sizeof(type))) /** Internal helper for pa_xnew0() */ static void* _pa_xnewdup_internal(const void *p, size_t n, size_t k) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE2(2,3); static inline void* _pa_xnewdup_internal(const void *p, size_t n, size_t k) { assert(n < INT_MAX/k); return pa_xmemdup(p, n*k); } /** Same as pa_xnew() but duplicate the specified data */ #define pa_xnewdup(type, p, n) ((type*) _pa_xnewdup_internal((p), (n), sizeof(type))) /** Internal helper for pa_xrenew() */ static void* _pa_xrenew_internal(void *p, size_t n, size_t k) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE2(2,3); static inline void* _pa_xrenew_internal(void *p, size_t n, size_t k) { assert(n < INT_MAX/k); return pa_xrealloc(p, n*k); } /** Reallocate n new structures of the specified type. */ #define pa_xrenew(type, p, n) ((type*) _pa_xrenew_internal(p, (n), sizeof(type))) PA_C_DECL_END #endif apulse-0.1.13/CMakeLists.txt000066400000000000000000000054451364710014100156320ustar00rootroot00000000000000project(apulse) cmake_minimum_required (VERSION 2.8) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -fPIC -fvisibility=hidden") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") find_package(PkgConfig REQUIRED) pkg_check_modules(REQ glib-2.0 alsa REQUIRED) list(APPEND REQ_LIBRARIES m) set(WITH_TRACE 0 CACHE STRING "trace level: no tracing (0) / unimplemented only (1) / all (2)") set(LOG_TO_STDERR 0 CACHE STRING "send all log output to stderr") # Options. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_TRACE_LEVEL=${WITH_TRACE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_LOG_TO_STDERR=${LOG_TO_STDERR}") include_directories(${REQ_INCLUDE_DIRS}) set(USE_BUNDLED_PULSEAUDIO_HEADERS 1 CACHE BOOL "Use bundled PulseAudio headers instead of system ones") if (${USE_BUNDLED_PULSEAUDIO_HEADERS}) include_directories(3rdparty/pulseaudio-headers) else() pkg_check_modules(PA libpulse>=5.0 REQUIRED) include_directories(${PA_INCLUDE_DIRECTORIES}) endif() link_directories(${REQ_LIBRARY_DIRS}) add_library(trace-helper STATIC src/trace.c ) add_library(pulse SHARED src/apulse-channel-map.c src/apulse-common.c src/apulse-context.c src/apulse-ext.c src/apulse-format-info.c src/apulse-mainloop.c src/apulse-misc.c src/apulse-operation.c src/apulse-proplist.c src/apulse-signal.c src/apulse-stream.c src/apulse-threaded-mainloop.c src/apulse-volume.c src/ringbuffer.c src/util.c ) add_library(pulse-simple SHARED src/apulse-simple.c ) add_library(pulse-mainloop-glib SHARED src/apulse-mainloop-glib.c ) set_target_properties(pulse PROPERTIES VERSION 0) set_target_properties(pulse-mainloop-glib PROPERTIES VERSION 0) set_target_properties(pulse-simple PROPERTIES VERSION 0) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-version-script=\"${CMAKE_SOURCE_DIR}/src/symbolmap\"") target_link_libraries(pulse trace-helper ${REQ_LIBRARIES}) target_link_libraries(pulse-mainloop-glib trace-helper pulse ${REQ_LIBRARIES}) target_link_libraries(pulse-simple trace-helper pulse ${REQ_LIBRARIES}) add_subdirectory(tests) set(APULSEPATH "${CMAKE_INSTALL_PREFIX}/lib/apulse" CACHE PATH "library installation directory") set(APULSE_SEARCH_PATHS "${APULSEPATH}" CACHE PATH "directory list for LD_LIBRARY_PATH") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/apulse.template" "${CMAKE_CURRENT_BINARY_DIR}/apulse" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/apulse" DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(TARGETS pulse-simple pulse pulse-mainloop-glib DESTINATION "${APULSEPATH}") install(FILES "${CMAKE_SOURCE_DIR}/man/apulse.1" DESTINATION share/man/man1) apulse-0.1.13/LICENSE.MIT000066400000000000000000000020261364710014100145170ustar00rootroot00000000000000The MIT License (MIT) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. apulse-0.1.13/README.md000066400000000000000000000211031364710014100143360ustar00rootroot00000000000000About ===== PulseAudio emulation for ALSA. The program provides an alternative partial implementation of the PulseAudio API. It consists of a loader script and a number of shared libraries with the same names as from original PulseAudio, so applications could dynamically load them and think they are talking to PulseAudio. Internally, no separate sound mixing daemon is used. Instead, apulse relies on ALSA's `dmix`, `dsnoop`, and `plug` plugins to handle multiple sound sources and capture streams running at the same time. `dmix` plugin muxes multiple playback streams; `dsnoop` plugin allow multiple applications to capture from a single microphone; and `plug` plugin transparently converts audio between various sample formats, sample rates and channel numbers. For more than a decade now, ALSA comes with these plugins enabled and configured by default. `apulse` wasn't designed to be a drop-in replacement of PulseAudio. It's pointless, since that will be just reimplementation of original PulseAudio, with the same client-daemon architecture, required by the complete feature set. Instead, only parts of the API that are crucial to specific applications are implemented. That's why there is a loader script, named `apulse`. It updates value of `LD_LIBRARY_PATH` environment variable to point also to the directory where apulse's libraries are installed, making them available to the application. Name comes from names of both ALSA and PulseAudio. As `aoss` was a compatibility layer between OSS programs and ALSA, `apulse` was designed to be compatibility layer between PulseAudio applications and ALSA. Install ======= You need ALSA libraries and GLib installed. On Debian-based distributions, they are in packages `libasound2-dev` and `libglib2.0-dev`. To build and install, run in source directory: ``` $ mkdir build && cd build $ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. $ make # make install ``` That will create directory named `build`, and build there. It's possible to install just by running `make install` as `root`, as shown above. But you won't be able to uninstall installed files. That's why it's recommended to wrap files into a package. Use `checkinstall`, or some alternative. If you want 32-bit binaries on 64-bit machine (for example, for Skype), use: ``` $ mkdir build && cd build $ CFLAGS=-m32 cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. $ make # make install ``` Recent GLib versions use different `.pc` files for `i386` and `amd64`. To help `pkg-config` find 32-bit versions, use `PKG_CONFIG_PATH` variable. So, on Debian it will be something like: ``` $ PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig CFLAGS=-m32 cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. ``` There is a way to configure where apulse libraries will be installed, via `APULSEPATH` cmake variable. For example, if you want to install libraries into default path, `/usr/lib`, use ``` cmake -DAPULSEPATH=/usr/lib -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. ``` If libraries are installed to a regular library path, you don't need run applications through `apulse` wrapper. Usage ===== ``` $ apulse [program-parameters] ``` Environment variables `APULSE_CAPTURE_DEVICE` and `APULSE_PLAYBACK_DEVICE` can be used to configure capture and playback devices. Try `hw:0,0`, `plughw:0,0` and the like. Refer to the ALSA user guide for a full list of device names. System directory versus separate directory installations -------------------------------------------------------- By default, libraries from `apulse` are installed into a separate directory, in order to hide them from all applications. Most applications in the wild, that support both PulseAudio and ALSA, try to autodetect which sound system is used. First, applications try to start with PulseAudio. Original client libraries fail early if no PulseAudio daemon is running or can be started. Then they switch to ALSA. Decision is made once, at the beginning. It works fine with PulseAudio, but doesn't work with `apulse`. Latter has no daemons, it happily says that everything is fine, and it's capable of playing audio. Applications then try to call more functions, and eventually touch unimplemented parts, often with crashes. So, libraries are hidden, and become visible only when a program is called through `apulse` wrapper script. It's possible to install apulse libraries to `/usr/lib`. Wrapper script won't be required, but then all applications will try to use PulseAudio API, despite they can use ALSA. Per-app RPATH trick ------------------- There is the RPATH property of ELF executable format, which is used to specify paths to search for dynamic libraries. It's like LD_LIBRARY_PATH variable, but per-executable. Since all that `apulse` launcher script does is setting LD_LIBRARY_PATH value before launching an application, it's possible to bake paths to apulse libraries into target executable itself. And so to launch it as usual, without helper script. For example, for Firefox it would be: ``` # patchelf --set-rpath /usr/lib/apulse /usr/lib/firefox/libxul.so ``` For some reason, it doesn't work if RPATH is set for `/usr/lib/firefox/firefox` itself, so some experiments are required to make it work. Known issues ============ Not implemented functions, application crashes ---------------------------------------------- Large portion of PulseAudio API is not implemented. There are functions that do nothing and return some arbitraty values. Often, if application tries to call something not implemented, it crashes while trying to dereference a NULL pointer. By default, tracing level is set to `0`, which means no messages are printed to standard output. It's possible to increase that value to `1`, which shows unimplemented function calls, or to `2`, which shows all function calls. To change level, use `WITH_TRACE` parameter when calling `cmake`. Something like `cmake -DWITH_TRACE=1 ..` Building apulse with trace level 1 won't fix issues, but will at least help to identify if crashes are caused by not implemented functions. Generic errors in do_connect_pcm -------------------------------- Apulse acts as a generic ALSA client. It tries to open audio device, and sometimes fails. At its core, apulse does neither audio mixing nor resampling. Instead, it relies on `plug`, `dmix`, and `dsnoop` ALSA plugins, which are usually enabled by default. These plugins handle multiple audio sources, performing resampling and mixing transparently. For years now ALSA comes with those plugins enabled. Audio just works without configuring anything. But not everybody use default settings. On custom configurations apulse may fail to output and/or capture audio. There could be no sound at all, or just a single audio stream playing at a time. It's also possible that adapters with hardware mixers, which capable of playing multiple streams, may still be unable to handle multiple capture streams. Depending on hardware, you may still need either `dmix` or `dsnoop` plugins. Or both. In other words, for apulse to work, your setup should be capable of playing and capturing multiple streams simultaneously. Access errors in do_connect_pcm ------------------------------- If other applications output sound just fine, it's possible that application you are using restricts itself. For example, Firefox now have a sandbox, that blocks file access. It has predefined list of allowed paths, but ALSA devices are not included by default. Fortunately, it's possible to add those path by hand. Add "/dev/snd/" to "security.sandbox.content.write_path_whitelist" parameter in `about:config`. Note that trailing slash in "/dev/snd/" is required. Firefox 58 tabs crashing when trying to play audio -------------------------------------------------- Firefox 58 (Nightly) tightened its sandbox a bit more. Now `ioctl()` calls are forbidden too, but are used by ALSA libraries. That causes sandbox violation with subsequent process termination. Exception can be added by setting parameter `security.sandbox.content.syscall_whitelist` in `about:config`. That field accepts a comma separated list of system call numbers. Add there `16` for x86-64, or `54` for x86 or ARM. Firefox 60 tighened its content sandbox more, but at the same time moved audio accesses from content processes to the main process. From Firefox 60 onwards no changes to the sandbox settings are necessary. License ======= Source code is distributed under the terms of the MIT License. See LICENSE.MIT for full text. Third party code ================ `/3rdparty/pulseaudio-headers` contains part of PulseAudio project and is distributed under LGPLv2.1+ terms. See content of the files for details. apulse-0.1.13/man/000077500000000000000000000000001364710014100136355ustar00rootroot00000000000000apulse-0.1.13/man/apulse.1000066400000000000000000000042741364710014100152170ustar00rootroot00000000000000.TH APULSE 1 2017-10-23 "apulse" "apulse" .SH NAME .B apulse \- The PulseAudio emulator for \fBALSA\fR .SH SYNOPSIS .B apulse .RI .RI [program-parameters]... .SH DESCRIPTION The program provides an alternative partial implementation of the PulseAudio API. It consists of a loader script and a number of shared libraries with the same names as from original PulseAudio, so applications could dynamically load them and think they are talking to PulseAudio. Internally, no separate sound mixing daemon is used. Instead, \fBapulse\fR relies on \fBALSA\fR's \fBdmix\fR, \fBdsnoop\fR, and \fBplug\fR plugins to handle multiple sound sources and capture streams running at the same time. \fBdmix\fR plugin muxes multiple playback streams; \fBdsnoop\fR plugin allow multiple applications to capture from a single microphone; and \fBplug\fR plugin transparently converts audio between various sample formats, sample rates and channel numbers. For more than a decade now, \fBALSA\fR comes with these plugins enabled and configured by default. \fBapulse\fR wasn't designed to be a drop-in replacement of PulseAudio. It's pointless, since that will be just reimplementation of original PulseAudio, with the same client-daemon architecture, required by the complete feature set. Instead, only parts of the API that are crucial to specific applications are implemented. That's why there is a loader script, named \fBapulse\fR. It updates value of LD_LIBRARY_PATH environment variable to point also to the directory where \fBapulse\fR's libraries are installed, making them available to the application. Name comes from names of both \fBALSA\fR and PulseAudio. As \fBaoss\fR was a compatibility layer between OSS programs and \fBALSA\fR, \fBapulse\fR was designed to be compatibility layer between PulseAudio applications and \fBALSA\fR. .SH RETURN VALUE \fBapulse\fR is a simple shell wrapper script that calls \fBexec\fR on the program given in parameters. Except for cases when the wrapper itself fails to load, return value is the return value of that program. .SH EXAMPLE Run a newer Firefox browser with fake PulseAudio: .nf .sp apulse firefox .fi .SH AUTHORS \fBapulse\fR was written by Rinat Ibragimov in 2014-2017. apulse-0.1.13/src/000077500000000000000000000000001364710014100136515ustar00rootroot00000000000000apulse-0.1.13/src/apulse-channel-map.c000066400000000000000000000432201364710014100174700ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" static const char *channel_name[PA_CHANNEL_POSITION_MAX] = { [PA_CHANNEL_POSITION_MONO] = "mono", [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", [PA_CHANNEL_POSITION_LFE] = "lfe", [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", [PA_CHANNEL_POSITION_AUX0] = "aux0", [PA_CHANNEL_POSITION_AUX1] = "aux1", [PA_CHANNEL_POSITION_AUX2] = "aux2", [PA_CHANNEL_POSITION_AUX3] = "aux3", [PA_CHANNEL_POSITION_AUX4] = "aux4", [PA_CHANNEL_POSITION_AUX5] = "aux5", [PA_CHANNEL_POSITION_AUX6] = "aux6", [PA_CHANNEL_POSITION_AUX7] = "aux7", [PA_CHANNEL_POSITION_AUX8] = "aux8", [PA_CHANNEL_POSITION_AUX9] = "aux9", [PA_CHANNEL_POSITION_AUX10] = "aux10", [PA_CHANNEL_POSITION_AUX11] = "aux11", [PA_CHANNEL_POSITION_AUX12] = "aux12", [PA_CHANNEL_POSITION_AUX13] = "aux13", [PA_CHANNEL_POSITION_AUX14] = "aux14", [PA_CHANNEL_POSITION_AUX15] = "aux15", [PA_CHANNEL_POSITION_AUX16] = "aux16", [PA_CHANNEL_POSITION_AUX17] = "aux17", [PA_CHANNEL_POSITION_AUX18] = "aux18", [PA_CHANNEL_POSITION_AUX19] = "aux19", [PA_CHANNEL_POSITION_AUX20] = "aux20", [PA_CHANNEL_POSITION_AUX21] = "aux21", [PA_CHANNEL_POSITION_AUX22] = "aux22", [PA_CHANNEL_POSITION_AUX23] = "aux23", [PA_CHANNEL_POSITION_AUX24] = "aux24", [PA_CHANNEL_POSITION_AUX25] = "aux25", [PA_CHANNEL_POSITION_AUX26] = "aux26", [PA_CHANNEL_POSITION_AUX27] = "aux27", [PA_CHANNEL_POSITION_AUX28] = "aux28", [PA_CHANNEL_POSITION_AUX29] = "aux29", [PA_CHANNEL_POSITION_AUX30] = "aux30", [PA_CHANNEL_POSITION_AUX31] = "aux31", [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center", [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left", [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right", }; APULSE_EXPORT pa_channel_map * pa_channel_map_init(pa_channel_map *m) { trace_info_f("F %s m=%p\n", __func__, m); if (m) memset(m, 0, sizeof(*m)); return m; } APULSE_EXPORT pa_channel_map * pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { trace_info_f("F %s m=%p, channels=%u, def=%u\n", __func__, m, channels, def); if (!m) return NULL; memset(m, 0, sizeof(*m)); channels = MIN(channels, PA_CHANNELS_MAX); m->channels = channels; switch (def) { default: case PA_CHANNEL_MAP_AIFF: switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; case 3: m->map[0] = PA_CHANNEL_POSITION_LEFT; m->map[1] = PA_CHANNEL_POSITION_RIGHT; m->map[2] = PA_CHANNEL_POSITION_CENTER; return m; case 4: m->map[0] = PA_CHANNEL_POSITION_LEFT; m->map[1] = PA_CHANNEL_POSITION_CENTER; m->map[2] = PA_CHANNEL_POSITION_RIGHT; m->map[3] = PA_CHANNEL_POSITION_REAR_CENTER; return m; case 5: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; return m; case 6: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; m->map[2] = PA_CHANNEL_POSITION_CENTER; m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[4] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; m->map[5] = PA_CHANNEL_POSITION_REAR_CENTER; return m; default: return NULL; } break; case PA_CHANNEL_MAP_ALSA: switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; case 2: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return m; case 4: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; return m; case 5: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; return m; case 6: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[5] = PA_CHANNEL_POSITION_LFE; return m; case 8: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[5] = PA_CHANNEL_POSITION_LFE; m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; return m; default: return NULL; } break; case PA_CHANNEL_MAP_AUX: for (unsigned int k = 0; k < channels; k++) m->map[k] = PA_CHANNEL_POSITION_AUX0 + k; return m; case PA_CHANNEL_MAP_WAVEEX: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[3] = PA_CHANNEL_POSITION_LFE; m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT; m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER; m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; case 2: case 3: case 4: case 6: case 8: case 9: case 11: case 12: case 15: case 18: return m; default: return NULL; } break; case PA_CHANNEL_MAP_OSS: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[3] = PA_CHANNEL_POSITION_LFE; m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; return m; case 2: case 3: case 4: case 6: case 8: return m; default: return NULL; } break; } return NULL; } APULSE_EXPORT pa_channel_map * pa_channel_map_init_mono(pa_channel_map *m) { gchar *s_m = trace_pa_channel_map_as_string(m); trace_info_f("F %s m=%s\n", __func__, s_m); g_free(s_m); pa_channel_map *cm = calloc(1, sizeof(pa_channel_map)); cm->channels = 1; cm->map[0] = PA_CHANNEL_POSITION_MONO; return cm; } APULSE_EXPORT pa_channel_map * pa_channel_map_init_stereo(pa_channel_map *m) { gchar *s_m = trace_pa_channel_map_as_string(m); trace_info_f("F %s m=%s\n", __func__, s_m); g_free(s_m); pa_channel_map *cm = calloc(1, sizeof(pa_channel_map)); cm->channels = 2; cm->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; cm->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; return cm; } APULSE_EXPORT pa_channel_map * pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { trace_info_f("F %s m=%p, channels=%u, def=(%u)\n", __func__, m, channels, def); channels = MIN(channels, PA_CHANNELS_MAX); // Try to find a channel map with largest number of channels for (unsigned int k = channels; k > 0; k--) { if (pa_channel_map_init_auto(m, k, def) != NULL) { // Found a channel map. Now fill remaining position with AUX. unsigned int n = k; for (/* void */; k < channels; k++) m->map[k] = PA_CHANNEL_POSITION_AUX0 + (k - n); m->channels = channels; return m; } } return NULL; } APULSE_EXPORT int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) { gchar *s_map = trace_pa_channel_map_as_string(map); gchar *s_ss = trace_pa_sample_spec_as_string(ss); trace_info_f("F %s map=%s, ss=%s\n", __func__, s_map, s_ss); g_free(s_ss); g_free(s_map); return map->channels == ss->channels; } APULSE_EXPORT pa_channel_map * pa_channel_map_parse(pa_channel_map *map, const char *s) { trace_info_f("F %s map=%p, s=%s\n", __func__, map, s); pa_channel_map m = {}; if (strcmp(s, "stereo") == 0) { m.channels = 2; m.map[0] = PA_CHANNEL_POSITION_LEFT; m.map[1] = PA_CHANNEL_POSITION_RIGHT; } else if (strcmp(s, "surround-21") == 0) { m.channels = 3; m.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m.map[2] = PA_CHANNEL_POSITION_LFE; } else if (strcmp(s, "surround-40") == 0) { m.channels = 4; m.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; } else if (strcmp(s, "surround-41") == 0) { m.channels = 5; m.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m.map[4] = PA_CHANNEL_POSITION_LFE; } else if (strcmp(s, "surround-50") == 0) { m.channels = 5; m.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; } else if (strcmp(s, "surround-51") == 0) { m.channels = 6; m.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; m.map[5] = PA_CHANNEL_POSITION_LFE; } else if (strcmp(s, "surround-51") == 0) { m.channels = 8; m.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; m.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; m.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; m.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; m.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; m.map[5] = PA_CHANNEL_POSITION_LFE; m.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; m.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; } if (m.channels > 0) { // it was one of the predefined setups above *map = m; return map; } char **p = g_strsplit(s, ",", PA_CHANNELS_MAX); int k = 0; while (k < PA_CHANNELS_MAX && p[k]) { m.channels = k + 1; m.map[k] = pa_channel_position_from_string(p[k]); k++; } g_strfreev(p); *map = m; return map; } APULSE_EXPORT char * pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { gchar *s_map = trace_pa_channel_map_as_string(map); trace_info_f("F %s s=%p, l=%d, map=%s\n", __func__, s, (int)l, s_map); g_free(s_map); char *ptr = s; if (!pa_channel_map_valid(map)) { snprintf(s, l, "(invalid)"); return s; } for (int c = 0; c < map->channels && l > 1; c++) { int adv = snprintf(ptr, l, "%s%s", (c == 0) ? "" : ",", pa_channel_position_to_string(map->map[c])); ptr += adv; l -= adv; } return s; } APULSE_EXPORT int pa_channel_map_valid(const pa_channel_map *map) { gchar *s_map = trace_pa_channel_map_as_string(map); trace_info_f("F %s map=%s\n", __func__, s_map); g_free(s_map); if (!map) return 0; const int channel_count_valid = (0 < map->channels && map->channels <= PA_CHANNELS_MAX); if (!channel_count_valid) return 0; for (int k = 0; k < map->channels; k++) { const int channel_valid = (0 < map->map[k] && map->map[k] <= PA_CHANNEL_POSITION_MAX); if (!channel_valid) return 0; } return 1; } APULSE_EXPORT pa_channel_position_t pa_channel_position_from_string(const char *s) { trace_info_f("F %s s=%s\n", __func__, s); if (!s) return PA_CHANNEL_POSITION_INVALID; for (unsigned int k = 0; k < PA_CHANNEL_POSITION_MAX; k++) { if (!channel_name[k]) continue; if (strcmp(channel_name[k], s) == 0) return k; } return PA_CHANNEL_POSITION_INVALID; } APULSE_EXPORT const char * pa_channel_position_to_string(pa_channel_position_t pos) { gchar *s_pos = trace_pa_channel_position_t_as_string(pos); trace_info_f("F %s pos=%s\n", __func__, s_pos); g_free(s_pos); if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) return "unknown"; const char *s = channel_name[pos]; if (!s) return "unknown"; return s; } APULSE_EXPORT const char * pa_channel_position_to_pretty_string(pa_channel_position_t pos) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_channel_map_can_balance(const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_channel_map_can_fade(const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT const char * pa_channel_map_to_name(const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT const char * pa_channel_map_to_pretty_name(const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return 0; } apulse-0.1.13/src/apulse-common.c000066400000000000000000000142561364710014100166040ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" typedef enum pa_log_level { PA_LOG_ERROR = 0, PA_LOG_WARN = 1, PA_LOG_NOTICE = 2, PA_LOG_INFO = 3, PA_LOG_DEBUG = 4, PA_LOG_LEVEL_MAX } pa_log_level_t; APULSE_EXPORT void pa_log_level_meta(pa_log_level_t level, const char *file, int line, const char *func, const char *format, ...) { char buf[2048]; int written = 0; snprintf(buf, sizeof(buf), "pa_log: <%d> %s:%d %s %n", level, file, line, func, &written); va_list args; va_start(args, format); vsnprintf(buf + written, sizeof(buf) - written, format, args); va_end(args); trace_info("%s\n", buf); } APULSE_EXPORT void pa_disable_sigpipe(void) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT int pa_open_cloexec(const char *fn, int flags, mode_t mode) { int fd = open(fn, flags, mode); if (fd < 0) return fd; fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); return fd; } APULSE_EXPORT int pa_close(int fd) { close(fd); return 0; } APULSE_EXPORT char * pa_ascii_filter(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_ascii_valid(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_utf8_filter(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_utf8_to_locale(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_utf8_valid(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_bytes_snprint(char *s, size_t l, unsigned v) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT const char * pa_encoding_to_string(pa_encoding_t e) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_encoding_t pa_encoding_from_string(const char *encoding) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT char * pa_get_fqdn(char *s, size_t l) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_get_home_dir(char *s, size_t l) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_msleep(unsigned long t) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_usec_t pa_timeval_age(const struct timeval *tv) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT struct timeval * pa_timeval_add(struct timeval *tv, pa_usec_t v) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT struct timeval * pa_timeval_sub(struct timeval *tv, pa_usec_t v) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT struct timeval * pa_timeval_store(struct timeval *tv, pa_usec_t v) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_usec_t pa_timeval_load(const struct timeval *tv) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT char * pa_get_host_name(char *s, size_t l) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_get_user_name(char *s, size_t l) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT struct timeval * pa_gettimeofday(struct timeval *tv) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void * pa_xmemdup(const void *p, size_t l) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void * pa_xrealloc(void *ptr, size_t size) { trace_info_f("F %s ptr=%p, size=%zu\n", __func__, ptr, size); void *p = realloc(ptr, size); if (!p) return ptr; return p; } APULSE_EXPORT char * pa_xstrdup(const char *s) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_xstrndup(const char *s, size_t l) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_sample_format_is_le(pa_sample_format_t f) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_sample_format_is_be(pa_sample_format_t f) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT size_t pa_sample_size_of_format(pa_sample_format_t f) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_sample_spec * pa_sample_spec_init(pa_sample_spec *spec) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_sample_spec_equal(const pa_sample_spec *a, const pa_sample_spec *b) { gchar *s_a = trace_pa_sample_spec_as_string(a); gchar *s_b = trace_pa_sample_spec_as_string(b); trace_info_z("Z %s a=%s, b=%s\n", __func__, s_a, s_b); g_free(s_b); g_free(s_a); return 0; } APULSE_EXPORT pa_sample_format_t pa_parse_sample_format(const char *format) { trace_info_z("Z %s\n", __func__); return 0; } apulse-0.1.13/src/apulse-context.c000066400000000000000000001063731364710014100170020ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" static void pai_context_set_state(pa_context *c, pa_context_state_t new_state) { if (c->state == new_state) return; pa_context_ref(c); c->state = new_state; if (c->state_cb) c->state_cb(c, c->state_cb_userdata); if (new_state == PA_CONTEXT_FAILED || new_state == PA_CONTEXT_TERMINATED) { c->state_cb = NULL; } pa_context_unref(c); } static void pai_context_state_changed(pa_mainloop_api *api, pa_defer_event *de, void *userdata) { pa_context *c = userdata; pai_context_set_state(c, c->new_state); pa_context_unref(c); } APULSE_EXPORT int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) { trace_info_f("P %s c=%p, server=%s, flags=%u, api=%p\n", __func__, c, server, flags, api); pa_context_ref(c); pai_context_set_state(c, PA_CONTEXT_CONNECTING); c->new_state = PA_CONTEXT_READY; c->mainloop_api->defer_new(c->mainloop_api, pai_context_state_changed, c); return 0; } APULSE_EXPORT void pa_context_disconnect(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); pai_context_set_state(c, PA_CONTEXT_TERMINATED); } APULSE_EXPORT int pa_context_errno(pa_context *c) { trace_info_z("Z %s c=%p\n", __func__, c); return 0; } APULSE_EXPORT uint32_t pa_context_get_protocol_version(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); return PA_PROTOCOL_VERSION; } static void pa_context_get_server_info_impl(pa_operation *op) { pa_server_info info = { .user_name = "apulse_user_name", // TODO: actual user name .host_name = "apulse_host_name", // TODO: actual host name .server_version = "5.0", .server_name = "pulseaudio", .sample_spec = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2, }, .default_sink_name = "default_sink_name", .default_source_name = "default_source_name", .cookie = 1, .channel_map = { .channels = 2, .map = {PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT}, }, }; if (op->server_info_cb) op->server_info_cb(op->c, &info, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, cb=%p, userdata=%p\n", __func__, c, &cb, userdata); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_get_server_info_impl); op->c = c; op->server_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } APULSE_EXPORT uint32_t pa_context_get_server_protocol_version(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); return 8; // PA headers say "8" is the protocol version used in PulseAudio // 0.9 } static pa_sink_info pai_fill_default_sink_info(void) { static pa_proplist *proplist = NULL; if (!proplist) { // TODO: free memory proplist = pa_proplist_new(); } static pa_sink_port_info sink_port = { .name = "ALSA sink", .description = "ALSA sink", .priority = 1, .available = PA_PORT_AVAILABLE_YES, }; static pa_sink_port_info *sink_ports[] = { &sink_port, }; // TODO: real data pa_sink_info info = { .name = "default_sink_name", .index = 0, .description = "default and only sink", .sample_spec = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2, }, .channel_map = { .channels = 2, .map = {PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT}, }, .owner_module = PA_INVALID_INDEX, .volume = { .channels = 2, .values = { PA_VOLUME_NORM, PA_VOLUME_NORM, }, }, .mute = 0, .monitor_source = 0, .monitor_source_name = NULL, .latency = 100000, .driver = "apulse", .flags = 0, .proplist = proplist, .configured_latency = 100000, .base_volume = PA_VOLUME_NORM, .state = PA_SINK_RUNNING, .n_volume_steps = 0, .card = 0, .n_ports = 1, .ports = sink_ports, .active_port = &sink_port, }; return info; } static void pa_context_get_sink_info_by_name_impl(pa_operation *op) { pa_sink_info info = pai_fill_default_sink_info(); if (op->sink_info_cb) { if (strcmp(op->char_ptr_arg_1, info.name) == 0) op->sink_info_cb(op->c, &info, 0, op->cb_userdata); op->sink_info_cb(op->c, NULL, 1, op->cb_userdata); } free(op->char_ptr_arg_1); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, name=%s, cb=%p, userdata=%p\n", __func__, c, name, cb, userdata); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_get_sink_info_by_name_impl); op->c = c; op->char_ptr_arg_1 = strdup(name ? name : ""); op->sink_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } static void pa_context_get_sink_info_list_impl(pa_operation *op) { pa_sink_info info = pai_fill_default_sink_info(); if (op->sink_info_cb) { op->sink_info_cb(op->c, &info, 0, op->cb_userdata); op->sink_info_cb(op->c, NULL, 1, op->cb_userdata); } pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, cb=%p, userdata=%p\n", __func__, c, cb, userdata); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_get_sink_info_list_impl); op->c = c; op->sink_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } static pa_source_info pai_fill_default_source_info(void) { static pa_proplist *proplist = NULL; if (!proplist) { // TODO: free memory proplist = pa_proplist_new(); } static pa_source_port_info source_port = { .name = "ALSA source", .description = "ALSA source", .priority = 1, .available = PA_PORT_AVAILABLE_YES, }; static pa_source_port_info *source_ports[] = { &source_port, }; // TODO: real data pa_source_info info = { .name = "default_source_name", .index = 0, .description = "default_source_name", .sample_spec = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2, }, .channel_map = { .channels = 2, .map = { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, }, }, .owner_module = PA_INVALID_INDEX, .volume = { .channels = 2, .values = { PA_VOLUME_NORM, PA_VOLUME_NORM, }, }, .mute = 0, .monitor_of_sink = 0, .monitor_of_sink_name = NULL, .latency = 100000, // TODO: where to get latency figures? .driver = "apulse", .flags = 0, .proplist = proplist, .configured_latency = 100000, .base_volume = PA_VOLUME_NORM, .state = PA_SOURCE_RUNNING, .n_volume_steps = 0, .card = PA_INVALID_INDEX, .n_ports = 1, .ports = source_ports, .active_port = &source_port, .n_formats = 0, .formats = NULL, }; return info; } static void pa_context_get_source_info_list_impl(pa_operation *op) { pa_source_info info = pai_fill_default_source_info(); if (op->source_info_cb) { op->source_info_cb(op->c, &info, 0, op->cb_userdata); op->source_info_cb(op->c, NULL, 1, op->cb_userdata); } pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, cb=%p, userdata=%p\n", __func__, c, cb, userdata); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_get_source_info_list_impl); op->c = c; op->source_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } static void pa_context_get_source_info_by_name_impl(pa_operation *op) { pa_source_info info = pai_fill_default_source_info(); if (op->source_info_cb) { if (strcmp(op->char_ptr_arg_1, info.name) == 0) op->source_info_cb(op->c, &info, 0, op->cb_userdata); op->source_info_cb(op->c, NULL, 1, op->cb_userdata); } free(op->char_ptr_arg_1); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, name=%s, cb=%p, userdata=%p\n", __func__, c, name, cb, userdata); pa_operation *op = pa_operation_new( c->mainloop_api, pa_context_get_source_info_by_name_impl); op->c = c; op->char_ptr_arg_1 = strdup(name ? name : ""); op->source_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } static void pa_context_get_sink_info_by_index_impl(pa_operation *op) { pa_sink_info info = pai_fill_default_sink_info(); if (op->sink_info_cb) { if (op->int_arg_1 == info.index) op->sink_info_cb(op->c, &info, 0, op->cb_userdata); op->sink_info_cb(op->c, NULL, 1, op->cb_userdata); } pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, idx=%u, cb=%p, userdata=%p\n", __func__, c, idx, cb, userdata); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_get_sink_info_by_index_impl); op->c = c; op->int_arg_1 = idx; op->sink_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } static void pa_context_get_sink_input_info_impl(pa_operation *op) { uint32_t idx = op->int_arg_1; pa_stream *s = g_hash_table_lookup(op->c->streams_ht, GINT_TO_POINTER(idx)); if (!s) { trace_error("%s, no such stream: %u\n", __func__, idx); pa_operation_cancel(op); return; } pa_sink_input_info sii = { .index = 0, .name = "dummy-sink", .owner_module = PA_INVALID_INDEX, .client = PA_INVALID_INDEX, .sink = 0, .sample_spec = (pa_sample_spec){.format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2}, .channel_map.channels = 2, .channel_map.map[0] = PA_CHANNEL_POSITION_LEFT, .channel_map.map[1] = PA_CHANNEL_POSITION_RIGHT, .volume.channels = 2, .volume.values[0] = PA_VOLUME_NORM, .volume.values[1] = PA_VOLUME_NORM, .buffer_usec = 0, .sink_usec = 0, .resample_method = "auto", .driver = "guess who", .mute = 0, .proplist = pa_proplist_new(), .corked = 0, .has_volume = 1, .volume_writable = 1, .format = NULL, }; if (op->sink_input_info_cb) op->sink_input_info_cb(op->c, &sii, 0, op->cb_userdata); pa_proplist_free(sii.proplist); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, idx=%u, cb=%p, userdata=%p\n", __func__, c, idx, cb, userdata); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_get_sink_input_info_impl); op->c = c; op->int_arg_1 = idx; op->sink_input_info_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } APULSE_EXPORT pa_context_state_t pa_context_get_state(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); return c ? c->state : PA_CONTEXT_UNCONNECTED; } APULSE_EXPORT pa_context * pa_context_new(pa_mainloop_api *mainloop_api, const char *name) { trace_info_f("F %s mainloop_api=%p, name=%s\n", __func__, mainloop_api, name); pa_proplist *p = pa_proplist_new(); pa_context *c = pa_context_new_with_proplist(mainloop_api, name, p); pa_proplist_free(p); return c; } APULSE_EXPORT pa_context * pa_context_new_with_proplist(pa_mainloop_api *mainloop_api, const char *name, pa_proplist *proplist) { trace_info_f("F %s mainloop_api=%p, name=%s, proplist=%p\n", __func__, mainloop_api, name, proplist); pa_context *c = calloc(1, sizeof(pa_context)); c->state = PA_CONTEXT_UNCONNECTED; c->mainloop_api = mainloop_api; c->name = strdup(name ? name : ""); c->ref_cnt = 1; c->streams_ht = g_hash_table_new(g_direct_hash, g_direct_equal); for (uint32_t k = 0; k < PA_CHANNELS_MAX; k++) { c->source_volume[k] = PA_VOLUME_NORM; } return c; } APULSE_EXPORT pa_context * pa_context_ref(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); if (!c) return NULL; c->ref_cnt++; return c; } APULSE_EXPORT pa_time_event * pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, usec=%" PRIu64 " cb=%p, userdata=%p\n", __func__, c, (uint64_t)usec, cb, userdata); struct timeval when = { .tv_sec = usec / PA_USEC_PER_SEC, .tv_usec = usec % PA_USEC_PER_SEC, }; return c->mainloop_api->time_new(c->mainloop_api, &when, cb, userdata); } APULSE_EXPORT pa_operation * pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s c=%p, idx=%u, mute=%d, cb=%p, userdata=%p\n", __func__, c, idx, mute, cb, userdata); return NULL; } static void pa_context_set_sink_input_volume_impl(pa_operation *op) { uint32_t idx = op->int_arg_1; pa_stream *s = g_hash_table_lookup(op->c->streams_ht, GINT_TO_POINTER(idx)); if (!s) { // Can't find a stream with selected index. if (op->context_success_cb) op->context_success_cb(op->c, 0, op->cb_userdata); return; } memset(s->volume, 0, sizeof(s->volume)); const uint32_t channels = MIN(op->pa_cvolume_arg_1.channels, PA_CHANNELS_MAX); for (uint32_t k = 0; k < channels; k++) s->volume[k] = op->pa_cvolume_arg_1.values[k]; if (op->context_success_cb) op->context_success_cb(op->c, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { gchar *s_volume = trace_pa_volume_as_string(volume); trace_info_f("F %s c=%p, idx=%u, volume=%s, cb=%p, userdata=%p\n", __func__, c, idx, s_volume, cb, userdata); g_free(s_volume); pa_operation *op = pa_operation_new(c->mainloop_api, pa_context_set_sink_input_volume_impl); op->c = c; op->int_arg_1 = idx; op->context_success_cb = cb; op->cb_userdata = userdata; if (volume) op->pa_cvolume_arg_1 = *volume; pa_operation_launch(op); return op; } APULSE_EXPORT void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { trace_info_f("F %s c=%p, cb=%p, userdata=%p\n", __func__, c, cb, userdata); c->state_cb = cb; c->state_cb_userdata = userdata; } APULSE_EXPORT void pa_context_unref(pa_context *c) { trace_info_f("F %s c=%p\n", __func__, c); if (!c) return; c->ref_cnt--; if (c->ref_cnt == 0) { g_hash_table_unref(c->streams_ht); free(c->name); free(c); } } APULSE_EXPORT pa_operation * pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } static void pa_context_set_source_volume_by_index_impl(pa_operation *op) { // TODO: actually change volume if (op->context_success_cb) op->context_success_cb(op->c, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { gchar *s_volume = trace_pa_volume_as_string(volume); trace_info_f("Z %s c=%p, idx=%u, volume=%s, cb=%p, userdata=%p\n", __func__, c, idx, s_volume, cb, userdata); g_free(s_volume); pa_operation *op = pa_operation_new( c->mainloop_api, pa_context_set_source_volume_by_index_impl); op->c = c; op->context_success_cb = cb; op->cb_userdata = userdata; if (volume) op->pa_cvolume_arg_1 = *volume; pa_operation_launch(op); return op; } APULSE_EXPORT void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { trace_info_z("Z %s c=%p, cb=%p, userdata=%p\n", __func__, c, cb, userdata); } APULSE_EXPORT pa_operation * pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s c=%p, m=0x%04x, cb=%p, userdata=%p\n", __func__, c, m, cb, userdata); return NULL; } APULSE_EXPORT pa_operation * pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char *argument, pa_context_index_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_suspend_sink_by_name(pa_context *c, const char *sink_name, int suspend, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_sink_port_by_index(pa_context *c, uint32_t idx, const char *port, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_sink_port_by_name(pa_context *c, const char *name, const char *port, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_suspend_source_by_name(pa_context *c, const char *source_name, int suspend, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char *port, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_port_by_name(pa_context *c, const char *name, const char *port, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_load_module(pa_context *c, const char *name, const char *argument, pa_context_index_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_card_info_by_index(pa_context *c, uint32_t idx, pa_card_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_card_info_by_name(pa_context *c, const char *name, pa_card_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_card_info_list(pa_context *c, pa_card_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_card_profile_by_index(pa_context *c, uint32_t idx, const char *profile, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_card_profile_by_name(pa_context *c, const char *name, const char *profile, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_port_latency_offset(pa_context *c, const char *card_name, const char *port_name, int64_t offset, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, const char *sink_name, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, const char *source_name, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_output_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_source_output_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_context_is_local(pa_context *c) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_operation * pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT const char * pa_context_get_server(pa_context *c) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT uint32_t pa_context_get_index(pa_context *s) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss) { gchar *s_ss = trace_pa_sample_spec_as_string(ss); trace_info_z("Z %s c=%p, ss=%s\n", __func__, c, s_ss); g_free(s_ss); return 0; } APULSE_EXPORT int pa_context_load_cookie_from_file(pa_context *c, const char *cookie_file_path) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT void pa_context_set_event_callback(pa_context *p, pa_context_event_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT int pa_context_is_pending(pa_context *c) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_operation * pa_context_play_sample(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_play_sample_with_proplist(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_proplist *proplist, pa_context_play_sample_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } apulse-0.1.13/src/apulse-ext.c000066400000000000000000000143431364710014100161110ustar00rootroot00000000000000/* * Copyright © 2017-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" #include #include #include APULSE_EXPORT pa_operation * pa_ext_device_manager_test(pa_context *c, pa_ext_device_manager_test_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_manager_read(pa_context *c, pa_ext_device_manager_read_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_manager_set_device_description(pa_context *c, const char *device, const char *description, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_manager_delete(pa_context *c, const char *const s[], pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_manager_enable_role_device_priority_routing( pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_manager_reorder_devices_for_role(pa_context *c, const char *role, const char **devices, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_manager_subscribe(pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void pa_ext_device_manager_set_subscribe_cb(pa_context *c, pa_ext_device_manager_subscribe_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT pa_operation * pa_ext_device_restore_test(pa_context *c, pa_ext_device_restore_test_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_restore_subscribe(pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void pa_ext_device_restore_set_subscribe_cb(pa_context *c, pa_ext_device_restore_subscribe_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT pa_operation * pa_ext_device_restore_read_formats_all( pa_context *c, pa_ext_device_restore_read_device_formats_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_restore_read_formats( pa_context *c, pa_device_type_t type, uint32_t idx, pa_ext_device_restore_read_device_formats_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_device_restore_save_formats(pa_context *c, pa_device_type_t type, uint32_t idx, uint8_t n_formats, pa_format_info **formats, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_stream_restore_test(pa_context *c, pa_ext_stream_restore_test_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_stream_restore_read(pa_context *c, pa_ext_stream_restore_read_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_stream_restore_write(pa_context *c, pa_update_mode_t mode, const pa_ext_stream_restore_info data[], unsigned n, int apply_immediately, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_ext_stream_restore_delete(pa_context *c, const char *const s[], pa_context_success_cb_t cb, void *userdata); APULSE_EXPORT pa_operation * pa_ext_stream_restore_subscribe(pa_context *c, int enable, pa_context_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void pa_ext_stream_restore_set_subscribe_cb(pa_context *c, pa_ext_stream_restore_subscribe_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } apulse-0.1.13/src/apulse-format-info.c000066400000000000000000000147441364710014100175370ustar00rootroot00000000000000/* * Copyright © 2015-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" APULSE_EXPORT void pa_format_info_free(pa_format_info *f) { trace_info_f("F %s f=%p\n", __func__, f); pa_proplist_free(f->plist); free(f); } APULSE_EXPORT pa_format_info * pa_format_info_new(void) { trace_info_f("F %s (void)\n", __func__); pa_format_info *fi = malloc(sizeof(pa_format_info)); if (!fi) return NULL; fi->encoding = PA_ENCODING_INVALID; fi->plist = pa_proplist_new(); return fi; } APULSE_EXPORT void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) { gchar *s_map = trace_pa_channel_map_as_string(map); trace_info_f("F %s f=%p, map=%s\n", __func__, f, s_map); g_free(s_map); char buf[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map_snprint(buf, sizeof(buf), map); pa_proplist_sets(f->plist, PA_PROP_FORMAT_CHANNEL_MAP, buf); } APULSE_EXPORT void pa_format_info_set_channels(pa_format_info *f, int channels) { trace_info_f("F %s f=%p, channels=%d\n", __func__, f, channels); char buf[20]; snprintf(buf, sizeof(buf), "%d", channels); pa_proplist_sets(f->plist, PA_PROP_FORMAT_CHANNELS, buf); } APULSE_EXPORT void pa_format_info_set_rate(pa_format_info *f, int rate) { trace_info_f("F %s f=%p, rate=%d\n", __func__, f, rate); char buf[20]; snprintf(buf, sizeof(buf), "%d", rate); pa_proplist_sets(f->plist, PA_PROP_FORMAT_RATE, buf); } APULSE_EXPORT void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) { trace_info_f("F %s f=%p, sf=%u\n", __func__, f, sf); pa_proplist_sets(f->plist, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf)); } APULSE_EXPORT int pa_format_info_valid(const pa_format_info *f) { trace_info_f("F %s f=%p\n", __func__, f); int encoding_valid = (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX); int plist_valid = (f->plist != NULL); return encoding_valid && plist_valid; } APULSE_EXPORT pa_format_info * pa_format_info_copy(const pa_format_info *src) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_format_info_is_pcm(const pa_format_info *f) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT char * pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_format_info * pa_format_info_from_string(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_format_info * pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) { gchar *s_ss = trace_pa_sample_spec_as_string(ss); gchar *s_map = trace_pa_channel_map_as_string(map); trace_info_z("Z %s ss=%s, map=%s\n", __func__, s_ss, s_map); g_free(s_map); g_free(s_ss); return NULL; } APULSE_EXPORT int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT void pa_format_info_free_string_array(char **values, int n_values) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) { trace_info_z("Z %s\n", __func__); } apulse-0.1.13/src/apulse-mainloop-glib.c000066400000000000000000000104731364710014100200420ustar00rootroot00000000000000/* * Copyright © 2017-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" #include static pa_io_event * gml_api_io_new(pa_mainloop_api *a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) { trace_info_z("Z %s a=%p, fd=%d, events=0x%x, cb=%p, userdata=%p\n", __func__, a, fd, events, cb, userdata); return NULL; } static void gml_api_io_enable(pa_io_event *e, pa_io_event_flags_t events) { trace_info_z("Z %s e=%p, events=0x%x\n", __func__, e, events); } static void gml_api_io_free(pa_io_event *e) { trace_info_z("Z %s e=%p\n", __func__, e); } static void gml_api_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) { trace_info_z("Z %s\n", __func__); } static pa_time_event * gml_api_time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) { trace_info_z("Z %s a=%p, tv=%p {%ld, %ld}, cb=%p, userdata=%p\n", __func__, a, tv, tv ? tv->tv_sec : 0, tv ? tv->tv_usec : 0, cb, userdata); return NULL; } static void gml_api_time_restart(pa_time_event *e, const struct timeval *tv) { trace_info_z("Z %s e=%p, tv=%p {%ld, %ld}\n", __func__, e, tv, tv ? tv->tv_sec : 0, tv ? tv->tv_usec : 0); } static void gml_api_time_free(pa_time_event *e) { trace_info_z("Z %s e=%p\n", __func__, e); } static void gml_api_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { trace_info_f("Z %s e=%p, cb=%p\n", __func__, e, cb); } static pa_defer_event * gml_api_defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } static void gml_api_defer_enable(pa_defer_event *e, int b) { trace_info_z("Z %s\n", __func__); } static void gml_api_defer_free(pa_defer_event *e) { trace_info_z("Z %s\n", __func__); } static void gml_api_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) { trace_info_z("Z %s\n", __func__); } static void gml_api_quit(pa_mainloop_api *a, int retval) { trace_info_z("Z %s a=%p, retval=%d\n", __func__, a, retval); } APULSE_EXPORT pa_glib_mainloop * pa_glib_mainloop_new(GMainContext *c) { trace_info_z("Z %s c=%p\n", __func__, c); pa_glib_mainloop *m = g_malloc0(sizeof(pa_glib_mainloop)); m->api = (pa_mainloop_api){ .userdata = m, .io_new = gml_api_io_new, .io_enable = gml_api_io_enable, .io_free = gml_api_io_free, .io_set_destroy = gml_api_io_set_destroy, .time_new = gml_api_time_new, .time_restart = gml_api_time_restart, .time_free = gml_api_time_free, .time_set_destroy = gml_api_time_set_destroy, .defer_new = gml_api_defer_new, .defer_enable = gml_api_defer_enable, .defer_free = gml_api_defer_free, .defer_set_destroy = gml_api_defer_set_destroy, .quit = gml_api_quit, }; return m; } APULSE_EXPORT void pa_glib_mainloop_free(pa_glib_mainloop *g) { trace_info_f("F %s g=%p\n", __func__, g); g_free(g); } APULSE_EXPORT pa_mainloop_api * pa_glib_mainloop_get_api(pa_glib_mainloop *g) { trace_info_f("F %s g=%p\n", __func__, g); return &g->api; } apulse-0.1.13/src/apulse-mainloop.c000066400000000000000000000363371364710014100171360ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _XOPEN_SOURCE 500 #include "apulse.h" #include "trace.h" #include #include static int from_pa_io_event_flags(pa_io_event_flags_t flags) { return ((flags & PA_IO_EVENT_INPUT) ? POLLIN : 0) | ((flags & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | ((flags & PA_IO_EVENT_HANGUP) ? POLLHUP : 0) | ((flags & PA_IO_EVENT_ERROR) ? POLLERR : 0); } static pa_io_event_flags_t to_pa_io_event_flags(int flags) { return ((flags & POLLIN) ? PA_IO_EVENT_INPUT : 0) | ((flags & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0) | ((flags & POLLHUP) ? PA_IO_EVENT_HANGUP : 0) | ((flags & POLLERR) ? PA_IO_EVENT_ERROR : 0); } static void ml_api_defer_enable(pa_defer_event *e, int b) { trace_info_f("F %s\n", __func__); e->enabled = b; } static void ml_api_defer_free(pa_defer_event *e) { trace_info_f("F %s\n", __func__); pa_mainloop *ml = e->mainloop; g_queue_remove(ml->deferred_events_queue, e); g_slice_free(pa_defer_event, e); pa_mainloop_wakeup(ml); } static pa_defer_event * ml_api_defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata) { trace_info_f("F %s\n", __func__); pa_mainloop *ml = a->userdata; pa_defer_event *de = g_slice_new0(pa_defer_event); de->enabled = 1; de->cb = cb; de->userdata = userdata; de->mainloop = ml; g_queue_push_tail(ml->deferred_events_queue, de); pa_mainloop_wakeup(ml); return de; } static void ml_api_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) { trace_info_z("Z %s\n", __func__); } static void ml_api_io_enable(pa_io_event *e, pa_io_event_flags_t events) { trace_info_f("F %s e=%p, events=0x%x\n", __func__, e, events); if (e->events == events) return; e->events = events; pa_mainloop *ml = e->mainloop; ml->recreate_fds = 1; pa_mainloop_wakeup(ml); } static void ml_api_io_free(pa_io_event *e) { trace_info_f("F %s e=%p\n", __func__, e); pa_mainloop *ml = e->mainloop; g_hash_table_remove(ml->events_ht, e); g_slice_free(pa_io_event, e); ml->recreate_fds = 1; pa_mainloop_wakeup(ml); } static pa_io_event * ml_api_io_new(pa_mainloop_api *a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) { trace_info_f("F %s a=%p, fd=%d, events=0x%x, cb=%p, userdata=%p\n", __func__, a, fd, events, cb, userdata); pa_mainloop *ml = a->userdata; pa_io_event *ioe = g_slice_new(pa_io_event); ioe->fd = fd; ioe->events = events; ioe->cb = cb; ioe->cb_userdata = userdata; ioe->mainloop = ml; ioe->pollfd = NULL; ioe->pcm = NULL; g_hash_table_replace(ml->events_ht, ioe, ioe); ml->recreate_fds = 1; pa_mainloop_wakeup(ml); return ioe; } static void ml_api_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) { trace_info_z("Z %s\n", __func__); } static void ml_api_quit(pa_mainloop_api *a, int retval) { trace_info_f("F %s a=%p, retval=%d\n", __func__, a, retval); pa_mainloop *ml = a->userdata; pa_mainloop_quit(ml, retval); } static void ml_api_time_free(pa_time_event *e) { trace_info_f("F %s e=%p\n", __func__, e); pa_mainloop *ml = e->mainloop; g_queue_remove(ml->timed_events_queue, e); if (e->destroy_cb) e->destroy_cb(&ml->api, e, e->userdata); g_slice_free(pa_time_event, e); pa_mainloop_wakeup(ml); } /// Comparator function for |timed_events_queue|. Orders events by value of /// |when| parameter. static gint time_event_comparator(gconstpointer a, gconstpointer b, gpointer user_data) { const pa_time_event *te_a = a; const pa_time_event *te_b = b; // First, try to compare seconds. if (te_a->when.tv_sec < te_b->when.tv_sec) return -1; if (te_a->when.tv_sec > te_b->when.tv_sec) return 1; // If we got here, tv_sec fields are equal. // Then, compare microseconds. if (te_a->when.tv_usec < te_b->when.tv_usec) return -1; if (te_a->when.tv_usec > te_b->when.tv_usec) return 1; // Timestamps are equal. return 0; } static pa_time_event * ml_api_time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) { trace_info_f("F %s a=%p, tv=%p {%ld, %ld}, cb=%p, userdata=%p\n", __func__, a, tv, tv ? tv->tv_sec : 0, tv ? tv->tv_usec : 0, cb, userdata); pa_mainloop *ml = a->userdata; pa_time_event *te = g_slice_new0(pa_time_event); te->enabled = 1; te->when = tv ? *tv : (struct timeval){}; te->cb = cb; te->userdata = userdata; te->mainloop = ml; g_queue_insert_sorted(ml->timed_events_queue, te, time_event_comparator, NULL); pa_mainloop_wakeup(ml); return te; } static void ml_api_time_restart(pa_time_event *e, const struct timeval *tv) { trace_info_f("F %s e=%p, tv=%p {%ld, %ld}\n", __func__, e, tv, tv ? tv->tv_sec : 0, tv ? tv->tv_usec : 0); pa_mainloop *ml = e->mainloop; g_queue_remove(ml->timed_events_queue, e); e->enabled = 1; e->when = tv ? *tv : (struct timeval){}; g_queue_insert_sorted(ml->timed_events_queue, e, time_event_comparator, NULL); pa_mainloop_wakeup(ml); } static void ml_api_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) { trace_info_f("F %s e=%p, cb=%p\n", __func__, e, cb); e->destroy_cb = cb; } static void pa_mainloop_api_once_impl(pa_operation *op) { if (op->mainloop_api_once_cb) op->mainloop_api_once_cb(op->api, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT void pa_mainloop_api_once(pa_mainloop_api *m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { trace_info_f("F %s\n", __func__); pa_operation *op = pa_operation_new(m, pa_mainloop_api_once_impl); op->mainloop_api_once_cb = callback; op->cb_userdata = userdata; pa_operation_launch(op); } static void recover_pcm(snd_pcm_t *pcm) { switch (snd_pcm_state(pcm)) { case SND_PCM_STATE_XRUN: snd_pcm_recover(pcm, -EPIPE, 1); break; case SND_PCM_STATE_SUSPENDED: snd_pcm_recover(pcm, -ESTRPIPE, 1); break; default: snd_pcm_drop(pcm); snd_pcm_prepare(pcm); break; } } static long microseconds_till_event(pa_usec_t now, const struct timeval *event_when) { return (uint64_t)event_when->tv_sec * 1000 * 1000 + event_when->tv_usec - now; } APULSE_EXPORT int pa_mainloop_dispatch(pa_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); int cnt = 0; GList *keys = g_hash_table_get_keys(m->events_ht); GList *it; it = keys; while (it) { struct pa_io_event *ioe = it->data; if (ioe->pollfd && ioe->pollfd->revents) { int idx = ioe->pollfd - m->fds; unsigned short revents = 0; if (0 < idx && idx <= m->alsa_special_cnt) { snd_pcm_poll_descriptors_revents(ioe->pcm, ioe->pollfd, 1, &revents); } else { revents = ioe->pollfd->revents; } if (revents & (~(POLLOUT | POLLIN))) { recover_pcm(ioe->pcm); } else { pa_io_event_flags_t eflags = to_pa_io_event_flags(revents); if (ioe->cb) ioe->cb(&m->api, ioe, ioe->fd, eflags, ioe->cb_userdata); ioe->pollfd->revents = 0; cnt++; } } it = g_list_next(it); } g_list_free(keys); if (m->fds && m->fds[0].revents) { // drain wakeup pipe char buf[200]; while (read(m->wakeup_pipe[0], buf, sizeof(buf)) > 0) { // cycle } m->fds[0].revents = 0; } pa_usec_t now = pa_rtclock_now(); pa_time_event *te = g_queue_peek_head(m->timed_events_queue); while (te && microseconds_till_event(now, &te->when) <= 0) { if (te->cb && te->enabled) te->cb(&m->api, te, &te->when, te->userdata); g_queue_pop_head(m->timed_events_queue); te = g_queue_peek_head(m->timed_events_queue); } pa_defer_event *de = g_queue_pop_head(m->deferred_events_queue); while (de) { if (de->cb) de->cb(&m->api, de, de->userdata); de = g_queue_pop_head(m->deferred_events_queue); } return cnt; } APULSE_EXPORT void pa_mainloop_free(pa_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); g_queue_free(m->deferred_events_queue); g_queue_free(m->timed_events_queue); g_hash_table_unref(m->events_ht); close(m->wakeup_pipe[0]); close(m->wakeup_pipe[1]); free(m); } APULSE_EXPORT pa_mainloop_api * pa_mainloop_get_api(pa_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); return &m->api; } APULSE_EXPORT int pa_mainloop_get_retval(pa_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); return m->retval; } APULSE_EXPORT int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { trace_info_f("F %s m=%p, block=%d\n", __func__, m, block); int err; int timeout = block ? -1 : 0; err = pa_mainloop_prepare(m, timeout); if (err < 0) return err; err = pa_mainloop_poll(m); if (err < 0) return err; err = pa_mainloop_dispatch(m); return err; } static void make_nonblock(int fd) { int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); } APULSE_EXPORT pa_mainloop * pa_mainloop_new(void) { trace_info_f("F %s (void)\n", __func__); pa_mainloop *m = calloc(1, sizeof(pa_mainloop)); m->api.userdata = m; m->api.io_new = ml_api_io_new; m->api.io_enable = ml_api_io_enable; m->api.io_free = ml_api_io_free; m->api.io_set_destroy = ml_api_io_set_destroy; m->api.time_new = ml_api_time_new; m->api.time_restart = ml_api_time_restart; m->api.time_free = ml_api_time_free; m->api.time_set_destroy = ml_api_time_set_destroy; m->api.defer_new = ml_api_defer_new; m->api.defer_enable = ml_api_defer_enable; m->api.defer_free = ml_api_defer_free; m->api.defer_set_destroy = ml_api_defer_set_destroy; m->api.quit = ml_api_quit; m->deferred_events_queue = g_queue_new(); m->timed_events_queue = g_queue_new(); m->events_ht = g_hash_table_new(g_direct_hash, g_direct_equal); m->recreate_fds = 1; pipe(m->wakeup_pipe); make_nonblock(m->wakeup_pipe[0]); make_nonblock(m->wakeup_pipe[1]); return m; } APULSE_EXPORT int pa_mainloop_poll(pa_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); long int timeout = m->timeout; pa_time_event *te = g_queue_peek_head(m->timed_events_queue); if (te) { pa_usec_t now = pa_rtclock_now(); long int msecs_till_next_event = microseconds_till_event(now, &te->when) / PA_USEC_PER_MSEC; // Ensure delay is non-negative, even if event is already expired. msecs_till_next_event = MAX(msecs_till_next_event, 0); if (timeout < 0) { // poll() call was supposed to wait for indefinite period of time. timeout = msecs_till_next_event; } else { timeout = MIN(timeout, msecs_till_next_event); } // |timeout| value should fit int limits. timeout = MIN(timeout, INT32_MAX); } int ret; if (m->poll_func) { ret = m->poll_func(m->fds, m->nfds, timeout, m->poll_func_userdata); } else { ret = poll(m->fds, m->nfds, timeout); } return ret; } APULSE_EXPORT int pa_mainloop_prepare(pa_mainloop *m, int timeout) { trace_info_f("P %s m=%p, timeout=%d\n", __func__, m, timeout); m->timeout = timeout; if (m->recreate_fds) { GList *keys = g_hash_table_get_keys(m->events_ht); GList *it; struct pollfd *tmp; m->nfds = g_list_length(keys) + 1; tmp = realloc(m->fds, m->nfds * sizeof(*m->fds)); if (!tmp) return -1; m->fds = tmp; m->fds[0].fd = m->wakeup_pipe[0]; m->fds[0].events = POLLIN; m->fds[0].revents = 0; /* special case for alsa pollfds */ int k = 1; m->alsa_special_cnt = 0; it = keys; while (it) { struct pa_io_event *ioe = it->data; if (ioe->events & 0x80000000u) { m->fds[k].fd = ioe->fd; m->fds[k].events = ioe->events & (~0x80000000u); m->fds[k].revents = 0; ioe->pollfd = &m->fds[k]; k++; m->alsa_special_cnt++; } it = g_list_next(it); } /* normal file descriptors */ it = keys; while (it) { struct pa_io_event *ioe = it->data; if ((ioe->events & 0x80000000u) == 0) { m->fds[k].fd = ioe->fd; m->fds[k].events = from_pa_io_event_flags(ioe->events); m->fds[k].revents = 0; ioe->pollfd = &m->fds[k]; k++; } it = g_list_next(it); } m->nfds = k; g_list_free(keys); m->recreate_fds = 0; } return 0; } APULSE_EXPORT void pa_mainloop_quit(pa_mainloop *m, int r) { trace_info_f("F %s m=%p, r=%d\n", __func__, m, r); m->retval = r; m->terminate = 1; pa_mainloop_wakeup(m); } APULSE_EXPORT int pa_mainloop_run(pa_mainloop *m, int *retval) { trace_info_f("F %s\n", __func__); int ret; do { ret = pa_mainloop_iterate(m, 1, retval); } while (ret >= 0 && !m->terminate); if (m->terminate) { *retval = m->retval; return 0; } return ret; } APULSE_EXPORT void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { trace_info_f("F %s m=%p, poll_func=%p, userdata=%p\n", __func__, m, poll_func, userdata); m->poll_func = poll_func; m->poll_func_userdata = userdata; } APULSE_EXPORT void pa_mainloop_wakeup(pa_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); char c = '!'; write(m->wakeup_pipe[1], &c, 1); } apulse-0.1.13/src/apulse-misc.c000066400000000000000000000145741364710014100162520ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" #include "util.h" APULSE_EXPORT const char * pa_get_library_version(void) { trace_info_f("F %s (void)\n", __func__); return pa_get_headers_version(); } APULSE_EXPORT int pa_sample_format_valid(unsigned format) { return format < PA_SAMPLE_MAX; } APULSE_EXPORT int pa_sample_rate_valid(uint32_t rate) { return 0 < rate && rate <= PA_RATE_MAX; } APULSE_EXPORT int pa_channels_valid(uint8_t channels) { return 0 < channels && channels <= PA_CHANNELS_MAX; } APULSE_EXPORT int pa_sample_spec_valid(const pa_sample_spec *spec) { return spec && pa_sample_format_valid(spec->format) && pa_sample_rate_valid(spec->rate) && pa_channels_valid(spec->channels); } APULSE_EXPORT const char * pa_strerror(int error) { trace_info_f("P %s error=%d\n", __func__, error); return "Oops."; } APULSE_EXPORT size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { return t * pa_bytes_per_second(spec) / (1000 * 1000); } APULSE_EXPORT pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { size_t bytes_per_second = pa_bytes_per_second(spec); if (bytes_per_second == 0) return 0; return 1000 * 1000 * length / bytes_per_second; } APULSE_EXPORT size_t pa_bytes_per_second(const pa_sample_spec *spec) { return spec->rate * pa_frame_size(spec); } APULSE_EXPORT size_t pa_frame_size(const pa_sample_spec *spec) { return spec->channels * pa_sample_size(spec); } APULSE_EXPORT size_t pa_sample_size(const pa_sample_spec *spec) { switch (spec->format) { case PA_SAMPLE_U8: case PA_SAMPLE_ALAW: case PA_SAMPLE_ULAW: return 1; case PA_SAMPLE_S16LE: case PA_SAMPLE_S16BE: return 2; case PA_SAMPLE_S24LE: case PA_SAMPLE_S24BE: return 3; case PA_SAMPLE_FLOAT32LE: case PA_SAMPLE_FLOAT32BE: case PA_SAMPLE_S32LE: case PA_SAMPLE_S32BE: case PA_SAMPLE_S24_32LE: case PA_SAMPLE_S24_32BE: case PA_SAMPLE_MAX: return 4; case PA_SAMPLE_INVALID: default: return 0; } } APULSE_EXPORT pa_cvolume * pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { trace_info_f("F %s a=%p, channels=%u, v=%u\n", __func__, a, channels, v); a->channels = MIN(channels, PA_CHANNELS_MAX); for (unsigned int k = 0; k < a->channels; k++) a->values[k] = CLAMP(v, PA_VOLUME_MUTED, PA_VOLUME_MAX); return a; } APULSE_EXPORT pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { trace_info_z("Z %s a=%p\n", __func__, a); return 0; } APULSE_EXPORT const char * pa_sample_format_to_string(pa_sample_format_t format) { switch (format) { case PA_SAMPLE_U8: return "u8"; case PA_SAMPLE_ALAW: return "aLaw"; case PA_SAMPLE_ULAW: return "uLaw"; case PA_SAMPLE_S16LE: return "s16le"; case PA_SAMPLE_S16BE: return "s16be"; case PA_SAMPLE_FLOAT32LE: return "float32le"; case PA_SAMPLE_FLOAT32BE: return "float32be"; case PA_SAMPLE_S32LE: return "s32le"; case PA_SAMPLE_S32BE: return "s32be"; case PA_SAMPLE_S24LE: return "s24le"; case PA_SAMPLE_S24BE: return "s24be"; case PA_SAMPLE_S24_32LE: return "s24-32le"; case PA_SAMPLE_S24_32BE: return "s24-32be"; default: return NULL; } } APULSE_EXPORT char * pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { gchar *s_spec = trace_pa_sample_spec_as_string(spec); trace_info_f("F %s s=%p, l=%u, spec=%s\n", __func__, s, (unsigned)l, s_spec); g_free(s_spec); if (spec && pa_sample_spec_valid(spec)) { snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); } else { snprintf(s, l, "invalid"); } return s; } APULSE_EXPORT char * pa_path_get_filename(const char *p) { char *last_slash; if (!p) return NULL; last_slash = strrchr(p, '/'); if (!last_slash) return (char *)p; return last_slash + 1; } APULSE_EXPORT pa_usec_t pa_rtclock_now(void) { trace_info_f("F %s (void)\n", __func__); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return (pa_usec_t)now.tv_sec * 1000000 + now.tv_nsec / 1000; } APULSE_EXPORT void pa_xfree(void *p) { free(p); } APULSE_EXPORT void * pa_xmalloc(size_t size) { return malloc(size); } APULSE_EXPORT void * pa_xmalloc0(size_t l) { return calloc(l, 1); } APULSE_EXPORT char * pa_locale_to_utf8(const char *str) { trace_info_z("Z %s\n", __func__); return strdup(str); } APULSE_EXPORT char * pa_get_binary_name(char *s, size_t len) { trace_info_f("F %s s=%p, len=%d\n", __func__, s, (int)len); if (len == 0) return NULL; char fullpath[PATH_MAX]; ssize_t flen = readlink("/proc/self/exe", fullpath, sizeof(fullpath) - 1); if (flen < 0) return NULL; // ensure fullpath ends with '\0' flen = MIN(flen, sizeof(fullpath) - 1); fullpath[flen] = 0; char *name = basename(fullpath); size_t name_len = strlen(name); // copy no more than len bytes to s name_len = MIN(name_len, len - 1); memcpy(s, name, name_len); s[name_len] = 0; return s; } apulse-0.1.13/src/apulse-operation.c000066400000000000000000000054241364710014100173110ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" static void deh_perform_operation(pa_mainloop_api *api, pa_defer_event *de, void *userdata) { pa_operation *op = userdata; op->handler(op); } pa_operation * pa_operation_new(pa_mainloop_api *api, void (*handler)(pa_operation *op)) { pa_operation *o = g_slice_new0(pa_operation); o->state = PA_OPERATION_RUNNING; o->ref_cnt = 1; o->api = api; o->handler = handler; return o; } void pa_operation_launch(pa_operation *op) { pa_mainloop_api *api = op->api; api->defer_new(api, deh_perform_operation, pa_operation_ref(op)); } void pa_operation_done(pa_operation *op) { op->state = PA_OPERATION_DONE; pa_operation_unref(op); } APULSE_EXPORT void pa_operation_cancel(pa_operation *o) { trace_info_z("Z %s o=%p\n", __func__, o); } APULSE_EXPORT pa_operation_state_t pa_operation_get_state(pa_operation *o) { trace_info_f("F %s o=%p\n", __func__, o); if (!o) { trace_error("Z %s operation is NULL\n", __func__); return PA_OPERATION_DONE; } return o->state; } APULSE_EXPORT pa_operation * pa_operation_ref(pa_operation *o) { trace_info_f("F %s o=%p\n", __func__, o); if (!o) return NULL; o->ref_cnt++; return o; } APULSE_EXPORT void pa_operation_unref(pa_operation *o) { trace_info_f("F %s o=%p\n", __func__, o); if (!o) return; o->ref_cnt--; if (o->ref_cnt == 0) g_slice_free(pa_operation, o); } APULSE_EXPORT void pa_operation_set_state_callback(pa_operation *o, pa_operation_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } apulse-0.1.13/src/apulse-proplist.c000066400000000000000000000123761364710014100171710ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" struct prop { size_t len; char *data; }; APULSE_EXPORT void pa_proplist_free(pa_proplist *p) { trace_info_f("F %s p=%p\n", __func__, p); g_hash_table_destroy(p->ht); free(p); } static void string_destroy_func(gpointer data) { free(data); } static void prop_destroy_func(gpointer data) { struct prop *p = data; free(p->data); g_slice_free1(sizeof(*p), p); } APULSE_EXPORT pa_proplist * pa_proplist_new(void) { trace_info_f("F %s (void)\n", __func__); pa_proplist *p = calloc(1, sizeof(pa_proplist)); p->ht = g_hash_table_new_full(g_str_hash, g_str_equal, string_destroy_func, prop_destroy_func); return p; } APULSE_EXPORT int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) { trace_info_f("F %s p=%p, key=%s, data=%p, nbytes=%d\n", __func__, p, key, data, (int)nbytes); struct prop *v = g_slice_alloc(sizeof(*v)); if (!v) return -1; v->data = g_memdup(data, nbytes); v->len = nbytes; g_hash_table_insert(p->ht, strdup(key), v); return 0; } APULSE_EXPORT int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) { trace_info_f("F %s p=%p, key=%s, value=%s\n", __func__, p, key, value); struct prop *v = g_slice_alloc(sizeof(*v)); if (!v) return -1; v->data = strdup(value); v->len = strlen(value) + 1; g_hash_table_insert(p->ht, strdup(key), v); return 0; } APULSE_EXPORT void pa_proplist_clear(pa_proplist *p) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, const pa_proplist *other) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT int pa_proplist_contains(pa_proplist *p, const char *key) { trace_info_f("F %s p=%p, key=%s\n", __func__, p, key); return g_hash_table_lookup(p->ht, key) != NULL; } APULSE_EXPORT const char * pa_proplist_gets(pa_proplist *p, const char *key) { trace_info_f("F %s p=%p, key=%s\n", __func__, p, key); struct prop *v = g_hash_table_lookup(p->ht, key); if (!v) return NULL; if (v->len == 0) return NULL; if (v->data[v->len - 1] != '\0') return NULL; // not a string return v->data; } APULSE_EXPORT pa_proplist * pa_proplist_copy(const pa_proplist *p) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT unsigned pa_proplist_size(pa_proplist *p) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_isempty(pa_proplist *p) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_equal(pa_proplist *a, pa_proplist *b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_key_valid(const char *key) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_setp(pa_proplist *p, const char *pair) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_unset(pa_proplist *p, const char *key) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_proplist_unset_many(pa_proplist *p, const char *const keys[]) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT const char * pa_proplist_iterate(pa_proplist *p, void **state) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_proplist_to_string(pa_proplist *p) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_proplist_to_string_sep(pa_proplist *p, const char *sep) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_proplist * pa_proplist_from_string(const char *str) { trace_info_z("Z %s\n", __func__); return NULL; } apulse-0.1.13/src/apulse-signal.c000066400000000000000000000034051364710014100165630ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" APULSE_EXPORT int pa_signal_init(pa_mainloop_api *api) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT void pa_signal_done(void) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT pa_signal_event * pa_signal_new(int sig, pa_signal_cb_t callback, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void pa_signal_free(pa_signal_event *e) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t callback) { trace_info_z("Z %s\n", __func__); } apulse-0.1.13/src/apulse-simple.c000066400000000000000000000211501364710014100165740ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" #include APULSE_EXPORT void pa_simple_free(pa_simple *s) { trace_info_f("F %s s=%p\n", __func__, s); if (s->initialized) { pa_stream_unref(s->stream); pa_context_disconnect(s->context); pa_context_unref(s->context); pa_threaded_mainloop_free(s->mainloop); s->initialized = 0; } free(s); } static void pai_simple_context_state_cb(pa_context *c, void *user_data) { pa_threaded_mainloop *mainloop = user_data; switch (pa_context_get_state(c)) { case PA_CONTEXT_READY: case PA_CONTEXT_TERMINATED: case PA_CONTEXT_FAILED: pa_threaded_mainloop_signal(mainloop, 0); break; default: break; } } static void pai_simple_stream_state_cb(pa_stream *s, void *user_data) { pa_simple *simple = user_data; switch (pa_stream_get_state(s)) { case PA_STREAM_READY: case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: pa_threaded_mainloop_signal(simple->mainloop, 0); break; default: break; } } static void pai_simple_stream_write_cb(pa_stream *s, size_t length, void *user_data) { pa_simple *simple = user_data; pa_threaded_mainloop_signal(simple->mainloop, 0); } static void pai_simple_stream_read_cb(pa_stream *s, size_t length, void *user_data) { pa_simple *simple = user_data; pa_threaded_mainloop_signal(simple->mainloop, 0); } static void pai_simple_stream_latency_update_cb(pa_stream *s, void *user_data) { pa_simple *simple = user_data; pa_threaded_mainloop_signal(simple->mainloop, 0); } static int pai_simple_stream_connect(pa_simple *simple, pa_stream_direction_t dir, const char *stream_name, const pa_sample_spec *ss, const pa_buffer_attr *attr) { simple->stream = pa_stream_new(simple->context, stream_name, ss, NULL); if (!simple->stream) { trace_error("%s: can't create stream", __func__); goto err_1; } pa_stream_set_state_callback(simple->stream, pai_simple_stream_state_cb, simple); pa_stream_set_read_callback(simple->stream, pai_simple_stream_read_cb, simple); pa_stream_set_write_callback(simple->stream, pai_simple_stream_write_cb, simple); pa_stream_set_latency_update_callback( simple->stream, pai_simple_stream_latency_update_cb, simple); if (dir == PA_STREAM_PLAYBACK) { if (pa_stream_connect_playback(simple->stream, NULL, attr, 0, NULL, NULL) < 0) { trace_error("%s: can't connect playback stream", __func__); goto err_2; } } else { int flags = PA_STREAM_ADJUST_LATENCY; if (pa_stream_connect_record(simple->stream, NULL, attr, flags) < 0) { trace_error("%s: can't connect record stream", __func__); goto err_2; } } while (1) { pa_stream_state_t state = pa_stream_get_state(simple->stream); if (state == PA_STREAM_READY) break; if (!PA_STREAM_IS_GOOD(state)) { trace_error("%s, stream is not ready\n", __func__); goto err_2; } pa_threaded_mainloop_wait(simple->mainloop); } return 0; err_2: pa_stream_unref(simple->stream); err_1: return -1; } APULSE_EXPORT pa_simple * pa_simple_new(const char *server, const char *name, pa_stream_direction_t dir, const char *dev, const char *stream_name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_buffer_attr *attr, int *error) { gchar *s_map = trace_pa_channel_map_as_string(map); gchar *s_ss = trace_pa_sample_spec_as_string(ss); trace_info_f( "F %s server=%s, name=%s, dir=%d, dev=%s, stream_name=%s, ss=%s, " "map=%s, attr=%p\n", __func__, server, name, dir, dev, stream_name, s_ss, s_map, attr); g_free(s_ss); g_free(s_map); pa_simple *simple = calloc(sizeof(*simple), 1); if (!simple) { trace_error("%s: can't allocate memory", __func__); return NULL; } simple->mainloop = pa_threaded_mainloop_new(); if (!simple->mainloop) { trace_error("%s: can't create mainloop", __func__); goto err_1; } simple->context = pa_context_new(pa_threaded_mainloop_get_api(simple->mainloop), name); if (!simple->context) { trace_error("%s: can't create context", __func__); goto err_2; } pa_context_set_state_callback(simple->context, pai_simple_context_state_cb, simple->mainloop); if (pa_context_connect(simple->context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) { trace_error("%s: can't connect context", __func__); goto err_3; } pa_threaded_mainloop_lock(simple->mainloop); if (pa_threaded_mainloop_start(simple->mainloop) < 0) { trace_error("%s: can't start mainloop", __func__); goto err_4; } pa_threaded_mainloop_wait(simple->mainloop); if (pa_context_get_state(simple->context) != PA_CONTEXT_READY) { trace_error("%s: can't get context ready", __func__); goto err_5; } if (pai_simple_stream_connect(simple, dir, stream_name, ss, attr) < 0) { trace_error("%s: can't connect stream", __func__); goto err_5; } pa_threaded_mainloop_unlock(simple->mainloop); simple->initialized = 1; return simple; err_5: pa_threaded_mainloop_unlock(simple->mainloop); err_4: pa_context_disconnect(simple->context); err_3: pa_context_unref(simple->context); err_2: pa_threaded_mainloop_free(simple->mainloop); err_1: free(simple); // TODO: error codes if (error) *error = -1; return NULL; } APULSE_EXPORT int pa_simple_write(pa_simple *s, const void *data, size_t bytes, int *error) { trace_info_f("F %s s=%p, data=%p, bytes=%zu, error=%p\n", __func__, s, data, bytes, error); size_t to_write = bytes; const char *p = data; pa_threaded_mainloop_lock(s->mainloop); while (to_write > 0) { size_t chunk_size = pa_stream_writable_size(s->stream); while (chunk_size == 0) { // Sleep here until write callback is called. pa_threaded_mainloop_wait(s->mainloop); chunk_size = pa_stream_writable_size(s->stream); } chunk_size = MIN(chunk_size, to_write); if (pa_stream_write(s->stream, p, chunk_size, NULL, 0, PA_SEEK_RELATIVE) < 0) { trace_error("%s: can't write", __func__); goto err; } p += chunk_size; to_write -= chunk_size; } pa_threaded_mainloop_unlock(s->mainloop); return 0; err: pa_threaded_mainloop_unlock(s->mainloop); return -1; } APULSE_EXPORT int pa_simple_drain(pa_simple *s, int *error) { trace_info_z("Z %s\n", __func__); return -1; } APULSE_EXPORT int pa_simple_read(pa_simple *s, void *data, size_t bytes, int *error) { trace_info_z("Z %s\n", __func__); return -1; } APULSE_EXPORT pa_usec_t pa_simple_get_latency(pa_simple *s, int *error) { trace_info_f("F %s s=%p, error=%p\n", __func__, s, error); pa_usec_t latency = 0; int negative; pa_stream_get_latency(s->stream, &latency, &negative); return latency; } APULSE_EXPORT int pa_simple_flush(pa_simple *s, int *error) { trace_info_z("Z %s\n", __func__); return -1; } apulse-0.1.13/src/apulse-stream.c000066400000000000000000001142701364710014100166040ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" #include "util.h" #define MAKE_SND_LIB_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c)) #define HAVE_SND_PCM_AVAIL SND_LIB_VERSION >= MAKE_SND_LIB_VERSION(1, 0, 18) static void deh_stream_state_changed(pa_mainloop_api *api, pa_defer_event *de, void *userdata) { pa_stream *s = userdata; if (s->state_cb) s->state_cb(s, s->state_cb_userdata); pa_stream_unref(s); } static void deh_stream_first_readwrite_callback(pa_mainloop_api *api, pa_defer_event *de, void *userdata) { pa_stream *s = userdata; if (s->direction == PA_STREAM_PLAYBACK) { size_t writable_size = pa_stream_writable_size(s); if (s->write_cb && writable_size > 0) s->write_cb(s, writable_size, s->write_cb_userdata); } else if (s->direction == PA_STREAM_RECORD) { size_t readable_size = pa_stream_readable_size(s); if (s->read_cb && readable_size > 0) s->read_cb(s, readable_size, s->read_cb_userdata); } pa_stream_unref(s); } static void data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_event_flags_t events, void *userdata) { pa_stream *s = userdata; snd_pcm_sframes_t frame_count; size_t frame_size = pa_frame_size(&s->ss); char buf[16 * 1024]; const size_t buf_size = pa_find_multiple_of(sizeof(buf), frame_size, 0); int paused = g_atomic_int_get(&s->paused); if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT)) { #if HAVE_SND_PCM_AVAIL frame_count = snd_pcm_avail(s->ph); #else snd_pcm_hwsync(s->ph); frame_count = snd_pcm_avail_update(s->ph); #endif if (frame_count < 0) { if (frame_count == -EBADFD) { // stream was closed return; } int cnt = 0, ret; do { cnt++; ret = snd_pcm_recover(s->ph, frame_count, 1); } while (ret == -1 && errno == EINTR && cnt < 5); switch (snd_pcm_state(s->ph)) { case SND_PCM_STATE_OPEN: // Highly unlikely device will be here in this state. But if it // is, there is nothing can be done. trace_error( "Stream '%s' of context '%s' have its associated PCM " "device in SND_PCM_STATE_OPEN state. Reconfiguration is " "required, but is not possible at the moment. Giving up.", s->name ? s->name : "", s->c->name ? s->c->name : ""); break; case SND_PCM_STATE_SETUP: // There is configuration, but device is not prepared and not // started. snd_pcm_prepare(s->ph); snd_pcm_start(s->ph); break; case SND_PCM_STATE_PREPARED: // Device prepared, but not started. snd_pcm_start(s->ph); break; case SND_PCM_STATE_RUNNING: // That's the expected state. break; case SND_PCM_STATE_XRUN: trace_error( "Stream '%s' of context '%s' have its associated device in " "SND_PCM_STATE_XRUN state even after xrun recovery.", s->name ? s->name : "", s->c->name ? s->c->name : ""); break; case SND_PCM_STATE_DRAINING: trace_error( "Stream '%s' of context '%s' have its associated device in " "SND_PCM_STATE_DRAINING state, which is highly unusual.", s->name ? s->name : "", s->c->name ? s->c->name : ""); break; case SND_PCM_STATE_PAUSED: // Resume from paused state. snd_pcm_pause(s->ph, 0); break; case SND_PCM_STATE_SUSPENDED: // Resume from suspended state. snd_pcm_resume(s->ph); break; case SND_PCM_STATE_DISCONNECTED: trace_error( "Stream '%s' of context '%s' have its associated device in " "SND_PCM_STATE_DISCONNECTED state. Giving up.", s->name ? s->name : "", s->c->name ? s->c->name : ""); break; default: // avoid compiler warnings of unhandled (library-private) enum values break; } #if HAVE_SND_PCM_AVAIL frame_count = snd_pcm_avail(s->ph); #else snd_pcm_hwsync(s->ph); frame_count = snd_pcm_avail_update(s->ph); #endif if (frame_count < 0) { trace_error( "%s, can't recover after failed snd_pcm_avail (%d)\n", __func__, (int)frame_count); return; } } } else { return; } if (events & PA_IO_EVENT_OUTPUT) { if (paused) { // client stream is corked. Pass silence to ALSA size_t bytecnt = MIN(buf_size, frame_count * frame_size); memset(buf, 0, bytecnt); snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } else { size_t writable_size = pa_stream_writable_size(s); // Ask client for data, but only if we are ready for at least // |minreq| bytes. if (s->write_cb && writable_size >= s->buffer_attr.minreq) s->write_cb(s, s->buffer_attr.minreq, s->write_cb_userdata); size_t bytecnt = MIN(buf_size, frame_count * frame_size); bytecnt = ringbuffer_read(s->rb, buf, bytecnt); pa_apply_volume_multiplier(buf, bytecnt, s->volume, &s->ss); if (bytecnt == 0) { // application is not ready yet, play silence bytecnt = MIN(buf_size, frame_count * frame_size); memset(buf, 0, bytecnt); } snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } } if (events & PA_IO_EVENT_INPUT) { if (paused) { // client stream is corked. Read data from ALSA and discard them size_t bytecnt = MIN(buf_size, frame_count * frame_size); snd_pcm_readi(s->ph, buf, bytecnt / frame_size); } else { size_t bytecnt = ringbuffer_writable_size(s->rb); if (bytecnt == 0) { // ringbuffer is full because app doesn't read data fast enough. // Make some room ringbuffer_drop(s->rb, frame_count * frame_size); bytecnt = ringbuffer_writable_size(s->rb); } bytecnt = MIN(bytecnt, frame_count * frame_size); bytecnt = MIN(bytecnt, buf_size); if (bytecnt > 0) { snd_pcm_readi(s->ph, buf, bytecnt / frame_size); pa_apply_volume_multiplier(buf, bytecnt, s->c->source_volume, &s->ss); ringbuffer_write(s->rb, buf, bytecnt); } size_t readable_size = pa_stream_readable_size(s); if (s->read_cb && readable_size > 0) s->read_cb(s, readable_size, s->read_cb_userdata); } } } static int do_connect_pcm(pa_stream *s, snd_pcm_stream_t stream_direction) { snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; int errcode = 0; const char *device_name; const char *direction_name; switch (stream_direction) { default: case SND_PCM_STREAM_PLAYBACK: device_name = getenv("APULSE_PLAYBACK_DEVICE"); direction_name = "playback"; break; case SND_PCM_STREAM_CAPTURE: device_name = getenv("APULSE_CAPTURE_DEVICE"); direction_name = "capture"; break; } if (device_name == NULL) device_name = "default"; char *device_description = g_strdup_printf("%s device \"%s\"", direction_name, device_name); if (!device_description) { trace_error("%s: can't allocate memory for device description string\n", __func__); goto fatal_error; } errcode = snd_pcm_open(&s->ph, device_name, stream_direction, 0); if (errcode < 0) { trace_error("%s: can't open %s. Error code %d (%s)\n", __func__, device_description, errcode, snd_strerror(errcode)); goto fatal_error; } errcode = snd_pcm_hw_params_malloc(&hw_params); if (errcode < 0) { trace_error( "%s: can't allocate memory for hw parameters for %s. Error code %d " "(%s)\n", __func__, device_description, errcode, snd_strerror(errcode)); goto fatal_error; } errcode = snd_pcm_hw_params_any(s->ph, hw_params); if (errcode < 0) { trace_error( "%s: can't get initial hw parameters for %s. Error code %d (%s)\n", __func__, device_description, errcode, snd_strerror(errcode)); goto fatal_error; } errcode = snd_pcm_hw_params_set_access(s->ph, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (errcode < 0) { trace_error( "%s: can't select interleaved mode for %s. Error code %d (%s)\n", __func__, device_description, errcode, snd_strerror(errcode)); // TODO: is it worth to support non-interleaved mode? goto fatal_error; } errcode = snd_pcm_hw_params_set_format(s->ph, hw_params, pa_format_to_alsa(s->ss.format)); if (errcode < 0) { snd_pcm_format_t alsa_format = pa_format_to_alsa(s->ss.format); trace_error( "%s: can't set sample format %d (\"%s\") for %s. Error code %d " "(%s)\n", __func__, alsa_format, snd_pcm_format_name(alsa_format), device_description, errcode, snd_strerror(errcode)); goto fatal_error; } errcode = snd_pcm_hw_params_set_rate_resample(s->ph, hw_params, 1); if (errcode < 0) { trace_error( "%s: can't enable rate resample for %s. Error code %d (%s)\n", __func__, device_description, errcode, snd_strerror(errcode)); // This is not a fatal error. Audio speed will be wrong, but there will // be something. } unsigned int rate = s->ss.rate; int dir = 0; errcode = snd_pcm_hw_params_set_rate_near(s->ph, hw_params, &rate, &dir); if (errcode < 0) { trace_error("%s: can't set sample rate for %s. Error code %d (%s)\n", __func__, device_description, errcode, snd_strerror(errcode)); goto fatal_error; } trace_info_f("%s: demanded %d Hz sample rate, got %d Hz for %s, dir = %d\n", __func__, (int)s->ss.rate, (int)rate, device_description, dir); if (rate != s->ss.rate) trace_error( "%s: actual sample rate, %d Hz, differs from required %d Hz\n", __func__, (int)rate, (int)s->ss.rate); errcode = snd_pcm_hw_params_set_channels(s->ph, hw_params, s->ss.channels); if (errcode < 0) { trace_error( "%s: can't set channel count to %d for %s. Error code %d (%s)\n", __func__, (int)s->ss.channels, device_description, errcode, snd_strerror(errcode)); // TODO: channel count handling? goto fatal_error; } const size_t frame_size = pa_frame_size(&s->ss); snd_pcm_uframes_t requested_period_size = s->buffer_attr.minreq / frame_size; snd_pcm_uframes_t period_size = requested_period_size; dir = 1; // Prefer larger period sizes, if exact is not possible. errcode = snd_pcm_hw_params_set_period_size_near(s->ph, hw_params, &period_size, &dir); if (errcode < 0) { trace_error( "%s: can't set period size to %d frames for %s. Error code %d " "(%s)\n", __func__, (int)requested_period_size, device_description, errcode, snd_strerror(errcode)); goto fatal_error; } trace_info_f( "%s: requested period size of %d frames, got %d frames for %s\n", __func__, (int)requested_period_size, (int)period_size, device_description); // Set up buffer size. Ensure it's at least four times larger than a period // size. snd_pcm_uframes_t requested_buffer_size = s->buffer_attr.tlength / frame_size; snd_pcm_uframes_t buffer_size = MAX(requested_buffer_size, 4 * period_size); errcode = snd_pcm_hw_params_set_buffer_size_near(s->ph, hw_params, &buffer_size); if (errcode < 0) { trace_error( "%s: can't set buffer size to %d frames for %s. Error code %d " "(%s)\n", __func__, (int)buffer_size, device_description, errcode, snd_strerror(errcode)); goto fatal_error; } trace_info_f( "%s: requested buffer size of %d frames, got %d frames for %s\n", __func__, (int)requested_buffer_size, (int)buffer_size, device_description); errcode = snd_pcm_hw_params(s->ph, hw_params); if (errcode < 0) { trace_error("%s: can't apply configured hw parameter block for %s\n", __func__, device_description); goto fatal_error; } snd_pcm_hw_params_free(hw_params); errcode = snd_pcm_sw_params_malloc(&sw_params); if (errcode < 0) { trace_error("%s: can't allocate memory for sw parameters for %s\n", __func__, device_description); goto fatal_error; } errcode = snd_pcm_sw_params_current(s->ph, sw_params); if (errcode < 0) { trace_error("%s: can't acquire current sw parameters for %s\n", __func__, device_description); goto fatal_error; } errcode = snd_pcm_sw_params_set_avail_min(s->ph, sw_params, period_size); if (errcode < 0) { trace_error("%s: can't set avail min for %s\n", __func__, device_description); goto fatal_error; } // no period event requested errcode = snd_pcm_sw_params(s->ph, sw_params); if (errcode < 0) { trace_error("%s: can't apply sw parameters for %s\n", __func__, device_description); goto fatal_error; } snd_pcm_sw_params_free(sw_params); errcode = snd_pcm_prepare(s->ph); if (errcode < 0) { trace_error("%s: can't prepare PCM device to use for %s\n", __func__, device_description); goto fatal_error; } int nfds = snd_pcm_poll_descriptors_count(s->ph); struct pollfd *fds = calloc(nfds, sizeof(struct pollfd)); s->ioe = calloc(nfds, sizeof(pa_io_event *)); s->nioe = nfds; snd_pcm_poll_descriptors(s->ph, fds, nfds); for (int k = 0; k < nfds; k++) { pa_mainloop_api *api = s->c->mainloop_api; s->ioe[k] = api->io_new(api, fds[k].fd, 0x80000000 | fds[k].events, data_available_for_stream, s); s->ioe[k]->pcm = s->ph; } free(fds); s->state = PA_STREAM_READY; pa_stream_ref(s); s->c->mainloop_api->defer_new(s->c->mainloop_api, deh_stream_state_changed, s); pa_stream_ref(s); s->c->mainloop_api->defer_new(s->c->mainloop_api, deh_stream_first_readwrite_callback, s); g_free(device_description); return 0; fatal_error: trace_error( "%s: failed to open ALSA device. Apulse does no resampling or format " "conversion, leaving that task to ALSA plugins. Ensure that selected " "device is capable of playing a particular sample format at a " "particular rate. They have to be supported by either hardware " "directly, or by \"plug\" and \"dmix\" ALSA plugins which will perform " "required conversions on CPU.\n", __func__); if (errcode == -EACCES) { trace_error( "%s: additionally, the error code is %d, which means access was " "denied. That looks like access restriction in a sandbox. If the " "app you are running uses sandboxing techniques, make sure " "/dev/snd/ directory is added into the allowed list. Both reading " "and writing access to the files in that directory are required.\n", __func__, -EACCES); } g_free(device_description); return -1; } APULSE_EXPORT int pa_stream_begin_write(pa_stream *p, void **data, size_t *nbytes) { trace_info_f("F %s p=%p nbytes=%p(%" PRIu64 ")\n", __func__, p, nbytes, (uint64_t)(nbytes ? *nbytes : 0)); free(p->write_buffer); if (*nbytes == (size_t)-1) *nbytes = 8192; *nbytes = pa_find_multiple_of(*nbytes, pa_frame_size(&p->ss), 0); p->write_buffer = malloc(*nbytes); if (!p->write_buffer) return -1; *data = p->write_buffer; return 0; } APULSE_EXPORT int pa_stream_cancel_write(pa_stream *p) { trace_info_f("F %s p=%p\n", __func__, p); free(p->write_buffer); p->write_buffer = NULL; return 0; } static void stream_adjust_buffer_attrs(pa_stream *s, const pa_buffer_attr *attr) { pa_buffer_attr *ba = &s->buffer_attr; const size_t frame_size = pa_frame_size(&s->ss); if (attr) { *ba = *attr; } else { // If client passed NULL, all parameters have default values. ba->maxlength = (uint32_t)-1; ba->tlength = (uint32_t)-1; ba->prebuf = (uint32_t)-1; ba->minreq = (uint32_t)-1; ba->fragsize = (uint32_t)-1; } // Adjust default values. // Overall buffer length. if (ba->maxlength == (uint32_t)-1) ba->maxlength = 4 * 1024 * 1024; if (ba->maxlength == 0) ba->maxlength = frame_size; // Target length of a buffer. if (ba->tlength == (uint32_t)-1) ba->tlength = pa_usec_to_bytes(2 * 1000 * 1000, &s->ss); if (ba->tlength == 0) ba->tlength = frame_size; ba->tlength = MIN(ba->tlength, ba->maxlength); // Minimum request (playback). if (ba->minreq == (uint32_t)-1) { ba->minreq = pa_usec_to_bytes(20 * 1000, &s->ss); ba->minreq = MIN(ba->minreq, ba->tlength / 4); } if (ba->minreq == 0) ba->minreq = frame_size; // Fragment size (recording). if (ba->fragsize == (uint32_t)-1) { ba->fragsize = pa_usec_to_bytes(20 * 1000, &s->ss); } if (ba->fragsize == 0) ba->fragsize = frame_size; // Pre-buffering. if (ba->prebuf == (uint32_t)-1) ba->prebuf = ba->tlength - ba->minreq; if (ba->prebuf > ba->tlength - ba->minreq) ba->prebuf = ba->tlength - ba->minreq; // Ensure values are all multiple of |frame_size|. ba->maxlength = pa_find_multiple_of(ba->maxlength, frame_size, 1); ba->tlength = pa_find_multiple_of(ba->tlength, frame_size, 1); ba->prebuf = pa_find_multiple_of(ba->prebuf, frame_size, 1); ba->minreq = pa_find_multiple_of(ba->minreq, frame_size, 1); ba->fragsize = pa_find_multiple_of(ba->fragsize, frame_size, 1); } APULSE_EXPORT int pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream) { gchar *s_attr = trace_pa_buffer_attr_as_string(attr); trace_info_f( "P %s s=%p, dev=%s, attr=%s, flags=0x%x, volume=%p, sync_stream=%p\n", __func__, s, dev, s_attr, flags, volume, sync_stream); g_free(s_attr); s->direction = PA_STREAM_PLAYBACK; stream_adjust_buffer_attrs(s, attr); if (do_connect_pcm(s, SND_PCM_STREAM_PLAYBACK) < 0) goto err; g_atomic_int_set(&s->paused, !!(flags & PA_STREAM_START_CORKED)); return 0; err: return -1; } static void pa_stream_cork_impl(pa_operation *op) { g_atomic_int_set(&op->s->paused, !!(op->int_arg_1)); if (op->stream_success_cb) op->stream_success_cb(op->s, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, b=%d, cb=%p, userdata=%p\n", __func__, s, b, cb, userdata); pa_operation *op = pa_operation_new(s->c->mainloop_api, pa_stream_cork_impl); op->s = s; op->int_arg_1 = b; op->stream_success_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } APULSE_EXPORT int pa_stream_disconnect(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); if (s->state != PA_STREAM_READY) return PA_ERR_BADSTATE; for (int k = 0; k < s->nioe; k++) { pa_mainloop_api *api = s->c->mainloop_api; api->io_free(s->ioe[k]); } free(s->ioe); snd_pcm_close(s->ph); s->state = PA_STREAM_TERMINATED; return PA_OK; } static void pa_stream_drain_impl(pa_operation *op) { snd_pcm_drain(op->s->ph); if (op->stream_success_cb) op->stream_success_cb(op->s, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); pa_operation *op = pa_operation_new(s->c->mainloop_api, pa_stream_drain_impl); op->s = s; op->stream_success_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } static void pa_stream_flush_impl(pa_operation *op) { // TODO: is it ok to do nothing? if (op->stream_success_cb) op->stream_success_cb(op->s, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); pa_operation *op = pa_operation_new(s->c->mainloop_api, pa_stream_flush_impl); op->s = s; op->stream_success_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } APULSE_EXPORT uint32_t pa_stream_get_index(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return s->idx; } APULSE_EXPORT int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { trace_info_f("F %s s=%p\n", __func__, s); snd_pcm_sframes_t delay; if (snd_pcm_delay(s->ph, &delay) < 0) delay = 0; if (r_usec) *r_usec = 1000 * 1000 * delay / s->ss.rate; if (negative) *negative = 0; return 0; } APULSE_EXPORT const pa_sample_spec * pa_stream_get_sample_spec(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return &s->ss; } APULSE_EXPORT pa_stream_state_t pa_stream_get_state(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return s->state; } APULSE_EXPORT int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { trace_info_f("F %s\n", __func__); // TODO: handle playback/capture delays? int64_t data_index = s->timing_info.write_index; if (data_index < 0) data_index = 0; *r_usec = pa_bytes_to_usec(data_index, &s->ss); return 0; } APULSE_EXPORT const pa_timing_info * pa_stream_get_timing_info(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); snd_pcm_sframes_t delay; if (snd_pcm_delay(s->ph, &delay) < 0) delay = 0; s->timing_info.read_index = s->timing_info.write_index - delay * pa_frame_size(&s->ss); return &s->timing_info; } APULSE_EXPORT int pa_stream_is_corked(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return g_atomic_int_get(&s->paused); } APULSE_EXPORT int pa_stream_is_suspended(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); // ALSA sink is never suspended return 0; } APULSE_EXPORT pa_stream * pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { gchar *s_map = trace_pa_channel_map_as_string(map); gchar *s_ss = trace_pa_sample_spec_as_string(ss); trace_info_f("F %s c=%p, name=%s, ss=%s, map=%s\n", __func__, c, name, s_ss, s_map); g_free(s_ss); g_free(s_map); pa_proplist *p = pa_proplist_new(); pa_stream *s = pa_stream_new_with_proplist(c, name, ss, map, p); pa_proplist_free(p); return s; } APULSE_EXPORT pa_stream * pa_stream_new_extended(pa_context *c, const char *name, pa_format_info *const *formats, unsigned int n_formats, pa_proplist *p) { trace_info_f("P %s c=%p, name=%s, formats=%p, n_formats=%u, p=%p\n", __func__, c, name, formats, n_formats, p); // TODO: multiple formats? // take first format if (n_formats < 1) { trace_error("%s, no formats\n", __func__); return NULL; } pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 48000, .channels = 2, }; const char *val; val = pa_proplist_gets(formats[0]->plist, PA_PROP_FORMAT_SAMPLE_FORMAT); if (val) ss.format = pa_sample_format_from_string(val); val = pa_proplist_gets(formats[0]->plist, PA_PROP_FORMAT_RATE); if (val) ss.rate = atoi(val); val = pa_proplist_gets(formats[0]->plist, PA_PROP_FORMAT_CHANNELS); if (val) ss.channels = atoi(val); return pa_stream_new_with_proplist(c, name, &ss, NULL, p); } APULSE_EXPORT pa_stream * pa_stream_new_with_proplist(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, pa_proplist *p) { gchar *s_map = trace_pa_channel_map_as_string(map); gchar *s_ss = trace_pa_sample_spec_as_string(ss); trace_info_f("F %s c=%p, name=%s, ss=%s, map=%s, p=%p\n", __func__, c, name, s_ss, s_map, p); g_free(s_ss); g_free(s_map); pa_stream *s = calloc(1, sizeof(pa_stream)); s->c = c; s->ref_cnt = 1; s->state = PA_STREAM_UNCONNECTED; s->ss = *ss; s->idx = c->next_stream_idx++; g_hash_table_insert(c->streams_ht, GINT_TO_POINTER(s->idx), s); // fill initial values of s->timing_info gettimeofday(&s->timing_info.timestamp, NULL); s->timing_info.synchronized_clocks = 1; s->timing_info.sink_usec = 0; s->timing_info.source_usec = 0; s->timing_info.transport_usec = 0; s->timing_info.playing = 1; s->timing_info.write_index_corrupt = 0; s->timing_info.write_index = 0; s->timing_info.read_index_corrupt = 0; s->timing_info.read_index = 0; s->timing_info.configured_sink_usec = 0; s->timing_info.configured_source_usec = 0; s->timing_info.since_underrun = 0; s->rb = ringbuffer_new(72 * 1024); // TODO: figure out size s->peek_buffer = malloc(s->rb->end - s->rb->start); for (uint32_t k = 0; k < PA_CHANNELS_MAX; k++) s->volume[k] = PA_VOLUME_NORM; return s; } APULSE_EXPORT pa_stream * pa_stream_ref(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); s->ref_cnt++; return s; } APULSE_EXPORT void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); s->latency_update_cb = cb; s->latency_update_cb_userdata = userdata; } static void pa_stream_set_name_impl(pa_operation *op) { free(op->s->name); op->s->name = op->char_ptr_arg_1; if (op->stream_success_cb) op->stream_success_cb(op->s, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("P %s s=%p, name=%s, cb=%p, userdata=%p\n", __func__, s, name, cb, userdata); pa_operation *op = pa_operation_new(s->c->mainloop_api, pa_stream_set_name_impl); op->s = s; op->stream_success_cb = cb; op->cb_userdata = userdata; op->char_ptr_arg_1 = strdup(name ? name : ""); pa_operation_launch(op); return op; } APULSE_EXPORT void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); s->state_cb = cb; s->state_cb_userdata = userdata; } APULSE_EXPORT void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); s->write_cb = cb; s->write_cb_userdata = userdata; } static void pa_stream_trigger_impl(pa_operation *op) { // TODO: does nothing? if (op->stream_success_cb) op->stream_success_cb(op->s, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); pa_operation *op = pa_operation_new(s->c->mainloop_api, pa_stream_trigger_impl); op->s = s; op->stream_success_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } APULSE_EXPORT void pa_stream_unref(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); s->ref_cnt--; if (s->ref_cnt == 0) { g_hash_table_remove(s->c->streams_ht, GINT_TO_POINTER(s->idx)); ringbuffer_free(s->rb); free(s->peek_buffer); free(s->write_buffer); free(s->name); free(s); } } static void pa_stream_update_timing_info_impl(pa_operation *op) { gettimeofday(&op->s->timing_info.timestamp, NULL); if (op->s->latency_update_cb) op->s->latency_update_cb(op->s, op->s->latency_update_cb_userdata); if (op->stream_success_cb) op->stream_success_cb(op->s, 1, op->cb_userdata); pa_operation_done(op); } APULSE_EXPORT pa_operation * pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); pa_operation *op = pa_operation_new(s->c->mainloop_api, pa_stream_update_timing_info_impl); op->s = s; op->stream_success_cb = cb; op->cb_userdata = userdata; pa_operation_launch(op); return op; } APULSE_EXPORT size_t pa_stream_writable_size(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); size_t writable_size = ringbuffer_writable_size(s->rb); // Some applications try to push more data than reported to be available // by pa_stream_writable_size(), which is fine for original PulseAudio // but is a severe error in this implementation, since buffer size is // limited. // // Workaround issue by reserving certain amount for that case. const size_t limit = 16 * 1024; // TODO: adaptive values? if (writable_size < limit) writable_size = 0; return pa_find_multiple_of(writable_size, pa_frame_size(&s->ss), 0); } APULSE_EXPORT size_t pa_stream_readable_size(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); size_t readable_size = ringbuffer_readable_size(s->rb); return pa_find_multiple_of(readable_size, pa_frame_size(&s->ss), 0); } APULSE_EXPORT int pa_stream_write(pa_stream *s, const void *data, size_t nbytes, pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek) { trace_info_f("F %s s=%p, data=%p, nbytes=%zu, free_cb=%p, offset=%" PRId64 ", seek=%u\n", __func__, s, data, nbytes, free_cb, offset, seek); if (offset != 0) trace_error("%s, offset != 0\n", __func__); if (seek != PA_SEEK_RELATIVE) trace_error("%s, seek != PA_SEEK_RELATIVE\n", __func__); size_t written = ringbuffer_write(s->rb, data, nbytes); s->timing_info.since_underrun += written; s->timing_info.write_index += written; if (data == s->write_buffer) { free(s->write_buffer); s->write_buffer = NULL; } else { if (free_cb) free_cb((void *)data); } return 0; } APULSE_EXPORT int pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { gchar *s_attr = trace_pa_buffer_attr_as_string(attr); trace_info_f("P %s s=%p, dev=%s, attr=%s, flags=0x%x\n", __func__, s, dev, s_attr, flags); g_free(s_attr); s->direction = PA_STREAM_RECORD; stream_adjust_buffer_attrs(s, attr); if (do_connect_pcm(s, SND_PCM_STREAM_CAPTURE) < 0) goto err; snd_pcm_start(s->ph); return 0; err: return -1; } APULSE_EXPORT int pa_stream_drop(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); ringbuffer_drop(s->rb, s->peek_buffer_data_len); return 0; } APULSE_EXPORT const pa_buffer_attr * pa_stream_get_buffer_attr(pa_stream *s) { trace_info_f("F %s\n", __func__); return &s->buffer_attr; } APULSE_EXPORT uint32_t pa_stream_get_device_index(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); // apulse uses only one sink -- ALSA device, so index is always 0 return 0; } APULSE_EXPORT const char * pa_stream_get_device_name(pa_stream *s) { trace_info_f("F %s s=%p\n", __func__, s); return "apulse"; } APULSE_EXPORT int pa_stream_peek(pa_stream *s, const void **data, size_t *nbytes) { trace_info_f("F %s s=%p\n", __func__, s); if (!s) return -1; size_t len = ringbuffer_readable_size(s->rb); s->peek_buffer_data_len = ringbuffer_peek(s->rb, s->peek_buffer, len); if (nbytes) *nbytes = s->peek_buffer_data_len; if (data) *data = s->peek_buffer; return 0; } APULSE_EXPORT void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { trace_info_f("F %s s=%p, cb=%p, userdata=%p\n", __func__, s, cb, userdata); if (s) { s->read_cb = cb; s->read_cb_userdata = userdata; } } APULSE_EXPORT void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT pa_context * pa_stream_get_context(pa_stream *p) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT int64_t pa_stream_get_underflow_index(pa_stream *p) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT void pa_stream_set_started_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_stream_set_moved_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_stream_set_suspended_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_stream_set_event_callback(pa_stream *p, pa_stream_event_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT void pa_stream_set_buffer_attr_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT pa_operation * pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT const pa_channel_map * pa_stream_get_channel_map(pa_stream *s) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT const pa_format_info * pa_stream_get_format_info(pa_stream *s) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_operation * pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT uint32_t pa_stream_get_monitor_stream(pa_stream *s) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_stream_connect_upload(pa_stream *s, size_t length) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_stream_finish_upload(pa_stream *s) { trace_info_z("Z %s\n", __func__); return 0; } apulse-0.1.13/src/apulse-threaded-mainloop.c000066400000000000000000000106651364710014100207100ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _XOPEN_SOURCE 500 #include "apulse.h" #include "trace.h" static void * mainloop_thread(void *param) { pa_threaded_mainloop *m = param; int retval; pthread_mutex_lock(&m->lock); pa_mainloop_run(m->m, &retval); pthread_mutex_unlock(&m->lock); return NULL; } static int poll_func(struct pollfd *fds, nfds_t nfds, int timeout, void *userdata) { pthread_mutex_t *lock = userdata; pthread_mutex_unlock(lock); int ret = poll(fds, nfds, timeout); pthread_mutex_lock(lock); return ret; } APULSE_EXPORT void pa_threaded_mainloop_free(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); if (m->running) pa_threaded_mainloop_stop(m); pthread_mutex_destroy(&m->lock); pthread_cond_destroy(&m->cond); pa_mainloop_free(m->m); free(m); } APULSE_EXPORT pa_mainloop_api * pa_threaded_mainloop_get_api(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); return &m->m->api; } APULSE_EXPORT int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); return pthread_equal(pthread_self(), m->t); } APULSE_EXPORT void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); pthread_mutex_lock(&m->lock); } APULSE_EXPORT pa_threaded_mainloop * pa_threaded_mainloop_new(void) { trace_info_f("F %s (void)\n", __func__); pthread_mutexattr_t mutex_attr; pa_threaded_mainloop *m = calloc(1, sizeof(*m)); m->m = pa_mainloop_new(); pthread_mutexattr_init(&mutex_attr); pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&m->lock, &mutex_attr); pthread_mutexattr_destroy(&mutex_attr); pthread_cond_init(&m->cond, NULL); pa_mainloop_set_poll_func(m->m, poll_func, &m->lock); return m; } APULSE_EXPORT void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { trace_info_f("F %s m=%p, wait_for_accept=%d\n", __func__, m, wait_for_accept); if (wait_for_accept != 0) trace_error("%s, not implemented branch\n", __func__); pthread_cond_signal(&m->cond); } APULSE_EXPORT int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); if (m->running) return 1; pthread_create(&m->t, NULL, mainloop_thread, m); m->running = 1; return 0; } APULSE_EXPORT void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); pa_mainloop_quit(m->m, 0); pthread_join(m->t, NULL); m->running = 0; } APULSE_EXPORT void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); pthread_mutex_unlock(&m->lock); } APULSE_EXPORT void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); pthread_cond_wait(&m->cond, &m->lock); } APULSE_EXPORT void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { trace_info_z("Z %s\n", __func__); } APULSE_EXPORT int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT void pa_threaded_mainloop_set_name(pa_threaded_mainloop *m, const char *name) { trace_info_z("Z %s\n", __func__); } apulse-0.1.13/src/apulse-volume.c000066400000000000000000000204231364710014100166140ustar00rootroot00000000000000/* * Copyright © 2017-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "apulse.h" #include "trace.h" #include #include APULSE_EXPORT pa_volume_t pa_sw_volume_from_linear(double v) { trace_info_f("F %s v=%f\n", __func__, v); if (v <= 0.0) return PA_VOLUME_MUTED; int64_t v_linear = lround(PA_VOLUME_NORM * cbrt(v)); assert(v_linear >= 0); return MIN(v_linear, PA_VOLUME_MAX); } APULSE_EXPORT double pa_sw_volume_to_linear(pa_volume_t v) { trace_info_f("F %s v=%u\n", __func__, v); uint32_t v_clamped = MIN(v, PA_VOLUME_MAX); double v_linear = v_clamped * (1.0 / PA_VOLUME_NORM); return v_linear * v_linear * v_linear; } APULSE_EXPORT char * pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_volume_snprint(char *s, size_t l, pa_volume_t v) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_volume_t pa_cvolume_max(const pa_cvolume *a) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_volume_t pa_cvolume_min(const pa_cvolume *a) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_cvolume_valid(const pa_cvolume *v) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_cvolume * pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_cvolume * pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_volume_t pa_sw_volume_from_dB(double f) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT double pa_sw_volume_to_dB(pa_volume_t v) { trace_info_z("Z %s\n", __func__); return 0.0; } APULSE_EXPORT pa_cvolume * pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return 0.0; } APULSE_EXPORT pa_cvolume * pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { trace_info_z("Z %s\n", __func__); return 0.0; } APULSE_EXPORT pa_cvolume * pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * #if PA_CHECK_VERSION(11, 99, 0) pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, const pa_channel_map *cm, pa_channel_position_mask_t mask) #else pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) #endif { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_cvolume_set_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v) { gchar *s_map = trace_pa_channel_map_as_string(map); gchar *s_t = trace_pa_channel_position_t_as_string(t); trace_info_z("Z %s cv=%p, map=%s, t=%s, v=%u\n", __func__, cv, s_map, s_t, v); g_free(s_t); g_free(s_map); return NULL; } APULSE_EXPORT pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) { gchar *s_map = trace_pa_channel_map_as_string(map); gchar *s_t = trace_pa_channel_position_t_as_string(t); trace_info_z("Z %s cv=%p, map=%s, t=%s\n", __func__, cv, s_map, s_t); g_free(s_t); g_free(s_map); return 0; } APULSE_EXPORT pa_cvolume * pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT pa_cvolume * pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { trace_info_z("Z %s\n", __func__); return 0; } APULSE_EXPORT pa_cvolume * pa_cvolume_init(pa_cvolume *a) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { trace_info_z("Z %s\n", __func__); return NULL; } APULSE_EXPORT char * pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) { trace_info_z("Z %s\n", __func__); return NULL; } apulse-0.1.13/src/apulse.h000066400000000000000000000111651364710014100153170ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #define _GNU_SOURCE #include "ringbuffer.h" #include #include #include #include #include #define APULSE_EXPORT __attribute__((visibility("default"))) struct pa_context { pa_context_state_t state; pa_context_state_t new_state; pa_context_notify_cb_t state_cb; void *state_cb_userdata; pa_mainloop_api *mainloop_api; char *name; int ref_cnt; int next_stream_idx; GHashTable *streams_ht; pa_volume_t source_volume[PA_CHANNELS_MAX]; }; struct pa_io_event { int fd; pa_io_event_flags_t events; pa_io_event_cb_t cb; void *cb_userdata; pa_io_event_destroy_cb_t destroy_cb; pa_mainloop *mainloop; struct pollfd *pollfd; snd_pcm_t *pcm; }; struct pa_mainloop { pa_mainloop_api api; GQueue *deferred_events_queue; GQueue *timed_events_queue; GHashTable *events_ht; ///< a set of (pa_io_event *) struct pollfd *fds; nfds_t nfds; int recreate_fds; ///< 1 if fds array needs to be recreated from events_ht int timeout; int wakeup_pipe[2]; int terminate; int retval; pa_poll_func poll_func; void *poll_func_userdata; int alsa_special_cnt; }; struct pa_glib_mainloop { pa_mainloop_api api; }; struct pa_threaded_mainloop { pa_mainloop *m; pthread_mutex_t lock; pthread_cond_t cond; pthread_t t; int running; }; struct pa_proplist { GHashTable *ht; }; struct pa_stream { pa_context *c; pa_stream_state_t state; pa_stream_direction_t direction; snd_pcm_t *ph; pa_sample_spec ss; pa_buffer_attr buffer_attr; int ref_cnt; int idx; pa_stream_notify_cb_t state_cb; void *state_cb_userdata; pa_stream_request_cb_t write_cb; void *write_cb_userdata; pa_stream_request_cb_t read_cb; void *read_cb_userdata; pa_stream_notify_cb_t latency_update_cb; void *latency_update_cb_userdata; char *name; pa_timing_info timing_info; pa_io_event **ioe; ///< list of pa_io_events int nioe; ///< count of pa_io_events ringbuffer_t *rb; void *peek_buffer; size_t peek_buffer_data_len; void *write_buffer; volatile int paused; pa_volume_t volume[PA_CHANNELS_MAX]; }; struct pa_operation { pa_operation_state_t state; pa_stream_success_cb_t stream_success_cb; pa_sink_input_info_cb_t sink_input_info_cb; pa_sink_info_cb_t sink_info_cb; pa_context_success_cb_t context_success_cb; pa_server_info_cb_t server_info_cb; pa_source_info_cb_t source_info_cb; void *cb_userdata; pa_mainloop_api *api; void (*mainloop_api_once_cb)(pa_mainloop_api *m, void *userdata); void (*handler)(pa_operation *op); int ref_cnt; int int_arg_1; char *char_ptr_arg_1; pa_cvolume pa_cvolume_arg_1; pa_stream *s; pa_context *c; }; struct pa_defer_event { int enabled; pa_defer_event_cb_t cb; void *userdata; pa_mainloop *mainloop; }; struct pa_time_event { int enabled; struct timeval when; pa_time_event_cb_t cb; void *userdata; pa_mainloop *mainloop; pa_time_event_destroy_cb_t destroy_cb; }; struct pa_simple { pa_context *context; pa_threaded_mainloop *mainloop; pa_stream *stream; pa_stream_direction_t direction; int initialized; }; pa_operation * pa_operation_new(pa_mainloop_api *api, void (*handler)(pa_operation *op)); void pa_operation_launch(pa_operation *op); void pa_operation_done(pa_operation *op); apulse-0.1.13/src/apulse.template000066400000000000000000000001721364710014100166770ustar00rootroot00000000000000#!/bin/sh APULSEPATH="@APULSE_SEARCH_PATHS@" LD_LIBRARY_PATH=$APULSEPATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} exec "$@" apulse-0.1.13/src/ringbuffer.c000066400000000000000000000115301364710014100161460ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "ringbuffer.h" #include #include static inline void _rb_lock(ringbuffer_t *rb) { pthread_mutex_lock(&rb->lock); } static inline void _rb_unlock(ringbuffer_t *rb) { pthread_mutex_unlock(&rb->lock); } ringbuffer_t * ringbuffer_new(size_t sz) { ringbuffer_t *rb = malloc(sizeof(*rb)); rb->start = malloc(sz); rb->end = rb->start + sz; rb->rpos = rb->start; rb->wpos = rb->start; rb->empty = 1; pthread_mutex_init(&rb->lock, NULL); return rb; } void ringbuffer_free(ringbuffer_t *rb) { pthread_mutex_destroy(&rb->lock); free(rb->start); free(rb); } static size_t _ringbuffer_readable_size(ringbuffer_t *rb) { if (rb->wpos > rb->rpos) { return rb->wpos - rb->rpos; } else if (rb->wpos < rb->rpos) { return (rb->end - rb->rpos) + (rb->wpos - rb->start); } else { // wpos == rpos if (rb->empty) return 0; else return rb->end - rb->start; } } size_t ringbuffer_readable_size(ringbuffer_t *rb) { size_t rsz; _rb_lock(rb); rsz = _ringbuffer_readable_size(rb); _rb_unlock(rb); return rsz; } static size_t _ringbuffer_writable_size(ringbuffer_t *rb) { if (rb->wpos > rb->rpos) { return (rb->end - rb->wpos) + (rb->rpos - rb->start); } else if (rb->wpos < rb->rpos) { return rb->rpos - rb->wpos; } else { // wpos == rpos if (rb->empty) return rb->end - rb->start; else return 0; } } size_t ringbuffer_writable_size(ringbuffer_t *rb) { size_t wsz; _rb_lock(rb); wsz = _ringbuffer_writable_size(rb); _rb_unlock(rb); return wsz; } size_t ringbuffer_write(ringbuffer_t *rb, const void *data, size_t len) { _rb_lock(rb); size_t remsz = rb->end - rb->wpos; size_t writable_size = _ringbuffer_writable_size(rb); if (len > writable_size) len = writable_size; if (len <= remsz) { memcpy(rb->wpos, data, len); rb->wpos += len; } else { memcpy(rb->wpos, data, remsz); memcpy(rb->start, (char *)data + remsz, len - remsz); rb->wpos = rb->start + len - remsz; } if (len > 0) rb->empty = 0; _rb_unlock(rb); return len; } size_t ringbuffer_read(ringbuffer_t *rb, void *data, size_t len) { _rb_lock(rb); size_t remsz = rb->end - rb->rpos; size_t readable_size = _ringbuffer_readable_size(rb); if (len > readable_size) len = readable_size; if (len <= remsz) { memcpy(data, rb->rpos, len); rb->rpos += len; } else { memcpy(data, rb->rpos, remsz); memcpy((char *)data + remsz, rb->start, len - remsz); rb->rpos = rb->start + len - remsz; } if (rb->rpos == rb->wpos) rb->empty = 1; _rb_unlock(rb); return len; } size_t ringbuffer_peek(ringbuffer_t *rb, void *data, size_t len) { _rb_lock(rb); size_t remsz = rb->end - rb->rpos; size_t readable_size = _ringbuffer_readable_size(rb); if (len > readable_size) len = readable_size; if (len <= remsz) { memcpy(data, rb->rpos, len); } else { memcpy(data, rb->rpos, remsz); memcpy((char *)data + remsz, rb->start, len - remsz); } _rb_unlock(rb); return len; } size_t ringbuffer_drop(ringbuffer_t *rb, size_t len) { _rb_lock(rb); size_t remsz = rb->end - rb->rpos; size_t readable_size = _ringbuffer_readable_size(rb); if (len > readable_size) len = readable_size; if (len <= remsz) { rb->rpos += len; } else { rb->rpos = rb->start + len - remsz; } if (rb->rpos == rb->wpos) rb->empty = 1; _rb_unlock(rb); return len; } apulse-0.1.13/src/ringbuffer.h000066400000000000000000000035041364710014100161550ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #include typedef struct { char *start; char *end; char *rpos; char *wpos; pthread_mutex_t lock; int empty; } ringbuffer_t; ringbuffer_t * ringbuffer_new(size_t sz); void ringbuffer_free(ringbuffer_t *rb); size_t ringbuffer_readable_size(ringbuffer_t *rb); size_t ringbuffer_writable_size(ringbuffer_t *rb); size_t ringbuffer_write(ringbuffer_t *rb, const void *data, size_t len); size_t ringbuffer_read(ringbuffer_t *rb, void *data, size_t len); /** get data from ring buffer without advancing read pointer */ size_t ringbuffer_peek(ringbuffer_t *rb, void *data, size_t len); size_t ringbuffer_drop(ringbuffer_t *rb, size_t len); apulse-0.1.13/src/symbolmap000066400000000000000000000000751364710014100156010ustar00rootroot00000000000000PULSE_0 { global: pa_*; local: *; }; apulse-0.1.13/src/trace.c000066400000000000000000000243641364710014100151240ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "trace.h" #include #include #include #include #include static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; #if CONFIG_LOG_TO_STDERR static int log_to_stderr = 1; #else static int log_to_stderr = 0; #endif // CONFIG_LOG_TO_STDERR void trace_info(const char *fmt, ...) { FILE *fp = log_to_stderr ? stderr : stdout; pthread_mutex_lock(&lock); va_list args; struct timeval tv; gettimeofday(&tv, NULL); fprintf(fp, "%d.%03d [apulse %5d] ", (int)tv.tv_sec, (int)tv.tv_usec / 1000, (int)syscall(__NR_gettid)); va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); pthread_mutex_unlock(&lock); } void trace_warning(const char *fmt, ...) { FILE *fp = log_to_stderr ? stderr : stdout; pthread_mutex_lock(&lock); va_list args; fprintf(fp, "[apulse] [warning] "); va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); pthread_mutex_unlock(&lock); } void trace_error(const char *fmt, ...) { static int stdout_tested = 0; static int stdout_is_a_tty = 0; pthread_mutex_lock(&lock); if (!stdout_tested) { stdout_is_a_tty = isatty(1); stdout_tested = 1; } va_list args; fprintf(stderr, "[apulse] [error] "); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); if (!log_to_stderr && !stdout_is_a_tty) { // Send a copy to stdout, if it's redirected to a file. fprintf(stdout, "[apulse] [error] "); va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } pthread_mutex_unlock(&lock); } gchar * trace_pa_buffer_attr_as_string(const pa_buffer_attr *attr) { gchar *res; if (attr) { res = g_strdup_printf( "{.maxlength=%u, .tlength=%u, .prebuf=%u, .minreq=%u, " ".fragsize=%u}", attr->maxlength, attr->tlength, attr->prebuf, attr->minreq, attr->fragsize); } else { res = g_strdup_printf("(nil)"); } return res; } gchar * trace_pa_volume_as_string(const pa_cvolume *v) { const unsigned int channel_count = MIN(v->channels, PA_CHANNELS_MAX); GString *s = g_string_new(NULL); g_string_append_printf(s, "%d:{", v->channels); for (unsigned int k = 0; k < channel_count; k++) { if (k != 0) g_string_append(s, ", "); g_string_append_printf(s, "%u", v->values[k]); } g_string_append(s, "}"); return g_string_free(s, FALSE); } gchar * trace_pa_channel_position_t_as_string(const pa_channel_position_t pos) { const char *s_pos; switch (pos) { case PA_CHANNEL_POSITION_INVALID: s_pos = "INVALID"; break; case PA_CHANNEL_POSITION_MONO: s_pos = "MONO"; break; case PA_CHANNEL_POSITION_FRONT_LEFT: s_pos = "FRONT_LEFT"; break; case PA_CHANNEL_POSITION_FRONT_RIGHT: s_pos = "FRONT_RIGHT"; break; case PA_CHANNEL_POSITION_FRONT_CENTER: s_pos = "FRONT_CENTER"; break; case PA_CHANNEL_POSITION_REAR_CENTER: s_pos = "REAR_CENTER"; break; case PA_CHANNEL_POSITION_REAR_LEFT: s_pos = "REAR_LEFT"; break; case PA_CHANNEL_POSITION_REAR_RIGHT: s_pos = "REAR_RIGHT"; break; case PA_CHANNEL_POSITION_LFE: s_pos = "LFE"; break; case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: s_pos = "FRONT_LEFT_OF_CENTER"; break; case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: s_pos = "FRONT_RIGHT_OF_CENTER"; break; case PA_CHANNEL_POSITION_SIDE_LEFT: s_pos = "SIDE_LEFT"; break; case PA_CHANNEL_POSITION_SIDE_RIGHT: s_pos = "SIDE_RIGHT"; break; case PA_CHANNEL_POSITION_AUX0: s_pos = "AUX0"; break; case PA_CHANNEL_POSITION_AUX1: s_pos = "AUX1"; break; case PA_CHANNEL_POSITION_AUX2: s_pos = "AUX2"; break; case PA_CHANNEL_POSITION_AUX3: s_pos = "AUX3"; break; case PA_CHANNEL_POSITION_AUX4: s_pos = "AUX4"; break; case PA_CHANNEL_POSITION_AUX5: s_pos = "AUX5"; break; case PA_CHANNEL_POSITION_AUX6: s_pos = "AUX6"; break; case PA_CHANNEL_POSITION_AUX7: s_pos = "AUX7"; break; case PA_CHANNEL_POSITION_AUX8: s_pos = "AUX8"; break; case PA_CHANNEL_POSITION_AUX9: s_pos = "AUX9"; break; case PA_CHANNEL_POSITION_AUX10: s_pos = "AUX10"; break; case PA_CHANNEL_POSITION_AUX11: s_pos = "AUX11"; break; case PA_CHANNEL_POSITION_AUX12: s_pos = "AUX12"; break; case PA_CHANNEL_POSITION_AUX13: s_pos = "AUX13"; break; case PA_CHANNEL_POSITION_AUX14: s_pos = "AUX14"; break; case PA_CHANNEL_POSITION_AUX15: s_pos = "AUX15"; break; case PA_CHANNEL_POSITION_AUX16: s_pos = "AUX16"; break; case PA_CHANNEL_POSITION_AUX17: s_pos = "AUX17"; break; case PA_CHANNEL_POSITION_AUX18: s_pos = "AUX18"; break; case PA_CHANNEL_POSITION_AUX19: s_pos = "AUX19"; break; case PA_CHANNEL_POSITION_AUX20: s_pos = "AUX20"; break; case PA_CHANNEL_POSITION_AUX21: s_pos = "AUX21"; break; case PA_CHANNEL_POSITION_AUX22: s_pos = "AUX22"; break; case PA_CHANNEL_POSITION_AUX23: s_pos = "AUX23"; break; case PA_CHANNEL_POSITION_AUX24: s_pos = "AUX24"; break; case PA_CHANNEL_POSITION_AUX25: s_pos = "AUX25"; break; case PA_CHANNEL_POSITION_AUX26: s_pos = "AUX26"; break; case PA_CHANNEL_POSITION_AUX27: s_pos = "AUX27"; break; case PA_CHANNEL_POSITION_AUX28: s_pos = "AUX28"; break; case PA_CHANNEL_POSITION_AUX29: s_pos = "AUX29"; break; case PA_CHANNEL_POSITION_AUX30: s_pos = "AUX30"; break; case PA_CHANNEL_POSITION_AUX31: s_pos = "AUX31"; break; case PA_CHANNEL_POSITION_TOP_CENTER: s_pos = "TOP_CENTER"; break; case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: s_pos = "TOP_FRONT_LEFT"; break; case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: s_pos = "TOP_FRONT_RIGHT"; break; case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: s_pos = "TOP_FRONT_CENTER"; break; case PA_CHANNEL_POSITION_TOP_REAR_LEFT: s_pos = "TOP_REAR_LEFT"; break; case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: s_pos = "TOP_REAR_RIGHT"; break; case PA_CHANNEL_POSITION_TOP_REAR_CENTER: s_pos = "TOP_REAR_CENTER"; break; case PA_CHANNEL_POSITION_MAX: s_pos = "MAX"; break; default: s_pos = "UNKNOWN"; break; } return g_strdup_printf("%s(%d)", s_pos, pos); } gchar * trace_pa_channel_map_as_string(const pa_channel_map *m) { if (!m) return g_strdup("(nil)"); GString *s = g_string_new(NULL); g_string_append_printf(s, "%u:{", m->channels); const unsigned int channel_count = MIN(m->channels, PA_CHANNELS_MAX); for (unsigned int k = 0; k < channel_count; k++) { if (k != 0) g_string_append(s, ","); gchar *s_channel_pos = trace_pa_channel_position_t_as_string(m->map[k]); g_string_append(s, s_channel_pos); g_free(s_channel_pos); } g_string_append(s, "}"); return g_string_free(s, FALSE); } gchar * trace_pa_sample_format_t_as_string(pa_sample_format_t sf) { const char *fmt; switch (sf) { case PA_SAMPLE_U8: fmt = "U8"; break; case PA_SAMPLE_ALAW: fmt = "ALAW"; break; case PA_SAMPLE_ULAW: fmt = "ULAW"; break; case PA_SAMPLE_S16LE: fmt = "S16LE"; break; case PA_SAMPLE_S16BE: fmt = "S16BE"; break; case PA_SAMPLE_FLOAT32LE: fmt = "FLOAT32LE"; break; case PA_SAMPLE_FLOAT32BE: fmt = "FLOAT32BE"; break; case PA_SAMPLE_S32LE: fmt = "S32LE"; break; case PA_SAMPLE_S32BE: fmt = "S32BE"; break; case PA_SAMPLE_S24LE: fmt = "S24LE"; break; case PA_SAMPLE_S24BE: fmt = "S24BE"; break; case PA_SAMPLE_S24_32LE: fmt = "S24_32LE"; break; case PA_SAMPLE_S24_32BE: fmt = "S24_32BE"; break; case PA_SAMPLE_MAX: fmt = "MAX"; break; case PA_SAMPLE_INVALID: fmt = "INVALID"; break; default: fmt = "UNKNOWN"; break; } return g_strdup_printf("%s(%d)", fmt, sf); } gchar * trace_pa_sample_spec_as_string(const pa_sample_spec *ss) { if (!ss) return g_strdup("(nil)"); gchar *s_format = trace_pa_sample_format_t_as_string(ss->format); gchar *str = g_strdup_printf("{.format=%s,.rate=%u,.channels=%u}", s_format, ss->rate, ss->channels); g_free(s_format); return str; } apulse-0.1.13/src/trace.h000066400000000000000000000043031364710014100151200ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #include #include #include #if CONFIG_TRACE_LEVEL >= 2 #define trace_info_f(...) trace_info(__VA_ARGS__) #define trace_info_z(...) trace_info(__VA_ARGS__) #elif CONFIG_TRACE_LEVEL == 1 #define trace_info_f(...) #define trace_info_z(...) trace_info(__VA_ARGS__) #else // CONFIG_TRACE_LEVEL == 0 #define trace_info_f(...) #define trace_info_z(...) #endif void trace_info(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_warning(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_error(const char *fmt, ...) __attribute__((format(printf, 1, 2))); gchar * trace_pa_buffer_attr_as_string(const pa_buffer_attr *attr); gchar * trace_pa_volume_as_string(const pa_cvolume *v); gchar * trace_pa_channel_position_t_as_string(const pa_channel_position_t pos); gchar * trace_pa_channel_map_as_string(const pa_channel_map *m); gchar * trace_pa_sample_format_t_as_string(pa_sample_format_t sf); gchar * trace_pa_sample_spec_as_string(const pa_sample_spec *ss); apulse-0.1.13/src/util.c000066400000000000000000000127731364710014100150040ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "trace.h" #include "util.h" int pa_format_to_alsa(pa_sample_format_t format) { switch (format) { case PA_SAMPLE_U8: return SND_PCM_FORMAT_U8; case PA_SAMPLE_ALAW: return SND_PCM_FORMAT_A_LAW; case PA_SAMPLE_ULAW: return SND_PCM_FORMAT_MU_LAW; case PA_SAMPLE_S16LE: return SND_PCM_FORMAT_S16_LE; case PA_SAMPLE_S16BE: return SND_PCM_FORMAT_S16_BE; case PA_SAMPLE_FLOAT32LE: return SND_PCM_FORMAT_FLOAT_LE; case PA_SAMPLE_FLOAT32BE: return SND_PCM_FORMAT_FLOAT_BE; case PA_SAMPLE_S32LE: return SND_PCM_FORMAT_S32_LE; case PA_SAMPLE_S32BE: return SND_PCM_FORMAT_S32_BE; case PA_SAMPLE_S24LE: return SND_PCM_FORMAT_S24_3LE; case PA_SAMPLE_S24BE: return SND_PCM_FORMAT_S24_3BE; case PA_SAMPLE_S24_32LE: return SND_PCM_FORMAT_S24_LE; case PA_SAMPLE_S24_32BE: return SND_PCM_FORMAT_S24_BE; default: return SND_PCM_FORMAT_UNKNOWN; } } pa_sample_format_t pa_sample_format_from_string(const char *str) { if (!str) return 0; if (strcmp(str, "u8") == 0) { return PA_SAMPLE_U8; } else if (strcmp(str, "aLaw") == 0) { return PA_SAMPLE_ALAW; } else if (strcmp(str, "uLaw") == 0) { return PA_SAMPLE_ULAW; } else if (strcmp(str, "s16le") == 0) { return PA_SAMPLE_S16LE; } else if (strcmp(str, "s16be") == 0) { return PA_SAMPLE_S16BE; } else if (strcmp(str, "float32le") == 0) { return PA_SAMPLE_FLOAT32LE; } else if (strcmp(str, "float32be") == 0) { return PA_SAMPLE_FLOAT32BE; } else if (strcmp(str, "s32le") == 0) { return PA_SAMPLE_S32LE; } else if (strcmp(str, "s32be") == 0) { return PA_SAMPLE_S32BE; } else if (strcmp(str, "s24le") == 0) { return PA_SAMPLE_S24LE; } else if (strcmp(str, "s24be") == 0) { return PA_SAMPLE_S24BE; } else if (strcmp(str, "s24-32le") == 0) { return PA_SAMPLE_S24_32LE; } else if (strcmp(str, "s24-32be") == 0) { return PA_SAMPLE_S24_32BE; } else { return 0; } } size_t pa_find_multiple_of(size_t number, size_t multiple_of, int towards_larger_numbers) { if (multiple_of == 0) return number; size_t n = towards_larger_numbers ? (number + multiple_of - 1) : number; return n - (n % multiple_of); } void pa_apply_volume_multiplier(void *buf, size_t sz, const pa_volume_t volume[PA_CHANNELS_MAX], const pa_sample_spec *ss) { char *p = buf; char *last = p + sz; float fvol[PA_CHANNELS_MAX]; uint32_t channels = MIN(ss->channels, PA_CHANNELS_MAX); if (channels == 0) { // No channels — nothing to scale. return; } int all_normal = 1; for (uint32_t k = 0; k < channels; k++) all_normal = all_normal && (volume[k] == PA_VOLUME_NORM); if (all_normal) { // No scaling required. return; } for (uint32_t k = 0; k < channels; k++) fvol[k] = pa_sw_volume_to_linear(volume[k]); switch (ss->format) { case PA_SAMPLE_FLOAT32NE: while (p < last) { for (uint32_t k = 0; k < channels && p < last; k++) { float sample; memcpy(&sample, p, sizeof(sample)); sample *= fvol[k]; memcpy(p, &sample, sizeof(sample)); p += sizeof(sample); } } break; case PA_SAMPLE_S16NE: while (p < last) { for (uint32_t k = 0; k < channels && p < last; k++) { int16_t sample; memcpy(&sample, p, sizeof(sample)); float sample_scaled = sample * fvol[k]; sample = CLAMP(sample_scaled, -32768.0, 32767.0); memcpy(p, &sample, sizeof(sample)); p += sizeof(sample); } } break; case PA_SAMPLE_U8: case PA_SAMPLE_ALAW: case PA_SAMPLE_ULAW: case PA_SAMPLE_S16RE: case PA_SAMPLE_FLOAT32RE: case PA_SAMPLE_S32NE: case PA_SAMPLE_S32RE: case PA_SAMPLE_S24NE: case PA_SAMPLE_S24RE: case PA_SAMPLE_S24_32NE: case PA_SAMPLE_S24_32RE: default: trace_error("format %s is not implemented in %s\n", pa_sample_format_to_string(ss->format), __func__); break; } } apulse-0.1.13/src/util.h000066400000000000000000000033241364710014100150010ustar00rootroot00000000000000/* * Copyright © 2014-2018 Rinat Ibragimov * * This file is part of "apulse" project. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #include #include int pa_format_to_alsa(pa_sample_format_t format); pa_sample_format_t pa_sample_format_from_string(const char *str); /// finds largest number that is less or equal than |number| and multiple of /// |multiple_of|. size_t pa_find_multiple_of(size_t number, size_t multiple_of, int towards_larger_numbers); void pa_apply_volume_multiplier(void *buf, size_t sz, const pa_volume_t volume[PA_CHANNELS_MAX], const pa_sample_spec *ss); apulse-0.1.13/tests/000077500000000000000000000000001364710014100142245ustar00rootroot00000000000000apulse-0.1.13/tests/CMakeLists.txt000066400000000000000000000007411364710014100167660ustar00rootroot00000000000000enable_testing() add_custom_target(check COMMAND "${CMAKE_CTEST_COMMAND}") set(test_list test_ringbuffer ) link_directories(${REQ_LIBRARY_DIRS}) # simplify inclusion of .c sources include_directories(..) foreach(item ${test_list}) add_executable(${item} EXCLUDE_FROM_ALL ${item}.c ) target_link_libraries(${item} "-Wl,-z,muldefs" dl ${REQ_LIBRARIES}) add_test(${item} ${item}) add_dependencies(check ${item}) endforeach() apulse-0.1.13/tests/test_ringbuffer.c000066400000000000000000000050111364710014100175550ustar00rootroot00000000000000#undef NDEBUG #include #include #include int main(void) { ringbuffer_t *rb = ringbuffer_new(16); char buf[20]; // check initial state assert(rb); assert(ringbuffer_readable_size(rb) == 0); assert(ringbuffer_writable_size(rb) == 16); // check for reading from empty buffer assert(ringbuffer_read(rb, buf, sizeof(buf)) == 0); // write some data assert(ringbuffer_write(rb, "hello", 5) == 5); assert(ringbuffer_readable_size(rb) == 5); assert(ringbuffer_writable_size(rb) == 11); // read that data assert(ringbuffer_read(rb, buf, sizeof(buf)) == 5); assert(memcmp(buf, "hello", 5) == 0); // test wrapping assert(ringbuffer_write(rb, "0123456789abcdef", 16) == 16); assert(ringbuffer_readable_size(rb) == 16); assert(ringbuffer_writable_size(rb) == 0); // reading of wrapped data in two chunks assert(ringbuffer_read(rb, buf, 15) == 15); assert(memcmp(buf, "0123456789abcde", 15) == 0); assert(ringbuffer_read(rb, buf, 15) == 1); assert(memcmp(buf, "f", 1) == 0); // check readable/writable size functions in case of buffer wrapping assert(ringbuffer_write(rb, "0123456789abcdef", 16) == 16); assert(ringbuffer_readable_size(rb) == 16); assert(ringbuffer_writable_size(rb) == 0); assert(ringbuffer_read(rb, buf, 3) == 3); assert(ringbuffer_readable_size(rb) == 13); assert(ringbuffer_writable_size(rb) == 3); assert(ringbuffer_read(rb, buf, 3) == 3); assert(ringbuffer_readable_size(rb) == 10); assert(ringbuffer_writable_size(rb) == 6); assert(ringbuffer_read(rb, buf, 3) == 3); assert(ringbuffer_readable_size(rb) == 7); assert(ringbuffer_writable_size(rb) == 9); assert(ringbuffer_read(rb, buf, 3) == 3); assert(ringbuffer_readable_size(rb) == 4); assert(ringbuffer_writable_size(rb) == 12); assert(ringbuffer_read(rb, buf, 3) == 3); assert(ringbuffer_readable_size(rb) == 1); assert(ringbuffer_writable_size(rb) == 15); assert(ringbuffer_read(rb, buf, 3) == 1); assert(ringbuffer_readable_size(rb) == 0); assert(ringbuffer_writable_size(rb) == 16); // try to write more than buffer have assert(ringbuffer_write(rb, "01234567890", 10) == 10); assert(ringbuffer_writable_size(rb) == 6); assert(ringbuffer_write(rb, "01234567890", 10) == 6); assert(ringbuffer_writable_size(rb) == 0); assert(ringbuffer_readable_size(rb) == 16); // cleanup ringbuffer_free(rb); printf("pass\n"); return 0; }