diff --git a/man/meson.build b/man/meson.build index 0418327b3..5506a356d 100644 --- a/man/meson.build +++ b/man/meson.build @@ -23,10 +23,6 @@ if get_option('pipewire-jack') manpages += [[ 'pw-jack', '1' ]] endif -if get_option('pipewire-pulseaudio') - manpages += [[ 'pw-pulse', '1' ]] -endif - foreach m : manpages file = m.get(0) + '.' + m.get(1) infile = file + '.xml.in' diff --git a/man/pw-jack.1.xml.in b/man/pw-jack.1.xml.in index 84f5bb751..c28422c43 100644 --- a/man/pw-jack.1.xml.in +++ b/man/pw-jack.1.xml.in @@ -63,7 +63,6 @@ This file is part of PipeWire.

, , -

diff --git a/man/pw-pulse.1.xml.in b/man/pw-pulse.1.xml.in deleted file mode 100644 index 5607f6462..000000000 --- a/man/pw-pulse.1.xml.in +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - pw-pulse [options] COMMAND [FILE] - - - -

pw-pulse modifies the LD_LIBRARY_PATH environment - variable so that applications will load PipeWire's reimplementation - of the PulseAudio client libraries instead of PulseAudio's own - libraries. This results in PulseAudio clients being redirected to - PipeWire.

- -

If PipeWire's reimplementation of the PulseAudio client libraries - has been installed as a system-wide replacement for PulseAudio's - own libraries, then the whole system already behaves in that way, - in which case pw-pulse has no practical effect.

-
- - - - - - - - - - -
-

pw-pulse gst123 /usr/share/sounds/freedesktop/stereo/bell.oga

-
- -
-

Using PipeWire for audio is currently considered to be - experimental.

-
- -
-

The PipeWire Developers <@PACKAGE_BUGREPORT@>; - PipeWire is available from

-
- -
-

- , - , - -

-
- -
diff --git a/meson.build b/meson.build index 8e783f307..f88b7de49 100644 --- a/meson.build +++ b/meson.build @@ -41,9 +41,9 @@ if host_machine.system() == 'linux' # glibc ld.so interprets ${LIB} in a library loading path with an # appropriate value for the current architecture, typically something # like lib, lib64 or lib/x86_64-linux-gnu. - # This allows the same pw-pulse script to work for both 32- and 64-bit + # This allows the same pw-jack script to work for both 32- and 64-bit # applications on biarch/multiarch distributions, by setting something - # like LD_LIBRARY_PATH='/usr/${LIB}/pipewire-0.3/pulse'. + # like LD_LIBRARY_PATH='/usr/${LIB}/pipewire-0.3/jack'. # Note that ${LIB} is a special token expanded by the runtime linker, # not an environment variable, and must be passed through literally. modules_install_dir_dlopen = join_paths(prefix, '${LIB}', pipewire_name) @@ -327,7 +327,7 @@ dbus_dep = dependency('dbus-1') sdl_dep = dependency('sdl2', required : false) sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : false) -if get_option('gstreamer') or get_option('pipewire-pulseaudio') +if get_option('gstreamer') glib_dep = dependency('glib-2.0', version : '>=2.32.0') endif @@ -364,12 +364,6 @@ if get_option('pipewire-jack') subdir('pipewire-jack/src') endif -if get_option('pipewire-pulseaudio') - pulseaudio_dep = dependency('libpulse', version : '>= 11.1') - subdir('pipewire-pulseaudio/src') - subdir('pipewire-pulseaudio/test') -endif - if get_option('pipewire-alsa') subdir('pipewire-alsa/alsa-plugins') subdir('pipewire-alsa/conf') diff --git a/meson_options.txt b/meson_options.txt index 4b9e46b83..122820ae1 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -49,13 +49,6 @@ option('pipewire-jack', option('libjack-path', description: 'Where to install the libjack.so library', type: 'string') -option('pipewire-pulseaudio', - description: 'Enable pipewire-pulseaudio integration', - type: 'boolean', - value: false) -option('libpulse-path', - description: 'Where to install the libpulse.so library', - type: 'string') option('spa-plugins', description: 'Enable spa plugins integration', type: 'boolean', diff --git a/pipewire-pulseaudio/LICENSE b/pipewire-pulseaudio/LICENSE deleted file mode 100644 index 19e307187..000000000 --- a/pipewire-pulseaudio/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -(This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.) - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random - Hacker. - - {signature of Ty Coon}, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/pipewire-pulseaudio/README.md b/pipewire-pulseaudio/README.md deleted file mode 100644 index 27b62cf29..000000000 --- a/pipewire-pulseaudio/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# pipewire-pulseaudio -PulseAudio client library for PipeWire - -This is a replacement libpulse.so library. Clients using this library will -transparently connect to PipeWire. - -This is now deprecated in favour of the protocol-pulse module that -implements the pulseaudio protocol directly. This makes it possible to -use the standard pulseaudio client library. diff --git a/pipewire-pulseaudio/src/bitset.c b/pipewire-pulseaudio/src/bitset.c deleted file mode 100644 index be834f5eb..000000000 --- a/pipewire-pulseaudio/src/bitset.c +++ /dev/null @@ -1,65 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 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 - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "internal.h" -#include "bitset.h" - -void pa_bitset_set(pa_bitset_t *b, unsigned k, bool v) { - pa_assert(b); - - if (v) - b[k >> 5] |= 1 << (k & 31); - else - b[k >> 5] &= ~((uint32_t) (1 << (k & 31))); -} - -bool pa_bitset_get(const pa_bitset_t *b, unsigned k) { - return !!(b[k >> 5] & (1 << (k & 31))); -} - -bool pa_bitset_equals(const pa_bitset_t *b, unsigned n, ...) { - va_list ap; - pa_bitset_t *a; - bool equal; - - a = alloca(PA_BITSET_SIZE(n)); - spa_memzero(a, PA_BITSET_SIZE(n)); - - va_start(ap, n); - for (;;) { - int j = va_arg(ap, int); - - if (j < 0) - break; - - pa_bitset_set(a, j, true); - } - va_end(ap); - - equal = memcmp(a, b, PA_BITSET_SIZE(n)) == 0; - - return equal; -} diff --git a/pipewire-pulseaudio/src/bitset.h b/pipewire-pulseaudio/src/bitset.h deleted file mode 100644 index 314dafc2a..000000000 --- a/pipewire-pulseaudio/src/bitset.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef foopulsecorebitsethfoo -#define foopulsecorebitsethfoo - -/*** - This file is part of PulseAudio. - - Copyright 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 - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, see . -***/ - -#include - -#define PA_BITSET_ELEMENTS(n) (((n)+31)/32) -#define PA_BITSET_SIZE(n) (PA_BITSET_ELEMENTS(n)*4) - -typedef uint32_t pa_bitset_t; - -void pa_bitset_set(pa_bitset_t *b, unsigned k, bool v); -bool pa_bitset_get(const pa_bitset_t *b, unsigned k); -bool pa_bitset_equals(const pa_bitset_t *b, unsigned n, ...); - -#endif diff --git a/pipewire-pulseaudio/src/channelmap.c b/pipewire-pulseaudio/src/channelmap.c deleted file mode 100644 index c86bb09f7..000000000 --- a/pipewire-pulseaudio/src/channelmap.c +++ /dev/null @@ -1,948 +0,0 @@ -/*** - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include "internal.h" -#include "bitset.h" -#include "sample-util.h" - -const char *const table[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" -}; - -const char *const pretty_table[PA_CHANNEL_POSITION_MAX] = { - [PA_CHANNEL_POSITION_MONO] = N_("Mono"), - - [PA_CHANNEL_POSITION_FRONT_CENTER] = N_("Front Center"), - [PA_CHANNEL_POSITION_FRONT_LEFT] = N_("Front Left"), - [PA_CHANNEL_POSITION_FRONT_RIGHT] = N_("Front Right"), - - [PA_CHANNEL_POSITION_REAR_CENTER] = N_("Rear Center"), - [PA_CHANNEL_POSITION_REAR_LEFT] = N_("Rear Left"), - [PA_CHANNEL_POSITION_REAR_RIGHT] = N_("Rear Right"), - - [PA_CHANNEL_POSITION_LFE] = N_("Subwoofer"), - - [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = N_("Front Left-of-center"), - [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = N_("Front Right-of-center"), - - [PA_CHANNEL_POSITION_SIDE_LEFT] = N_("Side Left"), - [PA_CHANNEL_POSITION_SIDE_RIGHT] = N_("Side Right"), - - [PA_CHANNEL_POSITION_AUX0] = N_("Auxiliary 0"), - [PA_CHANNEL_POSITION_AUX1] = N_("Auxiliary 1"), - [PA_CHANNEL_POSITION_AUX2] = N_("Auxiliary 2"), - [PA_CHANNEL_POSITION_AUX3] = N_("Auxiliary 3"), - [PA_CHANNEL_POSITION_AUX4] = N_("Auxiliary 4"), - [PA_CHANNEL_POSITION_AUX5] = N_("Auxiliary 5"), - [PA_CHANNEL_POSITION_AUX6] = N_("Auxiliary 6"), - [PA_CHANNEL_POSITION_AUX7] = N_("Auxiliary 7"), - [PA_CHANNEL_POSITION_AUX8] = N_("Auxiliary 8"), - [PA_CHANNEL_POSITION_AUX9] = N_("Auxiliary 9"), - [PA_CHANNEL_POSITION_AUX10] = N_("Auxiliary 10"), - [PA_CHANNEL_POSITION_AUX11] = N_("Auxiliary 11"), - [PA_CHANNEL_POSITION_AUX12] = N_("Auxiliary 12"), - [PA_CHANNEL_POSITION_AUX13] = N_("Auxiliary 13"), - [PA_CHANNEL_POSITION_AUX14] = N_("Auxiliary 14"), - [PA_CHANNEL_POSITION_AUX15] = N_("Auxiliary 15"), - [PA_CHANNEL_POSITION_AUX16] = N_("Auxiliary 16"), - [PA_CHANNEL_POSITION_AUX17] = N_("Auxiliary 17"), - [PA_CHANNEL_POSITION_AUX18] = N_("Auxiliary 18"), - [PA_CHANNEL_POSITION_AUX19] = N_("Auxiliary 19"), - [PA_CHANNEL_POSITION_AUX20] = N_("Auxiliary 20"), - [PA_CHANNEL_POSITION_AUX21] = N_("Auxiliary 21"), - [PA_CHANNEL_POSITION_AUX22] = N_("Auxiliary 22"), - [PA_CHANNEL_POSITION_AUX23] = N_("Auxiliary 23"), - [PA_CHANNEL_POSITION_AUX24] = N_("Auxiliary 24"), - [PA_CHANNEL_POSITION_AUX25] = N_("Auxiliary 25"), - [PA_CHANNEL_POSITION_AUX26] = N_("Auxiliary 26"), - [PA_CHANNEL_POSITION_AUX27] = N_("Auxiliary 27"), - [PA_CHANNEL_POSITION_AUX28] = N_("Auxiliary 28"), - [PA_CHANNEL_POSITION_AUX29] = N_("Auxiliary 29"), - [PA_CHANNEL_POSITION_AUX30] = N_("Auxiliary 30"), - [PA_CHANNEL_POSITION_AUX31] = N_("Auxiliary 31"), - - [PA_CHANNEL_POSITION_TOP_CENTER] = N_("Top Center"), - - [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = N_("Top Front Center"), - [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = N_("Top Front Left"), - [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = N_("Top Front Right"), - - [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = N_("Top Rear Center"), - [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = N_("Top Rear Left"), - [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = N_("Top Rear Right") -}; - -SPA_EXPORT -pa_channel_map* pa_channel_map_init(pa_channel_map *m) { - unsigned c; - pa_assert(m); - - m->channels = 0; - - for (c = 0; c < PA_CHANNELS_MAX; c++) - m->map[c] = PA_CHANNEL_POSITION_INVALID; - - return m; -} - -SPA_EXPORT -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { - pa_assert(m); - - pa_channel_map_init(m); - - m->channels = 1; - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; -} - -SPA_EXPORT -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { - pa_assert(m); - - pa_channel_map_init(m); - - m->channels = 2; - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - return m; -} - -SPA_EXPORT -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { - pa_assert(m); - pa_assert(pa_channels_valid(channels)); - pa_assert(def < PA_CHANNEL_MAP_DEF_MAX); - - pa_channel_map_init(m); - - m->channels = (uint8_t) channels; - - switch (def) { - case PA_CHANNEL_MAP_AIFF: - - /* This is somewhat compatible with RFC3551 */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - 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_FRONT_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; - - case 5: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; - SPA_FALLTHROUGH - - 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; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_ALSA: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - SPA_FALLTHROUGH - - case 6: - m->map[5] = PA_CHANNEL_POSITION_LFE; - SPA_FALLTHROUGH - - case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - SPA_FALLTHROUGH - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - SPA_FALLTHROUGH - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_AUX: { - unsigned i; - - for (i = 0; i < channels; i++) - m->map[i] = PA_CHANNEL_POSITION_AUX0 + i; - - return m; - } - - case PA_CHANNEL_MAP_WAVEEX: - - /* Following http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EKLAC */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 18: - 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; - SPA_FALLTHROUGH - - case 15: - 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; - SPA_FALLTHROUGH - - case 12: - m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; - SPA_FALLTHROUGH - - case 11: - m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; - SPA_FALLTHROUGH - - case 9: - m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; - SPA_FALLTHROUGH - - case 8: - m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; - m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; - SPA_FALLTHROUGH - - case 6: - m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; - SPA_FALLTHROUGH - - case 4: - m->map[3] = PA_CHANNEL_POSITION_LFE; - SPA_FALLTHROUGH - - case 3: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - SPA_FALLTHROUGH - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_OSS: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; - SPA_FALLTHROUGH - - case 6: - m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; - SPA_FALLTHROUGH - - case 4: - m->map[3] = PA_CHANNEL_POSITION_LFE; - SPA_FALLTHROUGH - - case 3: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - SPA_FALLTHROUGH - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - default: - pa_assert_not_reached(); - } -} - -SPA_EXPORT -pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { - unsigned c; - - pa_assert(m); - pa_assert(pa_channels_valid(channels)); - pa_assert(def < PA_CHANNEL_MAP_DEF_MAX); - - pa_channel_map_init(m); - - for (c = channels; c > 0; c--) { - - if (pa_channel_map_init_auto(m, c, def)) { - unsigned i = 0; - - for (; c < channels; c++) { - - m->map[c] = PA_CHANNEL_POSITION_AUX0 + i; - i++; - } - - m->channels = (uint8_t) channels; - - return m; - } - } - - return NULL; -} - -SPA_EXPORT -const char* pa_channel_position_to_string(pa_channel_position_t pos) { - - if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) - return NULL; - - return table[pos]; -} - -SPA_EXPORT -const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) { - - if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) - return NULL; - - pa_init_i18n(); - - return _(pretty_table[pos]); -} - -SPA_EXPORT -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { - unsigned c; - - pa_assert(a); - pa_assert(b); - - pa_return_val_if_fail(pa_channel_map_valid(a), 0); - - if (PA_UNLIKELY(a == b)) - return 1; - - pa_return_val_if_fail(pa_channel_map_valid(b), 0); - - if (a->channels != b->channels) - return 0; - - for (c = 0; c < a->channels; c++) - if (a->map[c] != b->map[c]) - return 0; - - return 1; -} - -SPA_EXPORT -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { - unsigned channel; - char *e; - - pa_assert(s); - pa_assert(l > 0); - pa_assert(map); - - pa_init_i18n(); - - if (!pa_channel_map_valid(map)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - *(e = s) = 0; - - for (channel = 0; channel < map->channels && l > 1; channel++) { - l -= pa_snprintf(e, l, "%s%s", - channel == 0 ? "" : ",", - pa_channel_position_to_string(map->map[channel])); - - e = strchr(e, 0); - } - - return s; -} - -SPA_EXPORT -pa_channel_position_t pa_channel_position_from_string(const char *p) { - pa_channel_position_t i; - pa_assert(p); - - /* Some special aliases */ - if (pa_streq(p, "left")) - return PA_CHANNEL_POSITION_LEFT; - else if (pa_streq(p, "right")) - return PA_CHANNEL_POSITION_RIGHT; - else if (pa_streq(p, "center")) - return PA_CHANNEL_POSITION_CENTER; - else if (pa_streq(p, "subwoofer")) - return PA_CHANNEL_POSITION_SUBWOOFER; - - for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) - if (pa_streq(p, table[i])) - return i; - - return PA_CHANNEL_POSITION_INVALID; -} - -SPA_EXPORT -pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { - pa_channel_map map; - char **tokens; - int i, n_tokens; - - pa_assert(rmap); - pa_assert(s); - - pa_channel_map_init(&map); - - /* We don't need to match against the well known channel mapping - * "mono" here explicitly, because that can be understood as - * listing with one channel called "mono". */ - - if (pa_streq(s, "stereo")) { - map.channels = 2; - map.map[0] = PA_CHANNEL_POSITION_LEFT; - map.map[1] = PA_CHANNEL_POSITION_RIGHT; - goto finish; - } else if (pa_streq(s, "surround-21")) { - map.channels = 3; - map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - map.map[2] = PA_CHANNEL_POSITION_LFE; - goto finish; - } else if (pa_streq(s, "surround-40")) { - map.channels = 4; - map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - goto finish; - } else if (pa_streq(s, "surround-41")) { - map.channels = 5; - map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - map.map[4] = PA_CHANNEL_POSITION_LFE; - goto finish; - } else if (pa_streq(s, "surround-50")) { - map.channels = 5; - map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - goto finish; - } else if (pa_streq(s, "surround-51")) { - map.channels = 6; - map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - map.map[5] = PA_CHANNEL_POSITION_LFE; - goto finish; - } else if (pa_streq(s, "surround-71")) { - map.channels = 8; - map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - map.map[5] = PA_CHANNEL_POSITION_LFE; - map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - goto finish; - } - - map.channels = 0; - - tokens = pw_split_strv(s, ",", INT_MAX, &n_tokens); - - for (i = 0; i < n_tokens; i++) { - pa_channel_position_t f; - - if (map.channels >= PA_CHANNELS_MAX) { - pw_free_strv(tokens); - return NULL; - } - - if ((f = pa_channel_position_from_string(tokens[i])) == PA_CHANNEL_POSITION_INVALID) { - pw_free_strv(tokens); - return NULL; - } - map.map[map.channels++] = f; - } - pw_free_strv(tokens); - -finish: - - if (!pa_channel_map_valid(&map)) - return NULL; - - *rmap = map; - return rmap; -} - -SPA_EXPORT -int pa_channel_map_valid(const pa_channel_map *map) { - unsigned c; - - pa_assert(map); - - if (!pa_channels_valid(map->channels)) - return 0; - - for (c = 0; c < map->channels; c++) - if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX) - return 0; - - return 1; -} - -SPA_EXPORT -int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) { - pa_assert(map); - pa_assert(ss); - - pa_return_val_if_fail(pa_channel_map_valid(map), 0); - pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); - - return map->channels == ss->channels; -} - -SPA_EXPORT -int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { - pa_channel_position_mask_t am, bm; - - pa_assert(a); - pa_assert(b); - - pa_return_val_if_fail(pa_channel_map_valid(a), 0); - - if (PA_UNLIKELY(a == b)) - return 1; - - pa_return_val_if_fail(pa_channel_map_valid(b), 0); - - am = pa_channel_map_mask(a); - bm = pa_channel_map_mask(b); - - return (bm & am) == bm; -} - -SPA_EXPORT -int pa_channel_map_can_balance(const pa_channel_map *map) { - pa_channel_position_mask_t m; - - pa_assert(map); - pa_return_val_if_fail(pa_channel_map_valid(map), 0); - - m = pa_channel_map_mask(map); - - return - (PA_CHANNEL_POSITION_MASK_LEFT & m) && - (PA_CHANNEL_POSITION_MASK_RIGHT & m); -} - -SPA_EXPORT -int pa_channel_map_can_fade(const pa_channel_map *map) { - pa_channel_position_mask_t m; - - pa_assert(map); - pa_return_val_if_fail(pa_channel_map_valid(map), 0); - - m = pa_channel_map_mask(map); - - return - (PA_CHANNEL_POSITION_MASK_FRONT & m) && - (PA_CHANNEL_POSITION_MASK_REAR & m); -} - -SPA_EXPORT -int pa_channel_map_can_lfe_balance(const pa_channel_map *map) { - pa_channel_position_mask_t m; - - pa_assert(map); - pa_return_val_if_fail(pa_channel_map_valid(map), 0); - - m = pa_channel_map_mask(map); - - return - (PA_CHANNEL_POSITION_MASK_LFE & m) && - (PA_CHANNEL_POSITION_MASK_HFE & m); -} - -SPA_EXPORT -const char* pa_channel_map_to_name(const pa_channel_map *map) { - pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)]; - unsigned c; - - pa_assert(map); - - pa_return_val_if_fail(pa_channel_map_valid(map), NULL); - - memset(in_map, 0, sizeof(in_map)); - - for (c = 0; c < map->channels; c++) - pa_bitset_set(in_map, map->map[c], true); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_MONO, -1)) - return "mono"; - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1)) - return "stereo"; - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1)) - return "surround-40"; - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_LFE, -1)) - return "surround-41"; - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, -1)) - return "surround-50"; - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1)) - return "surround-51"; - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1)) - return "surround-71"; - - return NULL; -} - -SPA_EXPORT -const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) { - pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)]; - unsigned c; - - pa_assert(map); - - pa_return_val_if_fail(pa_channel_map_valid(map), NULL); - - memset(in_map, 0, sizeof(in_map)); - - for (c = 0; c < map->channels; c++) - pa_bitset_set(in_map, map->map[c], true); - - pa_init_i18n(); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_MONO, -1)) - return _("Mono"); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1)) - return _("Stereo"); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1)) - return _("Surround 4.0"); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_LFE, -1)) - return _("Surround 4.1"); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, -1)) - return _("Surround 5.0"); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1)) - return _("Surround 5.1"); - - if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1)) - return _("Surround 7.1"); - - return NULL; -} - -SPA_EXPORT -int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) { - unsigned c; - - pa_return_val_if_fail(pa_channel_map_valid(map), 0); - pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0); - - for (c = 0; c < map->channels; c++) - if (map->map[c] == p) - return 1; - - return 0; -} - -SPA_EXPORT -pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) { - unsigned c; - pa_channel_position_mask_t r = 0; - - pa_return_val_if_fail(pa_channel_map_valid(map), 0); - - for (c = 0; c < map->channels; c++) - r |= PA_CHANNEL_POSITION_MASK(map->map[c]); - - return r; -} - -static const uint32_t audio_channels[] = { - [PA_CHANNEL_POSITION_MONO] = SPA_AUDIO_CHANNEL_MONO, - - [PA_CHANNEL_POSITION_FRONT_LEFT] = SPA_AUDIO_CHANNEL_FL, - [PA_CHANNEL_POSITION_FRONT_RIGHT] = SPA_AUDIO_CHANNEL_FR, - [PA_CHANNEL_POSITION_FRONT_CENTER] = SPA_AUDIO_CHANNEL_FC, - - [PA_CHANNEL_POSITION_REAR_CENTER] = SPA_AUDIO_CHANNEL_RC, - [PA_CHANNEL_POSITION_REAR_LEFT] = SPA_AUDIO_CHANNEL_RL, - [PA_CHANNEL_POSITION_REAR_RIGHT] = SPA_AUDIO_CHANNEL_RR, - - [PA_CHANNEL_POSITION_LFE] = SPA_AUDIO_CHANNEL_LFE, - [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SPA_AUDIO_CHANNEL_FLC, - [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SPA_AUDIO_CHANNEL_FRC, - - [PA_CHANNEL_POSITION_SIDE_LEFT] = SPA_AUDIO_CHANNEL_SL, - [PA_CHANNEL_POSITION_SIDE_RIGHT] = SPA_AUDIO_CHANNEL_SR, - - [PA_CHANNEL_POSITION_AUX0] = SPA_AUDIO_CHANNEL_CUSTOM_START + 1, - [PA_CHANNEL_POSITION_AUX1] = SPA_AUDIO_CHANNEL_CUSTOM_START + 2, - [PA_CHANNEL_POSITION_AUX2] = SPA_AUDIO_CHANNEL_CUSTOM_START + 3, - [PA_CHANNEL_POSITION_AUX3] = SPA_AUDIO_CHANNEL_CUSTOM_START + 4, - [PA_CHANNEL_POSITION_AUX4] = SPA_AUDIO_CHANNEL_CUSTOM_START + 5, - [PA_CHANNEL_POSITION_AUX5] = SPA_AUDIO_CHANNEL_CUSTOM_START + 6, - [PA_CHANNEL_POSITION_AUX6] = SPA_AUDIO_CHANNEL_CUSTOM_START + 7, - [PA_CHANNEL_POSITION_AUX7] = SPA_AUDIO_CHANNEL_CUSTOM_START + 8, - [PA_CHANNEL_POSITION_AUX8] = SPA_AUDIO_CHANNEL_CUSTOM_START + 9, - [PA_CHANNEL_POSITION_AUX9] = SPA_AUDIO_CHANNEL_CUSTOM_START + 10, - [PA_CHANNEL_POSITION_AUX10] = SPA_AUDIO_CHANNEL_CUSTOM_START + 11, - [PA_CHANNEL_POSITION_AUX11] = SPA_AUDIO_CHANNEL_CUSTOM_START + 12, - [PA_CHANNEL_POSITION_AUX12] = SPA_AUDIO_CHANNEL_CUSTOM_START + 13, - [PA_CHANNEL_POSITION_AUX13] = SPA_AUDIO_CHANNEL_CUSTOM_START + 14, - [PA_CHANNEL_POSITION_AUX14] = SPA_AUDIO_CHANNEL_CUSTOM_START + 15, - [PA_CHANNEL_POSITION_AUX15] = SPA_AUDIO_CHANNEL_CUSTOM_START + 16, - [PA_CHANNEL_POSITION_AUX16] = SPA_AUDIO_CHANNEL_CUSTOM_START + 17, - [PA_CHANNEL_POSITION_AUX17] = SPA_AUDIO_CHANNEL_CUSTOM_START + 18, - [PA_CHANNEL_POSITION_AUX18] = SPA_AUDIO_CHANNEL_CUSTOM_START + 19, - [PA_CHANNEL_POSITION_AUX19] = SPA_AUDIO_CHANNEL_CUSTOM_START + 20, - [PA_CHANNEL_POSITION_AUX20] = SPA_AUDIO_CHANNEL_CUSTOM_START + 21, - [PA_CHANNEL_POSITION_AUX21] = SPA_AUDIO_CHANNEL_CUSTOM_START + 22, - [PA_CHANNEL_POSITION_AUX22] = SPA_AUDIO_CHANNEL_CUSTOM_START + 23, - [PA_CHANNEL_POSITION_AUX23] = SPA_AUDIO_CHANNEL_CUSTOM_START + 24, - [PA_CHANNEL_POSITION_AUX24] = SPA_AUDIO_CHANNEL_CUSTOM_START + 25, - [PA_CHANNEL_POSITION_AUX25] = SPA_AUDIO_CHANNEL_CUSTOM_START + 26, - [PA_CHANNEL_POSITION_AUX26] = SPA_AUDIO_CHANNEL_CUSTOM_START + 27, - [PA_CHANNEL_POSITION_AUX27] = SPA_AUDIO_CHANNEL_CUSTOM_START + 28, - [PA_CHANNEL_POSITION_AUX28] = SPA_AUDIO_CHANNEL_CUSTOM_START + 29, - [PA_CHANNEL_POSITION_AUX29] = SPA_AUDIO_CHANNEL_CUSTOM_START + 30, - [PA_CHANNEL_POSITION_AUX30] = SPA_AUDIO_CHANNEL_CUSTOM_START + 31, - [PA_CHANNEL_POSITION_AUX31] = SPA_AUDIO_CHANNEL_CUSTOM_START + 32, - - [PA_CHANNEL_POSITION_TOP_CENTER] = SPA_AUDIO_CHANNEL_TC, - - [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SPA_AUDIO_CHANNEL_TFL, - [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SPA_AUDIO_CHANNEL_TFR, - [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SPA_AUDIO_CHANNEL_TFC, - - [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SPA_AUDIO_CHANNEL_TRL, - [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SPA_AUDIO_CHANNEL_TRR, - [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SPA_AUDIO_CHANNEL_TRC, -}; - -static inline uint32_t channel_pa2id(pa_channel_position_t channel) -{ - if (channel < 0 || (size_t)channel >= SPA_N_ELEMENTS(audio_channels)) - return SPA_AUDIO_CHANNEL_UNKNOWN; - return audio_channels[channel]; -} - -static inline pa_channel_position_t channel_id2pa(uint32_t id, uint32_t *aux) -{ - size_t i; - for (i = 0; i < SPA_N_ELEMENTS(audio_channels); i++) { - if (id == audio_channels[i]) - return i; - } - return PA_CHANNEL_POSITION_AUX0 + (*aux)++; -} - -void pw_channel_map_from_positions(pa_channel_map *map, uint32_t n_pos, const uint32_t *pos) -{ - uint32_t i, aux = 0; - - pa_channel_map_init(map); - map->channels = n_pos; - for (i = 0; i < n_pos; i++) - map->map[i] = channel_id2pa(pos[i], &aux); - - if (!pa_channel_map_valid(map)) - pa_channel_map_init_extend(map, n_pos, PA_CHANNEL_MAP_DEFAULT); -} - -void pw_channel_map_to_positions(const pa_channel_map *map, uint32_t *pos) -{ - int i; - for (i = 0; i < map->channels; i++) - pos[i] = channel_pa2id(map->map[i]); -} diff --git a/pipewire-pulseaudio/src/context.c b/pipewire-pulseaudio/src/context.c deleted file mode 100644 index 8bc66dc23..000000000 --- a/pipewire-pulseaudio/src/context.c +++ /dev/null @@ -1,2238 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "internal.h" - -int pa_context_set_error(PA_CONST pa_context *c, int error) { - pa_assert(error >= 0); - pa_assert(error < PA_ERR_MAX); - if (c) { - pw_log_debug("context %p: error %d %s", c, error, pa_strerror(error)); - ((pa_context*)c)->error = error; - } - return error; -} - -static void global_free(pa_context *c, struct global *g) -{ - pw_log_debug("context %p: %d", c, g->id); - - spa_list_remove(&g->link); - - if (g->ginfo && g->ginfo->destroy) - g->ginfo->destroy(g); - if (g->stream) - g->stream->global = NULL; - if (g->proxy) - pw_proxy_destroy(g->proxy); - if (g->props) - pw_properties_free(g->props); - free(g->type); - free(g); -} - -static void context_unlink(pa_context *c) -{ - pa_stream *s, *t; - struct global *g; - pa_operation *o; - struct module_info *m; - - pw_log_debug("context %p: unlink %d", c, c->state); - - c->disconnect = true; - c->state_callback = NULL; - c->state_userdata = NULL; - - spa_list_for_each_safe(s, t, &c->streams, link) { - pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? - PA_STREAM_FAILED : PA_STREAM_TERMINATED); - } - if (c->registry) { - spa_hook_remove(&c->core_listener), - pw_proxy_destroy((struct pw_proxy*)c->registry); - c->registry = NULL; - } - if (c->core) { - spa_hook_remove(&c->core_listener); - pw_core_disconnect(c->core); - c->core = NULL; - } - spa_list_consume(g, &c->globals, link) - global_free(c, g); - - spa_list_consume(o, &c->operations, link) - pa_operation_cancel(o); - spa_list_consume(m, &c->modules, link) - pw_proxy_destroy(m->proxy); -} - -void pa_context_set_state(pa_context *c, pa_context_state_t st) { - pa_assert(c); - pa_assert(c->refcount >= 1); - - if (c->state == st) - return; - - pw_log_debug("context %p: state %d", c, st); - - pa_context_ref(c); - - c->state = st; - - if (c->state_callback) - c->state_callback(c, c->state_userdata); - - if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) - context_unlink(c); - - pa_context_unref(c); -} - -void pa_context_fail(PA_CONST pa_context *c, int error) { - pa_assert(c); - pa_assert(c->refcount >= 1); - - pw_log_debug("context %p: error %d", c, error); - - pa_context_set_error(c, error); - pa_context_set_state((pa_context*)c, PA_CONTEXT_FAILED); -} - -SPA_EXPORT -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) -{ - return pa_context_new_with_proplist(mainloop, name, NULL); -} - -pa_stream *pa_context_find_stream(pa_context *c, uint32_t idx) -{ - pa_stream *s; - spa_list_for_each(s, &c->streams, link) { - if (s->stream_index == idx) - return s; - } - return NULL; -} - -struct global *pa_context_find_global(pa_context *c, uint32_t id) -{ - struct global *g; - spa_list_for_each(g, &c->globals, link) { - if (g->id == id) - return g; - } - return NULL; -} - -const char *pa_context_find_global_name(pa_context *c, uint32_t id) -{ - struct global *g; - const char *name = NULL; - - g = pa_context_find_global(c, id & PA_IDX_MASK_MONITOR); - if (g == NULL) - return "unknown object"; - - if (g->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) { - name = pw_properties_get(g->props, PW_KEY_NODE_NAME); - } - if (name == NULL) - name = "unknown"; - return name; -} - -struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, const char *name) -{ - struct global *g; - const char *str; - uint32_t id; - - if (strcmp(name, "@DEFAULT_SINK@") == 0 || strcmp("@DEFAULT_MONITOR@", name) == 0) - id = c->default_sink; - else if (strcmp(name, "@DEFAULT_SOURCE@") == 0) - id = c->default_source; - else - id = atoi(name); - - spa_list_for_each(g, &c->globals, link) { - if ((g->mask & mask) == 0) - continue; - if (g->props != NULL && - (str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) != NULL) { - if (strcmp(str, name) == 0) - return g; - if (pa_endswith(name, ".monitor") && - strncmp(str, name, strlen(name) - 8) == 0) - return g; - } - if (id == SPA_ID_INVALID || g->id == id || (g->id == (id & PA_IDX_MASK_MONITOR))) - return g; - } - return NULL; -} - -struct global *pa_context_find_linked(pa_context *c, uint32_t idx) -{ - struct global *g, *f; - - spa_list_for_each(g, &c->globals, link) { - uint32_t src_node_id, dst_node_id; - - if (strcmp(g->type, PW_TYPE_INTERFACE_Link) != 0) - continue; - - src_node_id = g->link_info.src->port_info.node_id; - dst_node_id = g->link_info.dst->port_info.node_id; - - pw_log_debug("context %p: %p %d %d %d", c, g, idx, - src_node_id, dst_node_id); - - if (src_node_id == idx) - f = pa_context_find_global(c, dst_node_id); - else if (dst_node_id == idx) - f = pa_context_find_global(c, src_node_id); - else - continue; - - if (f == NULL || - !(f->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE))) - continue; - return f; - } - return NULL; -} - -static const char *str_etype(pa_subscription_event_type_t event) -{ - switch (event & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { - case PA_SUBSCRIPTION_EVENT_NEW: - return "new"; - case PA_SUBSCRIPTION_EVENT_CHANGE: - return "change"; - case PA_SUBSCRIPTION_EVENT_REMOVE: - return "remove"; - } - return "invalid"; -} - -static const char *str_efac(pa_subscription_event_type_t event) -{ - switch (event & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - return "sink"; - case PA_SUBSCRIPTION_EVENT_SOURCE: - return "source"; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - return "sink-input"; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - return "source-output"; - case PA_SUBSCRIPTION_EVENT_MODULE: - return "module"; - case PA_SUBSCRIPTION_EVENT_CLIENT: - return "client"; - case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE: - return "sample-cache"; - case PA_SUBSCRIPTION_EVENT_SERVER: - return "server"; - case PA_SUBSCRIPTION_EVENT_AUTOLOAD: - return "autoload"; - case PA_SUBSCRIPTION_EVENT_CARD: - return "card"; - } - return "invalid"; -} - -static void emit_event(pa_context *c, struct global *g, pa_subscription_event_type_t event) -{ - if (c->subscribe_callback && (c->subscribe_mask & g->mask)) { - pw_log_debug("context %p: obj %d: emit %s:%s", c, g->id, - str_etype(event), str_efac(g->event)); - c->subscribe_callback(c, - event | g->event, - g->id, - c->subscribe_userdata); - - if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) { - pw_log_debug("context %p: obj %d: emit %s:source", c, g->node_info.monitor, - str_etype(event)); - c->subscribe_callback(c, - event | PA_SUBSCRIPTION_EVENT_SOURCE, - g->node_info.monitor, - c->subscribe_userdata); - } - } -} - -static void do_global_sync(struct global *g) -{ - pa_subscription_event_type_t event; - - pw_log_debug("global %p sync", g); - if (g->ginfo && g->ginfo->sync) - g->ginfo->sync(g); - - if (g->init) { - if ((g->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT))) { - if (g->node_info.device_index == SPA_ID_INVALID || - (g->stream && g->stream->state != PA_STREAM_READY)) - return; - } - g->init = false; - g->changed++; - event = PA_SUBSCRIPTION_EVENT_NEW; - } else { - event = PA_SUBSCRIPTION_EVENT_CHANGE; - } - if (g->changed > 0) { - emit_event(g->context, g, event); - g->changed = 0; - } -} - - -static void global_sync(struct global *g) -{ - pa_context *c = g->context; - if (c->core != NULL) - c->pending_seq = pw_core_sync(c->core, PW_ID_CORE, c->pending_seq); - g->sync = true; -} - -static struct param *add_param(struct spa_list *params, uint32_t id, const struct spa_pod *param) -{ - struct param *p; - - if (param == NULL || !spa_pod_is_object(param)) { - errno = EINVAL; - return NULL; - } - if (id == SPA_ID_INVALID) - id = SPA_POD_OBJECT_ID(param); - - p = malloc(sizeof(struct param) + SPA_POD_SIZE(param)); - if (p == NULL) - return NULL; - - p->id = id; - p->param = SPA_MEMBER(p, sizeof(struct param), struct spa_pod); - memcpy(p->param, param, SPA_POD_SIZE(param)); - spa_list_append(params, &p->link); - - return p; -} - -static void remove_params(struct spa_list *params, uint32_t id) -{ - struct param *p, *t; - spa_list_for_each_safe(p, t, params, link) { - if (id == SPA_ID_INVALID || p->id == id) { - spa_list_remove(&p->link); - free(p); - } - } -} - -static void update_device_props(struct global *g) -{ - pa_card_info *i = &g->card_info.info; - const char *s; - - if ((s = pa_proplist_gets(i->proplist, PW_KEY_DEVICE_ICON_NAME))) - pa_proplist_sets(i->proplist, PA_PROP_DEVICE_ICON_NAME, s); -} - - -static void device_event_info(void *object, const struct pw_device_info *info) -{ - struct global *g = object; - pa_card_info *i = &g->card_info.info; - const char *str; - uint32_t n; - - pw_log_debug("global %p: id:%d change-mask:%"PRIu64, g, g->id, info->change_mask); - info = g->info = pw_device_info_update(g->info, info); - - i->index = g->id; - i->name = info->props ? - spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME) : "unknown"; - str = info->props ? spa_dict_lookup(info->props, PW_KEY_MODULE_ID) : NULL; - i->owner_module = str ? (unsigned)atoi(str) : SPA_ID_INVALID; - if (info->change_mask & PW_DEVICE_CHANGE_MASK_PROPS) { - i->driver = info->props ? - spa_dict_lookup(info->props, PW_KEY_DEVICE_API) : NULL; - - if (i->proplist) - pa_proplist_update_dict(i->proplist, info->props); - else { - i->proplist = pa_proplist_new_dict(info->props); - } - update_device_props(g); - g->changed++; - } - if (info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) { - for (n = 0; n < info->n_params; n++) { - uint32_t id = info->params[n].id; - bool do_enum = true; - - if (info->params[n].user == 0) - continue; - - info->params[n].user = 0; - - switch (id) { - case SPA_PARAM_EnumProfile: - if (g->card_info.pending_profiles) - continue; - remove_params(&g->card_info.profiles, id); - g->changed++; - g->card_info.n_profiles = 0; - break; - case SPA_PARAM_EnumRoute: - if (g->card_info.pending_ports) - continue; - remove_params(&g->card_info.ports, id); - g->changed++; - g->card_info.n_ports = 0; - break; - case SPA_PARAM_Route: - remove_params(&g->card_info.routes, id); - g->card_info.n_routes = 0; - break; - case SPA_PARAM_Profile: - break; - default: - do_enum = false; - break; - } - if (!(info->params[n].flags & SPA_PARAM_INFO_READ)) - continue; - if (do_enum) { - switch (id) { - case SPA_PARAM_EnumProfile: - case SPA_PARAM_Profile: - g->card_info.pending_profiles = true; - break; - case SPA_PARAM_EnumRoute: - case SPA_PARAM_Route: - g->card_info.pending_ports = true; - break; - } - pw_log_debug("global %p: id:%d do enum %s", g, g->id, - spa_debug_type_find_name(spa_type_param, id)); - pw_device_enum_params((struct pw_device*)g->proxy, - 0, id, 0, -1, NULL); - } - } - } - if (i->driver == NULL) - i->driver = "PipeWire"; - global_sync(g); -} - -static int parse_props(struct global *g, const struct spa_pod *param, bool device) -{ - int changed = 0; - struct spa_pod_prop *prop; - struct spa_pod_object *obj = (struct spa_pod_object *) param; - - SPA_POD_OBJECT_FOREACH(obj, prop) { - switch (prop->key) { - case SPA_PROP_volume: - { - float vol; - if (spa_pod_get_float(&prop->value, &vol) >= 0 && - g->node_info.volume != vol) { - g->node_info.volume = vol; - changed++; - } - SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME, device); - SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_VOLUME, - prop->flags & SPA_POD_PROP_FLAG_HARDWARE); - break; - } - case SPA_PROP_mute: - { - bool mute; - if (spa_pod_get_bool(&prop->value, &mute) >= 0 && - g->node_info.mute != mute) { - g->node_info.mute = mute; - changed++; - } - SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_MUTE, device); - SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_MUTE, - prop->flags & SPA_POD_PROP_FLAG_HARDWARE); - break; - } - case SPA_PROP_channelVolumes: - { - uint32_t n_vals; - float vol[SPA_AUDIO_MAX_CHANNELS]; - - n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, - vol, SPA_AUDIO_MAX_CHANNELS); - - if (n_vals != g->node_info.n_channel_volumes) { - pw_log_debug("channel change %d->%d, trigger remove", - g->node_info.n_channel_volumes, n_vals); - if (!g->init) - emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_REMOVE); - g->node_info.n_channel_volumes = n_vals; - /* mark as init, this will emit the NEW event when the - * params are updated */ - g->init = g->sync = true; - changed++; - } - if (memcmp(g->node_info.channel_volumes, vol, n_vals * sizeof(float)) != 0) { - memcpy(g->node_info.channel_volumes, vol, n_vals * sizeof(float)); - changed++; - } - SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME, device); - SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_VOLUME, - prop->flags & SPA_POD_PROP_FLAG_HARDWARE); - break; - } - case SPA_PROP_volumeBase: - spa_pod_get_float(&prop->value, &g->node_info.base_volume); - break; - case SPA_PROP_volumeStep: - spa_pod_get_float(&prop->value, &g->node_info.volume_step); - break; - default: - break; - } - } - return changed; -} - -static struct global *find_node_for_route(pa_context *c, struct global *card, uint32_t device) -{ - struct global *n; - spa_list_for_each(n, &c->globals, link) { - if (strcmp(n->type, PW_TYPE_INTERFACE_Node) != 0) - continue; - pw_log_debug("%d/%d %d/%d", - n->node_info.device_id, card->id, - n->node_info.profile_device_id, device); - if (n->node_info.device_id != card->id) - continue; - if (n->node_info.profile_device_id != device) - continue; - return n; - } - return NULL; -} - -static void device_event_param(void *object, int seq, - uint32_t id, uint32_t index, uint32_t next, - const struct spa_pod *param) -{ - struct global *g = object; - - pw_log_debug("update param %d %s", g->id, - spa_debug_type_find_name(spa_type_param, id)); - - switch (id) { - case SPA_PARAM_EnumProfile: - { - uint32_t index; - const char *name; - - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&index), - SPA_PARAM_PROFILE_name, SPA_POD_String(&name)) < 0) { - pw_log_warn("device %d: can't parse profile", g->id); - return; - } - if (add_param(&g->card_info.profiles, id, param)) - g->card_info.n_profiles++; - - pw_log_debug("device %d: enum profile %d: \"%s\" n_profiles:%d", g->id, - index, name, g->card_info.n_profiles); - break; - } - case SPA_PARAM_Profile: - { - uint32_t index; - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&index)) < 0) { - pw_log_warn("device %d: can't parse profile", g->id); - return; - } - pw_log_debug("device %d: current profile %d", g->id, index); - if (g->card_info.active_profile != index) { - g->changed++; - g->card_info.active_profile = index; - } - break; - } - case SPA_PARAM_EnumRoute: - { - uint32_t index; - const char *name; - - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&index), - SPA_PARAM_ROUTE_name, SPA_POD_String(&name)) < 0) { - pw_log_warn("device %d: can't parse route", g->id); - return; - } - if (add_param(&g->card_info.ports, id, param)) - g->card_info.n_ports++; - - pw_log_debug("device %d: enum route %d: \"%s\"", g->id, index, name); - break; - } - case SPA_PARAM_Route: - { - uint32_t index, device; - enum spa_direction direction; - - if (spa_pod_parse_object(param, - SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&index), - SPA_PARAM_ROUTE_direction, SPA_POD_Id(&direction), - SPA_PARAM_ROUTE_device, SPA_POD_Int(&device)) < 0) { - pw_log_warn("device %d: can't parse route", g->id); - return; - } - if (add_param(&g->card_info.routes, id, param)) - g->card_info.n_routes++; - - pw_log_debug("device %d: active %s route %d device %d", g->id, - direction == SPA_DIRECTION_OUTPUT ? "output" : "input", - index, device); - break; - } - default: - break; - } -} - -static void device_clear_profiles(struct global *g) -{ - pa_card_info *i = &g->card_info.info; - i->n_profiles = 0; - free(i->profiles); - i->profiles = NULL; - free(g->card_info.card_profiles); - g->card_info.card_profiles = NULL; - free(i->profiles2); - i->profiles2 = NULL; -} - -static void device_sync_profiles(struct global *g) -{ - pa_card_info *i = &g->card_info.info; - uint32_t n_profiles, j; - struct param *p; - - device_clear_profiles(g); - - n_profiles = g->card_info.n_profiles; - - i->profiles = calloc(n_profiles, sizeof(pa_card_profile_info)); - g->card_info.card_profiles = calloc(n_profiles, sizeof(pa_card_profile_info2)); - i->profiles2 = calloc(n_profiles + 1, sizeof(pa_card_profile_info2 *)); - i->n_profiles = 0; - - pw_log_debug("context %p: info for %d n_profiles:%d", g->context, g->id, n_profiles); - - j = 0; - spa_list_for_each(p, &g->card_info.profiles, link) { - uint32_t id, priority = 0, available = 0, n_cap = 0, n_play = 0; - const char *name = NULL; - const char *description = NULL; - struct spa_pod *classes = NULL, *info = NULL; - - if (spa_pod_parse_object(p->param, - SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&id), - SPA_PARAM_PROFILE_name, SPA_POD_String(&name), - SPA_PARAM_PROFILE_description, SPA_POD_OPT_String(&description), - SPA_PARAM_PROFILE_priority, SPA_POD_OPT_Int(&priority), - SPA_PARAM_PROFILE_available, SPA_POD_OPT_Id(&available), - SPA_PARAM_PROFILE_info, SPA_POD_OPT_Pod(&info), - SPA_PARAM_PROFILE_classes, SPA_POD_OPT_Pod(&classes)) < 0) { - pw_log_warn("device %d: can't parse profile", g->id); - continue; - } - if (classes != NULL) { - struct spa_pod *iter; - - SPA_POD_STRUCT_FOREACH(classes, iter) { - struct spa_pod_parser prs; - struct spa_pod_frame f[1]; - char *class; - uint32_t count; - - spa_pod_parser_pod(&prs, iter); - if (spa_pod_parser_get_struct(&prs, - SPA_POD_String(&class), - SPA_POD_Int(&count)) < 0) - continue; - - if (strcmp(class, "Audio/Sink") == 0) - n_play += count; - else if (strcmp(class, "Audio/Source") == 0) - n_cap += count; - - spa_pod_parser_pop(&prs, &f[0]); - } - } - pw_log_debug("profile %d: name:%s", j, name); - - i->profiles[j].name = name; - i->profiles[j].description = description ? description : name; - i->profiles[j].n_sinks = n_play; - i->profiles[j].n_sources = n_cap; - i->profiles[j].priority = priority; - - i->profiles2[j] = &g->card_info.card_profiles[j]; - i->profiles2[j]->name = i->profiles[j].name; - i->profiles2[j]->description = i->profiles[j].description; - i->profiles2[j]->n_sinks = i->profiles[j].n_sinks; - i->profiles2[j]->n_sources = i->profiles[j].n_sources; - i->profiles2[j]->priority = i->profiles[j].priority; - i->profiles2[j]->available = available != SPA_PARAM_AVAILABILITY_no; - - if (g->card_info.active_profile == id) { - i->active_profile = &i->profiles[j]; - i->active_profile2 = i->profiles2[j]; - } - j++; - } - i->profiles2[j] = NULL; - i->n_profiles = j; -} - -static void device_clear_ports(struct global *g) -{ - pa_card_info *i = &g->card_info.info; - uint32_t n; - - pw_log_debug("device %d clear ports %d", g->id, i->n_ports); - - for (n = 0; n < i->n_ports; n++) { - pa_card_port_info *pi = i->ports[n]; - pa_proplist_free(pi->proplist); - free(pi->profiles2); - } - - i->n_ports = 0; - free(i->ports); - i->ports = NULL; - free(g->card_info.card_ports); - g->card_info.card_ports = NULL; - free(g->card_info.port_devices); - g->card_info.port_devices = NULL; -} - -static void device_sync_ports(struct global *g) -{ - pa_card_info *i = &g->card_info.info; - pa_context *c = g->context; - uint32_t n_ports, j; - struct param *p; - - device_clear_ports(g); - - n_ports = g->card_info.n_ports; - i->ports = calloc(n_ports+1, sizeof(pa_card_port_info *)); - g->card_info.card_ports = calloc(n_ports, sizeof(pa_card_port_info)); - g->card_info.port_devices = calloc(n_ports, sizeof(struct port_device)); - i->n_ports = 0; - - pw_log_debug("context %p: info for %d n_ports:%d", g->context, g->id, n_ports); - - j = 0; - - spa_list_for_each(p, &g->card_info.ports, link) { - uint32_t id, priority; - enum spa_direction direction; - const char *name = NULL, *description = NULL; - enum spa_param_availability available = SPA_PARAM_AVAILABILITY_unknown; - struct spa_pod *profiles = NULL, *info = NULL, *devices = NULL; - pa_card_port_info *pi; - struct port_device *pd; - - if (spa_pod_parse_object(p->param, - SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&id), - SPA_PARAM_ROUTE_direction, SPA_POD_Id(&direction), - SPA_PARAM_ROUTE_name, SPA_POD_String(&name), - SPA_PARAM_ROUTE_description, SPA_POD_OPT_String(&description), - SPA_PARAM_ROUTE_priority, SPA_POD_OPT_Int(&priority), - SPA_PARAM_ROUTE_available, SPA_POD_OPT_Id(&available), - SPA_PARAM_ROUTE_info, SPA_POD_OPT_Pod(&info), - SPA_PARAM_ROUTE_devices, SPA_POD_OPT_Pod(&devices), - SPA_PARAM_ROUTE_profiles, SPA_POD_OPT_Pod(&profiles)) < 0) { - pw_log_warn("device %d: can't parse route", g->id); - continue; - } - - pw_log_debug("port %d: name:%s available:%d", j, name, available); - - pi = i->ports[j] = &g->card_info.card_ports[j]; - spa_zero(*pi); - pi->name = name; - pi->description = description; - pi->priority = priority; - pi->available = available; - pi->direction = direction == SPA_DIRECTION_INPUT ? PA_DIRECTION_INPUT : PA_DIRECTION_OUTPUT; - pi->proplist = pa_proplist_new(); - while (info) { - struct spa_pod_parser prs; - struct spa_pod_frame f[1]; - int32_t n, n_items; - const char *key, *value; - - spa_pod_parser_pod(&prs, info); - if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 || - spa_pod_parser_get_int(&prs, &n_items) < 0) - break; - - for (n = 0; n < n_items; n++) { - if (spa_pod_parser_get(&prs, - SPA_POD_String(&key), - SPA_POD_String(&value), - NULL) < 0) - break; - pa_proplist_sets(pi->proplist, key, value); - } - spa_pod_parser_pop(&prs, &f[0]); - break; - } - pi->n_profiles = 0; - pi->profiles = NULL; - pi->profiles2 = NULL; - while (profiles) { - uint32_t *pr, n, n_pr; - - pr = spa_pod_get_array(profiles, &n_pr); - if (pr == NULL) - break; - - pi->n_profiles = n_pr; - pi->profiles2 = calloc(n_pr + 1, sizeof(pa_card_profile_info2 *)); - for (n = 0; n < n_pr; n++) - pi->profiles2[n] = i->profiles2[pr[n]]; - pi->profiles2[n_pr] = NULL; - pi->profiles = (pa_card_profile_info **)pi->profiles2; - break; - } - pd = &g->card_info.port_devices[j]; - pd->n_devices = 0; - pd->devices = NULL; - if (devices) - pd->devices = spa_pod_get_array(devices, &pd->n_devices); - j++; - } - i->ports[j] = NULL; - i->n_ports = j; - if (i->n_ports == 0) { - device_clear_ports(g); - } - - spa_list_for_each(p, &g->card_info.routes, link) { - struct global *ng; - uint32_t index, device; - enum spa_param_availability available = SPA_PARAM_AVAILABILITY_unknown; - struct spa_pod *props = NULL; - const char *name; - - if (spa_pod_parse_object(p->param, - SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&index), - SPA_PARAM_ROUTE_name, SPA_POD_String(&name), - SPA_PARAM_ROUTE_device, SPA_POD_Int(&device), - SPA_PARAM_ROUTE_available, SPA_POD_OPT_Id(&available), - SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props)) < 0) { - pw_log_warn("device %d: can't parse route", g->id); - continue; - } - ng = find_node_for_route(c, g, device); - if (ng) { - int changed = 0; - pw_log_debug("device: %d port:%d: name:%s available:%d", ng->id, - index, name, available); - if (ng->node_info.active_port != index) { - ng->node_info.active_port = index; - changed++; - } - if (ng->node_info.available_port != available) { - ng->node_info.available_port = available; - changed++; - } - if (props) - changed += parse_props(ng, props, true); - ng->changed += changed; - if (ng->changed) - global_sync(ng); - } - } -} - -static void device_sync(struct global *g) -{ - if (g->card_info.pending_profiles) { - device_sync_profiles(g); - g->card_info.pending_profiles = false; - g->card_info.pending_ports = true; - } - if (g->card_info.pending_ports) { - device_sync_ports(g); - g->card_info.pending_ports = false; - } -} - -static const struct pw_device_events device_events = { - PW_VERSION_DEVICE_EVENTS, - .info = device_event_info, - .param = device_event_param, -}; - -static void device_destroy(void *data) -{ - struct global *global = data; - - pw_log_debug("device %d destroy", global->id); - - if (global->card_info.info.proplist) - pa_proplist_free(global->card_info.info.proplist); - - device_clear_ports(global); - device_clear_profiles(global); - - remove_params(&global->card_info.routes, SPA_ID_INVALID); - remove_params(&global->card_info.ports, SPA_ID_INVALID); - remove_params(&global->card_info.profiles, SPA_ID_INVALID); - - if (global->info) - pw_device_info_free(global->info); -} - -struct global_info device_info = { - .version = PW_VERSION_DEVICE, - .events = &device_events, - .destroy = device_destroy, - .sync = device_sync, -}; - -static void clear_node_formats(struct global *g) -{ - pa_format_info **f; - pw_array_for_each(f, &g->node_info.formats) - pa_format_info_free(*f); - pw_array_reset(&g->node_info.formats); - g->changed++; -} - -static void node_event_info(void *object, const struct pw_node_info *info) -{ - struct global *g = object; - const char *str; - uint32_t i; - - pw_log_debug("global %p: id:%d change-mask:%"PRIu64, g, g->id, info->change_mask); - info = g->info = pw_node_info_update(g->info, info); - - if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS) { - if (info->props && (str = spa_dict_lookup(info->props, "card.profile.device"))) - g->node_info.profile_device_id = atoi(str); - else - g->node_info.profile_device_id = SPA_ID_INVALID; - g->changed++; - } - if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) { - for (i = 0; i < info->n_params; i++) { - uint32_t id = info->params[i].id; - bool do_enum; - - if (info->params[i].user == 0) - continue; - info->params[i].user = 0; - - switch (id) { - case SPA_PARAM_EnumFormat: - clear_node_formats(g); - SPA_FALLTHROUGH - case SPA_PARAM_Props: - case SPA_PARAM_Format: - do_enum = true; - break; - default: - do_enum = false; - break; - } - - if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) - continue; - - if (do_enum) { - pw_log_debug("global %p: id:%d do enum %s", g, g->id, - spa_debug_type_find_name(spa_type_param, id)); - - pw_node_enum_params((struct pw_node*)g->proxy, - 0, id, 0, -1, NULL); - } - } - } - global_sync(g); -} - -static void node_event_param(void *object, int seq, - uint32_t id, uint32_t index, uint32_t next, - const struct spa_pod *param) -{ - struct global *g = object; - - pw_log_debug("update param %d %s", g->id, - spa_debug_type_find_name(spa_type_param, id)); - - switch (id) { - case SPA_PARAM_Props: - if (!SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME | NODE_FLAG_DEVICE_MUTE)) - parse_props(g, param, false); - break; - case SPA_PARAM_EnumFormat: - { - pa_format_info *f = pa_format_info_from_param(param); - if (f) { - pw_array_add_ptr(&g->node_info.formats, f); - - if (g->node_info.channel_map.channels == 0) - pa_format_info_get_channel_map(f, &g->node_info.channel_map); - - if (g->node_info.sample_spec.format == 0 || - g->node_info.sample_spec.rate == 0 || - g->node_info.sample_spec.channels == 0) { - pa_format_info_get_sample_format(f, &g->node_info.sample_spec.format); - pa_format_info_get_rate(f, &g->node_info.sample_spec.rate); - pa_format_info_get_channels(f, &g->node_info.sample_spec.channels); - } - } - break; - } - case SPA_PARAM_Format: - pa_format_parse_param(param, &g->node_info.sample_spec, &g->node_info.channel_map); - break; - default: - break; - } -} - -static const struct pw_node_events node_events = { - PW_VERSION_NODE_EVENTS, - .info = node_event_info, - .param = node_event_param, -}; - -static void node_destroy(void *data) -{ - struct global *global = data; - clear_node_formats(global); - pw_array_clear(&global->node_info.formats); - if (global->info) - pw_node_info_free(global->info); -} - -struct global_info node_info = { - .version = PW_VERSION_NODE, - .events = &node_events, - .destroy = node_destroy, -}; - - -static void module_event_info(void *object, const struct pw_module_info *info) -{ - struct global *g = object; - pa_module_info *i = &g->module_info.info; - - pw_log_debug("global %p: id:%d change-mask:%"PRIu64, g, g->id, info->change_mask); - - info = g->info = pw_module_info_update(g->info, info); - - i->index = g->id; - if (info->change_mask & PW_MODULE_CHANGE_MASK_PROPS) { - if (i->proplist) - pa_proplist_update_dict(i->proplist, info->props); - else - i->proplist = pa_proplist_new_dict(info->props); - g->changed++; - } - i->name = info->name; - i->argument = info->args; - i->n_used = -1; - i->auto_unload = false; - global_sync(g); -} - -static const struct pw_module_events module_events = { - PW_VERSION_MODULE_EVENTS, - .info = module_event_info, -}; - -static void module_destroy(void *data) -{ - struct global *global = data; - if (global->module_info.info.proplist) - pa_proplist_free(global->module_info.info.proplist); - if (global->info) - pw_module_info_free(global->info); -} - -struct global_info module_info = { - .version = PW_VERSION_MODULE, - .events = &module_events, - .destroy = module_destroy, -}; - -static void client_event_info(void *object, const struct pw_client_info *info) -{ - struct global *g = object; - const char *str; - pa_client_info *i = &g->client_info.info; - - pw_log_debug("global %p: id:%d change-mask:%"PRIu64, g, g->id, info->change_mask); - info = g->info = pw_client_info_update(g->info, info); - - i->index = g->id; - str = info->props ? spa_dict_lookup(info->props, PW_KEY_MODULE_ID) : NULL; - i->owner_module = str ? (unsigned)atoi(str) : SPA_ID_INVALID; - - if (info->change_mask & PW_CLIENT_CHANGE_MASK_PROPS) { - if (i->proplist) - pa_proplist_update_dict(i->proplist, info->props); - else - i->proplist = pa_proplist_new_dict(info->props); - i->name = info->props ? - spa_dict_lookup(info->props, PW_KEY_APP_NAME) : NULL; - i->driver = info->props ? - spa_dict_lookup(info->props, PW_KEY_PROTOCOL) : NULL; - g->changed++; - } - if (i->name == NULL) - i->name = "Unknown"; - if (i->driver == NULL) - i->name = "PipeWire"; - global_sync(g); -} - -static const struct pw_client_events client_events = { - PW_VERSION_CLIENT_EVENTS, - .info = client_event_info, -}; - -static void client_destroy(void *data) -{ - struct global *global = data; - if (global->client_info.info.proplist) - pa_proplist_free(global->client_info.info.proplist); - if (global->info) - pw_client_info_free(global->info); -} - -struct global_info client_info = { - .version = PW_VERSION_CLIENT, - .events = &client_events, - .destroy = client_destroy, -}; - -static int metadata_property(void *object, - uint32_t subject, - const char *key, - const char *type, - const char *value) -{ - struct global *global = object; - pa_context *c = global->context; - uint32_t val; - bool changed = false; - - if (subject == PW_ID_CORE) { - val = (key && value) ? (uint32_t)atoi(value) : SPA_ID_INVALID; - if (key == NULL || strcmp(key, METADATA_DEFAULT_SINK) == 0) { - changed = c->default_sink != val; - c->default_sink = val; - } - if (key == NULL || strcmp(key, METADATA_DEFAULT_SOURCE) == 0) { - changed = c->default_source != val; - c->default_source = val; - } - } - if (changed) - emit_event(global->context, global, PA_SUBSCRIPTION_EVENT_CHANGE); - - return 0; -} - -static const struct pw_metadata_events metadata_events = { - PW_VERSION_METADATA_EVENTS, - .property = metadata_property, -}; - -static void metadata_destroy(void *data) -{ - struct global *global = data; - pa_context *c = global->context; - if (c->metadata == global) - c->metadata = NULL; -} - -struct global_info metadata_info = { - .version = PW_VERSION_METADATA, - .events = &metadata_events, - .destroy = metadata_destroy, -}; - -static void proxy_removed(void *data) -{ - struct global *g = data; - pw_proxy_destroy(g->proxy); -} - -static void proxy_destroy(void *data) -{ - struct global *g = data; - spa_hook_remove(&g->proxy_listener); - spa_hook_remove(&g->object_listener); - g->proxy = NULL; -} - -static const struct pw_proxy_events proxy_events = { - PW_VERSION_PROXY_EVENTS, - .removed = proxy_removed, - .destroy = proxy_destroy, -}; - -static void configure_device(pa_stream *s, struct global *g) -{ - const char *str; - uint32_t old = s->device_index; - - if (s->direction == PA_STREAM_RECORD) { - if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) { - s->device_index = g->node_info.monitor; - } - else - s->device_index = g->id; - } else { - s->device_index = g->id; - } - - free(s->device_name); - if ((str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) == NULL) - s->device_name = strdup("unknown"); - else - s->device_name = strdup(str); - - pw_log_debug("stream %p: linked to %d '%s'", s, s->device_index, s->device_name); - - if (old != SPA_ID_INVALID && old != s->device_index && - s->state == PA_STREAM_READY && s->moved_callback) - s->moved_callback(s, s->moved_userdata); -} - -static void update_link(pa_context *c, uint32_t src_node_id, uint32_t dst_node_id) -{ - struct global *s, *d; - - s = pa_context_find_global(c, src_node_id); - d = pa_context_find_global(c, dst_node_id); - - if (s == NULL || d == NULL) - return; - - if (s->stream && s->stream->direct_on_input == dst_node_id) { - pw_log_debug("node %d linked to stream %d %p (%d)", - src_node_id, dst_node_id, s->stream, s->stream->state); - } - else if (d->stream && d->stream->direct_on_input == src_node_id) { - pw_log_debug("node %d linked to stream %d %p (%d)", - dst_node_id, src_node_id, d->stream, d->stream->state); - } - else if ((s->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) && - (d->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT))) { - pw_log_debug("node %d linked to device %d", dst_node_id, src_node_id); - d->node_info.device_index = src_node_id; - if (d->stream) - configure_device(d->stream, s); - if (!d->init) - emit_event(c, d, PA_SUBSCRIPTION_EVENT_CHANGE); - } else if ((s->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT)) && - (d->mask & (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE))) { - pw_log_debug("node %d linked to device %d", src_node_id, dst_node_id); - s->node_info.device_index = dst_node_id; - if (s->stream) - configure_device(s->stream, d); - if (!s->init) - emit_event(c, s, PA_SUBSCRIPTION_EVENT_CHANGE); - } -} - -static int set_mask(pa_context *c, struct global *g) -{ - const char *str; - struct global_info *ginfo = NULL; - - if (strcmp(g->type, PW_TYPE_INTERFACE_Device) == 0) { - if (g->props == NULL) - return 0; - if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL) - return 0; - if (strcmp(str, "Audio/Device") != 0) - return 0; - - pw_log_debug("found card %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_CARD; - g->event = PA_SUBSCRIPTION_EVENT_CARD; - ginfo = &device_info; - spa_list_init(&g->card_info.profiles); - spa_list_init(&g->card_info.ports); - spa_list_init(&g->card_info.routes); - } else if (strcmp(g->type, PW_TYPE_INTERFACE_Node) == 0) { - if (g->props == NULL) - return 0; - - if ((str = pw_properties_get(g->props, PW_KEY_PRIORITY_DRIVER)) != NULL) - g->priority_driver = pw_properties_parse_int(str); - - if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL) { - pw_log_debug("node %d without "PW_KEY_MEDIA_CLASS, g->id); - return 0; - } - - if (strcmp(str, "Audio/Sink") == 0) { - pw_log_debug("found sink %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE; - g->event = PA_SUBSCRIPTION_EVENT_SINK; - g->node_info.monitor = g->id | PA_IDX_FLAG_MONITOR; - } - else if (strcmp(str, "Audio/Source") == 0) { - pw_log_debug("found source %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_SOURCE; - g->event = PA_SUBSCRIPTION_EVENT_SOURCE; - } - else if (strcmp(str, "Stream/Output/Audio") == 0) { - pw_log_debug("found sink input %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT; - g->event = PA_SUBSCRIPTION_EVENT_SINK_INPUT; - } - else if (strcmp(str, "Stream/Input/Audio") == 0) { - pw_log_debug("found source output %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT; - g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT; - } - g->stream = pa_context_find_stream(c, g->id); - if (g->stream) { - pw_log_debug("global stream %p", g->stream); - g->stream->global = g; - } - - if ((str = pw_properties_get(g->props, PW_KEY_CLIENT_ID)) != NULL) - g->node_info.client_id = atoi(str); - else - g->node_info.client_id = SPA_ID_INVALID; - - if ((str = pw_properties_get(g->props, PW_KEY_DEVICE_ID)) != NULL) - g->node_info.device_id = atoi(str); - else - g->node_info.device_id = SPA_ID_INVALID; - - ginfo = &node_info; - g->node_info.device_index = SPA_ID_INVALID; - g->node_info.sample_spec.format = PA_SAMPLE_S16NE; - g->node_info.sample_spec.rate = 44100; - g->node_info.volume = 1.0f; - g->node_info.mute = false; - g->node_info.base_volume = 1.0f; - g->node_info.volume_step = 1.0f / (PA_VOLUME_NORM+1); - g->node_info.active_port = SPA_ID_INVALID; - g->node_info.available_port = SPA_PARAM_AVAILABILITY_unknown; - pw_array_init(&g->node_info.formats, sizeof(void*) * 4); - } else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) { - if (g->props == NULL) - return 0; - - if ((str = pw_properties_get(g->props, PW_KEY_NODE_ID)) == NULL) { - pw_log_warn("port %d without "PW_KEY_NODE_ID, g->id); - return 0; - } - g->port_info.node_id = atoi(str); - pw_log_debug("found port %d node %d", g->id, g->port_info.node_id); - } else if (strcmp(g->type, PW_TYPE_INTERFACE_Module) == 0) { - pw_log_debug("found module %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_MODULE; - g->event = PA_SUBSCRIPTION_EVENT_MODULE; - ginfo = &module_info; - } else if (strcmp(g->type, PW_TYPE_INTERFACE_Client) == 0) { - pw_log_debug("found client %d", g->id); - g->mask = PA_SUBSCRIPTION_MASK_CLIENT; - g->event = PA_SUBSCRIPTION_EVENT_CLIENT; - ginfo = &client_info; - } else if (strcmp(g->type, PW_TYPE_INTERFACE_Link) == 0) { - uint32_t src_node_id, dst_node_id; - - if ((str = pw_properties_get(g->props, PW_KEY_LINK_OUTPUT_PORT)) == NULL) - return 0; - g->link_info.src = pa_context_find_global(c, pw_properties_parse_int(str)); - if ((str = pw_properties_get(g->props, PW_KEY_LINK_INPUT_PORT)) == NULL) - return 0; - g->link_info.dst = pa_context_find_global(c, pw_properties_parse_int(str)); - - if (g->link_info.src == NULL || g->link_info.dst == NULL) - return 0; - - src_node_id = g->link_info.src->port_info.node_id; - dst_node_id = g->link_info.dst->port_info.node_id; - - pw_log_debug("link %d:%d->%d:%d", - src_node_id, g->link_info.src->id, - dst_node_id, g->link_info.dst->id); - - update_link(c, src_node_id, dst_node_id); - } else if (strcmp(g->type, PW_TYPE_INTERFACE_Metadata) == 0) { - if (c->metadata == NULL) { - ginfo = &metadata_info; - c->metadata = g; - g->mask = PA_SUBSCRIPTION_MASK_SERVER; - g->event = PA_SUBSCRIPTION_EVENT_SERVER; - } - } else { - return 0; - } - - pw_log_debug("global %p: id:%u mask %d/%d", g, g->id, g->mask, g->event); - - if (ginfo) { - pw_log_debug("bind %d", g->id); - - g->proxy = pw_registry_bind(c->registry, g->id, g->type, - ginfo->version, 0); - if (g->proxy == NULL) - return -ENOMEM; - - pw_proxy_add_object_listener(g->proxy, &g->object_listener, ginfo->events, g); - pw_proxy_add_listener(g->proxy, &g->proxy_listener, &proxy_events, g); - g->ginfo = ginfo; - global_sync(g); - } else { - emit_event(c, g, PA_SUBSCRIPTION_EVENT_NEW); - } - - return 1; -} - -static inline void insert_global(pa_context *c, struct global *global) -{ - struct global *g; - bool found = false; - - spa_list_for_each(g, &c->globals, link) { - if (g->priority_driver < global->priority_driver) { - g = spa_list_prev(g, link); - found = true; - break; - } - } - if (!found) - spa_list_append(&g->link, &global->link); - else - spa_list_prepend(&g->link, &global->link); -} - -static void registry_event_global(void *data, uint32_t id, - uint32_t permissions, const char *type, uint32_t version, - const struct spa_dict *props) -{ - pa_context *c = data; - struct global *g; - int res; - - g = calloc(1, sizeof(struct global)); - pw_log_debug("context %p: global %d %s %p", c, id, type, g); - g->context = c; - g->id = id; - g->permissions = permissions; - g->type = strdup(type); - g->init = true; - g->props = props ? pw_properties_new_dict(props) : NULL; - - res = set_mask(c, g); - insert_global(c, g); - - if (res != 1) - global_free(c, g); -} - -static void registry_event_global_remove(void *object, uint32_t id) -{ - pa_context *c = object; - struct global *g; - - pw_log_debug("context %p: remove %d", c, id); - if ((g = pa_context_find_global(c, id)) == NULL) - return; - - emit_event(c, g, PA_SUBSCRIPTION_EVENT_REMOVE); - - pw_log_debug("context %p: free %d %p", c, id, g); - global_free(c, g); -} - -static const struct pw_registry_events registry_events = -{ - PW_VERSION_REGISTRY_EVENTS, - .global = registry_event_global, - .global_remove = registry_event_global_remove, -}; - -static void core_info(void *data, const struct pw_core_info *info) -{ - pa_context *c = data; - bool first = c->core_info == NULL; - - pw_log_debug("context %p: info", c); - - if (first) { - pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); - pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); - } - - c->core_info = pw_core_info_update(c->core_info, info); -} - -static void core_error(void *data, uint32_t id, int seq, int res, const char *message) -{ - pa_context *c = data; - - pw_log_error("context %p: error id:%u seq:%d res:%d (%s): %s", c, - id, seq, res, spa_strerror(res), message); - - if (id == PW_ID_CORE) { - if (res == -EPIPE && !c->disconnect) - pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); - } -} - -static void core_done(void *data, uint32_t id, int seq) -{ - pa_context *c = data; - pa_operation *o, *t; - struct global *g; - struct spa_list ops; - - pw_log_debug("done id:%u seq:%d/%d", id, seq, c->pending_seq); - if (c->pending_seq != seq) - return; - - spa_list_for_each(g, &c->globals, link) { - if (g->sync) { - do_global_sync(g); - g->sync = false; - } - } - if (c->pending_seq != seq) - return; - - spa_list_init(&ops); - spa_list_consume(o, &c->operations, link) { - spa_list_remove(&o->link); - spa_list_append(&ops, &o->link); - } - spa_list_for_each_safe(o, t, &ops, link) { - if (!o->sync) - continue; - pa_operation_ref(o); - pw_log_debug("sync operation %p complete", o); - if (o->callback) - o->callback(o, o->userdata); - pa_operation_unref(o); - } - spa_list_consume(o, &ops, link) { - if (!o->sync) { - spa_list_remove(&o->link); - spa_list_append(&c->operations, &o->link); - continue; - } - pw_log_warn("operation %p canceled", o); - pa_operation_cancel(o); - } -} - -static const struct pw_core_events core_events = { - PW_VERSION_CORE_EVENTS, - .info = core_info, - .done = core_done, - .error = core_error -}; - -struct success_data { - pa_context_success_cb_t cb; - void *userdata; - int error; -}; - -static void on_success(pa_operation *o, void *userdata) -{ - struct success_data *d = userdata; - pa_context *c = o->context; - pw_log_debug("context %p: operation:%p error %d", c, o, d->error); - if (d->error != 0) - pa_context_set_error(c, d->error); - if (d->cb) - d->cb(c, d->error ? 0 : 1, d->userdata); - pa_operation_done(o); -} - -struct subscribe_data { - struct success_data success; - pa_subscription_mask_t mask; -}; - -static void on_subscribe(pa_operation *o, void *userdata) -{ - struct subscribe_data *d = userdata; - pa_context *c = o->context; - c->subscribe_mask = d->mask; - on_success(o, &d->success); -} - -SPA_EXPORT -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct subscribe_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: subscribe %08x", c, m); - - o = pa_operation_new(c, NULL, on_subscribe, sizeof(struct subscribe_data)); - d = o->userdata; - d->success.cb = cb; - d->success.userdata = userdata; - d->mask = m; - pa_operation_sync(o); - - return o; -} - -static void io_event_cb(pa_mainloop_api*ea, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) -{ - int res; - pa_context *c = userdata; - if (events & PA_IO_EVENT_INPUT) { - pw_log_debug("%p: iterate loop %p", c, c->loop); - pw_loop_enter(c->loop); - do { - res = pw_loop_iterate(c->loop, 0); - } while (res == -EINTR); - pw_loop_leave(c->loop); - } -} - -SPA_EXPORT -pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, PA_CONST pa_proplist *p) -{ - struct pw_context *context; - struct pw_loop *loop; - struct pw_properties *props; - bool fallback_loop = false; - pa_context *c; - - pa_assert(mainloop); - - props = pw_properties_new(NULL, NULL); - if (name) - pw_properties_set(props, PA_PROP_APPLICATION_NAME, name); - pw_properties_set(props, PW_KEY_CLIENT_API, "pulseaudio"); - if (p) - pw_properties_update_proplist(props, p); - - if (pa_mainloop_api_is_our_api(mainloop)) - loop = mainloop->userdata; - else { - loop = pw_loop_new(NULL); - fallback_loop = true; - } - - pw_log_debug("mainloop:%p loop:%p", mainloop, loop); - - context = pw_context_new(loop, - pw_properties_new( - PW_KEY_CONTEXT_PROFILE_MODULES, "default", - NULL), - sizeof(struct pa_context)); - if (context == NULL) - return NULL; - - c = pw_context_get_user_data(context); - c->props = props; - c->fallback_loop = fallback_loop; - c->loop = loop; - c->context = context; - c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); - c->refcount = 1; - c->client_index = PA_INVALID_INDEX; - c->default_sink = SPA_ID_INVALID; - c->default_source = SPA_ID_INVALID; - c->mainloop = mainloop; - c->error = 0; - c->state = PA_CONTEXT_UNCONNECTED; - - if (c->fallback_loop) { - c->io = c->mainloop->io_new(c->mainloop, - pw_loop_get_fd(c->loop), - PA_IO_EVENT_INPUT, - io_event_cb, c); - } - - if (name) - pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name); - - spa_list_init(&c->globals); - - spa_list_init(&c->streams); - spa_list_init(&c->operations); - spa_list_init(&c->modules); - - return c; -} - -static void context_free(pa_context *c) -{ - struct pw_loop *loop; - pw_log_debug("context %p: free", c); - - context_unlink(c); - - pw_properties_free(c->props); - if (c->proplist) - pa_proplist_free(c->proplist); - if (c->core_info) - pw_core_info_free(c->core_info); - - if (c->io) - c->mainloop->io_free(c->io); - loop = c->fallback_loop ? c->loop : NULL; - - pw_context_destroy(c->context); - - if (loop) - pw_loop_destroy(loop); -} - -SPA_EXPORT -void pa_context_unref(pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - if (--c->refcount == 0) - context_free(c); -} - -SPA_EXPORT -pa_context* pa_context_ref(pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - c->refcount++; - return c; -} - -SPA_EXPORT -void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED) - return; - - c->state_callback = cb; - c->state_userdata = userdata; -} - -SPA_EXPORT -void pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED) - return; - - c->event_callback = cb; - c->event_userdata = userdata; -} - -SPA_EXPORT -int pa_context_errno(PA_CONST pa_context *c) -{ - if (!c) - return PA_ERR_INVALID; - - pa_assert(c->refcount >= 1); - - return c->error; -} - -SPA_EXPORT -int pa_context_is_pending(PA_CONST pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE); - - return !spa_list_is_empty(&c->operations); -} - -SPA_EXPORT -pa_context_state_t pa_context_get_state(PA_CONST pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - return c->state; -} - -static void on_connected(pa_operation *o, void *userdata) -{ - pa_context *c = o->context; - pw_log_debug("context %p: connected", c); - pa_context_set_state(c, PA_CONTEXT_READY); - pa_operation_done(o); -} - -SPA_EXPORT -int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) -{ - int res = 0; - pa_operation *o; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID); - PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); - - pa_context_ref(c); - - c->no_fail = !!(flags & PA_CONTEXT_NOFAIL); - - pa_context_set_state(c, PA_CONTEXT_CONNECTING); - - if (server) - pw_properties_set(c->props, PW_KEY_REMOTE_NAME, server); - - c->core = pw_context_connect(c->context, pw_properties_copy(c->props), 0); - if (c->core == NULL) { - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - res = -1; - goto exit; - } - pw_core_add_listener(c->core, &c->core_listener, &core_events, c); - - c->registry = pw_core_get_registry(c->core, - PW_VERSION_REGISTRY, 0); - pw_registry_add_listener(c->registry, - &c->registry_listener, - ®istry_events, c); - - o = pa_operation_new(c, NULL, on_connected, sizeof(struct success_data)); - pa_operation_sync(o); - pa_operation_unref(o); - -exit: - pa_context_unref(c); - - return res; -} - -SPA_EXPORT -void pa_context_disconnect(pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - pw_log_debug("%p", c); - - c->disconnect = true; - if (c->registry) { - spa_hook_remove(&c->registry_listener), - pw_proxy_destroy((struct pw_proxy*)c->registry); - c->registry = NULL; - } - if (c->core) { - spa_hook_remove(&c->core_listener), - pw_core_disconnect(c->core); - c->core = NULL; - } - if (PA_CONTEXT_IS_GOOD(c->state)) - pa_context_set_state(c, PA_CONTEXT_TERMINATED); -} - -struct notify_data { - pa_context_notify_cb_t cb; - void *userdata; -}; - -static void on_notify(pa_operation *o, void *userdata) -{ - struct notify_data *d = userdata; - pa_context *c = o->context; - - pw_log_debug("%p", c); - - if (d->cb) - d->cb(c, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) -{ - pa_operation *o; - struct notify_data *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_notify, sizeof(struct notify_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_data *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_data)); - d = o->userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - pw_log_warn("Not Implemented"); - - return o; -} - -struct default_node { - uint32_t mask; - pa_context_success_cb_t cb; - void *userdata; - char *name; - const char *key; -}; - -static void do_default_node(pa_operation *o, void *userdata) -{ - struct default_node *d = userdata; - pa_context *c = o->context; - struct global *g; - int error = 0; - - pw_log_debug("%p mask:%d name:%s", c, d->mask, d->name); - - g = pa_context_find_global_by_name(c, d->mask, d->name); - if (g == NULL) { - error = PA_ERR_NOENTITY; - } else if (!SPA_FLAG_IS_SET(g->permissions, PW_PERM_M) || - (c->metadata && !SPA_FLAG_IS_SET(c->metadata->permissions, PW_PERM_W|PW_PERM_X))) { - error = PA_ERR_ACCESS; - } else if (c->metadata) { - char buf[16]; - snprintf(buf, sizeof(buf), "%d", g->id); - pw_metadata_set_property(c->metadata->proxy, - PW_ID_CORE, d->key, SPA_TYPE_INFO_BASE"Id", buf); - } else { - error = PA_ERR_NOTIMPLEMENTED; - } - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error != 0 ? 0 : 1, d->userdata); - pa_xfree(d->name); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct default_node *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, do_default_node, sizeof(*d)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->name = pa_xstrdup(name); - d->key = METADATA_DEFAULT_SINK; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct default_node *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, do_default_node, sizeof(*d)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->name = pa_xstrdup(name); - d->key = METADATA_DEFAULT_SOURCE; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -int pa_context_is_local(PA_CONST pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1); - - return 1; -} - -SPA_EXPORT -pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) -{ - struct spa_dict dict; - struct spa_dict_item items[1]; - pa_operation *o; - struct success_data *d; - int changed; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - items[0] = SPA_DICT_ITEM_INIT(PA_PROP_APPLICATION_NAME, name); - dict = SPA_DICT_INIT(items, 1); - changed = pw_properties_update(c->props, &dict); - - if (changed) { - struct pw_client *client; - - client = pw_core_get_client(c->core); - pw_client_update_properties(client, &c->props->dict); - } - - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -const char* pa_context_get_server(PA_CONST pa_context *c) -{ - const struct pw_core_info *info; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - info = c->core_info; - PA_CHECK_VALIDITY_RETURN_NULL(c, info && info->name, PA_ERR_NOENTITY); - - return info->name; -} - -SPA_EXPORT -uint32_t pa_context_get_protocol_version(PA_CONST pa_context *c) -{ - return PA_PROTOCOL_VERSION; -} - -SPA_EXPORT -uint32_t pa_context_get_server_protocol_version(PA_CONST pa_context *c) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX); - - return PA_PROTOCOL_VERSION; -} - -SPA_EXPORT -pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, PA_CONST pa_proplist *p, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_data *d; - - spa_assert(c); - spa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || - mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pa_proplist_update(c->proplist, mode, p); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_EXPORT -pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_data *d; - - spa_assert(c); - spa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_warn("Not Implemented"); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_EXPORT -uint32_t pa_context_get_index(PA_CONST pa_context *c) -{ - struct pw_client *client; - - pa_assert(c); - spa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); - client = pw_core_get_client(c->core); - if (client == NULL) - return PA_INVALID_INDEX; - - return pw_proxy_get_bound_id((struct pw_proxy*)client); -} - -SPA_EXPORT -pa_time_event* pa_context_rttime_new(PA_CONST pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) -{ - struct timeval tv; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(c->mainloop); - - if (usec == PA_USEC_INVALID) - return c->mainloop->time_new(c->mainloop, NULL, cb, userdata); - - pa_timeval_rtstore(&tv, usec, !c->fallback_loop); - - return c->mainloop->time_new(c->mainloop, &tv, cb, userdata); -} - -SPA_EXPORT -void pa_context_rttime_restart(PA_CONST pa_context *c, pa_time_event *e, pa_usec_t usec) -{ - struct timeval tv; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(c->mainloop); - - if (usec == PA_USEC_INVALID) - c->mainloop->time_restart(e, NULL); - else { - pa_timeval_rtstore(&tv, usec, !c->fallback_loop); - c->mainloop->time_restart(e, &tv); - } -} - -SPA_EXPORT -size_t pa_context_get_tile_size(PA_CONST pa_context *c, const pa_sample_spec *ss) -{ - size_t fs, mbs; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(c, !ss || pa_sample_spec_valid(ss), PA_ERR_INVALID, (size_t) -1); - - fs = ss ? pa_frame_size(ss) : 1; - mbs = PA_ROUND_DOWN(4096, fs); - return PA_MAX(mbs, fs); -} - -SPA_EXPORT -int pa_context_load_cookie_from_file(pa_context *c, const char *cookie_file_path) -{ - return 0; -} diff --git a/pipewire-pulseaudio/src/core-format.c b/pipewire-pulseaudio/src/core-format.c deleted file mode 100644 index 4977a242d..000000000 --- a/pipewire-pulseaudio/src/core-format.c +++ /dev/null @@ -1,248 +0,0 @@ -/*** - This file is part of PulseAudio. - - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "core-format.h" - -#include -#include - -#include "internal.h" - -SPA_EXPORT -int pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf) { - int r; - char *sf_str; - pa_sample_format_t sf_local; - - pa_assert(f); - pa_assert(sf); - - r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf_str); - if (r < 0) - return r; - - sf_local = pa_parse_sample_format(sf_str); - pa_xfree(sf_str); - - if (!pa_sample_format_valid(sf_local)) { - pa_log_debug("Invalid sample format."); - return -PA_ERR_INVALID; - } - - *sf = sf_local; - - return 0; -} - -SPA_EXPORT -int pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate) { - int r; - int rate_local; - - pa_assert(f); - pa_assert(rate); - - r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate_local); - if (r < 0) - return r; - - if (!pa_sample_rate_valid(rate_local)) { - pa_log_debug("Invalid sample rate: %i", rate_local); - return -PA_ERR_INVALID; - } - - *rate = rate_local; - - return 0; -} - -SPA_EXPORT -int pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels) { - int r; - int channels_local; - - pa_assert(f); - pa_assert(channels); - - r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels_local); - if (r < 0) - return r; - - if (!pa_channels_valid(channels_local)) { - pa_log_debug("Invalid channel count: %i", channels_local); - return -PA_ERR_INVALID; - } - - *channels = channels_local; - - return 0; -} - -SPA_EXPORT -int pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map) { - int r; - char *map_str; - - pa_assert(f); - pa_assert(map); - - r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &map_str); - if (r < 0) - return r; - - map = pa_channel_map_parse(map, map_str); - pa_xfree(map_str); - - if (!map) { - pa_log_debug("Failed to parse channel map."); - return -PA_ERR_INVALID; - } - - return 0; -} - -SPA_EXPORT -pa_format_info *pa_format_info_from_sample_spec2(const pa_sample_spec *ss, const pa_channel_map *map, bool set_format, - bool set_rate, bool set_channels) { - pa_format_info *format = NULL; - - pa_assert(ss); - - format = pa_format_info_new(); - format->encoding = PA_ENCODING_PCM; - - if (set_format) - pa_format_info_set_sample_format(format, ss->format); - - if (set_rate) - pa_format_info_set_rate(format, ss->rate); - - if (set_channels) { - pa_format_info_set_channels(format, ss->channels); - - if (map) { - if (map->channels != ss->channels) { - pa_log_debug("Channel map is incompatible with the sample spec."); - goto fail; - } - - pa_format_info_set_channel_map(format, map); - } - } - - return format; - -fail: - if (format) - pa_format_info_free(format); - - return NULL; -} - -SPA_EXPORT -int pa_format_info_to_sample_spec2(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, - const pa_sample_spec *fallback_ss, const pa_channel_map *fallback_map) { - int r, r2; - pa_sample_spec ss_local; - pa_channel_map map_local; - - pa_assert(f); - pa_assert(ss); - pa_assert(map); - pa_assert(fallback_ss); - pa_assert(fallback_map); - - if (!pa_format_info_is_pcm(f)) - return pa_format_info_to_sample_spec_fake(f, ss, map); - - r = pa_format_info_get_sample_format(f, &ss_local.format); - if (r == -PA_ERR_NOENTITY) - ss_local.format = fallback_ss->format; - else if (r < 0) - return r; - - pa_assert(pa_sample_format_valid(ss_local.format)); - - r = pa_format_info_get_rate(f, &ss_local.rate); - if (r == -PA_ERR_NOENTITY) - ss_local.rate = fallback_ss->rate; - else if (r < 0) - return r; - - pa_assert(pa_sample_rate_valid(ss_local.rate)); - - r = pa_format_info_get_channels(f, &ss_local.channels); - r2 = pa_format_info_get_channel_map(f, &map_local); - if (r == -PA_ERR_NOENTITY && r2 >= 0) - ss_local.channels = map_local.channels; - else if (r == -PA_ERR_NOENTITY) - ss_local.channels = fallback_ss->channels; - else if (r < 0) - return r; - - pa_assert(pa_channels_valid(ss_local.channels)); - - if (r2 >= 0 && map_local.channels != ss_local.channels) { - pa_log_debug("Channel map is not compatible with the sample spec."); - return -PA_ERR_INVALID; - } - - if (r2 == -PA_ERR_NOENTITY) { - if (fallback_map->channels == ss_local.channels) - map_local = *fallback_map; - else - pa_channel_map_init_extend(&map_local, ss_local.channels, PA_CHANNEL_MAP_DEFAULT); - } else if (r2 < 0) - return r2; - - pa_assert(pa_channel_map_valid(&map_local)); - pa_assert(ss_local.channels == map_local.channels); - - *ss = ss_local; - *map = map_local; - - return 0; -} - -SPA_EXPORT -int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { - int rate; - - pa_assert(f); - pa_assert(ss); - - /* Note: When we add support for non-IEC61937 encapsulated compressed - * formats, this function should return a non-zero values for these. */ - - ss->format = PA_SAMPLE_S16LE; - ss->channels = 2; - - if (map) - pa_channel_map_init_stereo(map); - - pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate) == 0, -PA_ERR_INVALID); - ss->rate = (uint32_t) rate; - - if (f->encoding == PA_ENCODING_EAC3_IEC61937) - ss->rate *= 4; - - return 0; -} diff --git a/pipewire-pulseaudio/src/core-format.h b/pipewire-pulseaudio/src/core-format.h deleted file mode 100644 index 37503041b..000000000 --- a/pipewire-pulseaudio/src/core-format.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef foocoreformathfoo -#define foocoreformathfoo - -/*** - This file is part of PulseAudio. - - 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, see . -***/ - -#include - -#include - -/* Gets the sample format stored in the format info. Returns a negative error - * code on failure. If the sample format property is not set at all, returns - * -PA_ERR_NOENTITY. */ -int pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf); - -/* Gets the sample rate stored in the format info. Returns a negative error - * code on failure. If the sample rate property is not set at all, returns - * -PA_ERR_NOENTITY. */ -int pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate); - -/* Gets the channel count stored in the format info. Returns a negative error - * code on failure. If the channels property is not set at all, returns - * -PA_ERR_NOENTITY. */ -int pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels); - -/* Gets the channel map stored in the format info. Returns a negative error - * code on failure. If the channel map property is not set at all, returns - * -PA_ERR_NOENTITY. */ -int pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map); - -/* Convert a sample spec and an optional channel map to a new PCM format info - * object (remember to free it). If map is NULL, then the channel map will be - * left unspecified. If some fields of the sample spec should be ignored, pass - * false for set_format, set_rate and set_channels as appropriate, then those - * fields will be left unspecified. This function returns NULL if the input is - * invalid (for example, setting the sample rate was requested, but the rate - * in ss is invalid). - * - * pa_format_info_from_sample_spec() exists too. This "version 2" was created, - * because the original function doesn't provide the possibility of ignoring - * some of the sample spec fields. That functionality can't be added to the - * original function, because the function is a part of the public API and - * adding parameters to it would break the API. */ -pa_format_info *pa_format_info_from_sample_spec2(const pa_sample_spec *ss, const pa_channel_map *map, bool set_format, - bool set_rate, bool set_channels); - -/* Convert the format info into a sample spec and a channel map. If the format - * info doesn't contain some information, the fallback sample spec and channel - * map are used to populate the output. - * - * pa_format_info_to_sample_spec() exists too. This "version 2" was created, - * because the original function doesn't provide the possibility of specifying - * a fallback sample spec and channel map. That functionality can't be added to - * the original function, because the function is part of the public API and - * adding parameters to it would break the API. */ -int pa_format_info_to_sample_spec2(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map, - const pa_sample_spec *fallback_ss, const pa_channel_map *fallback_map); - -/* For compressed formats. Converts the format info into a sample spec and a - * channel map that an ALSA device can use as its configuration parameters when - * playing back the compressed data. That is, the returned sample spec doesn't - * describe the audio content, but the device parameters. */ -int pa_format_info_to_sample_spec_fake(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map); - -#endif diff --git a/pipewire-pulseaudio/src/direction.c b/pipewire-pulseaudio/src/direction.c deleted file mode 100644 index d1dc6d722..000000000 --- a/pipewire-pulseaudio/src/direction.c +++ /dev/null @@ -1,50 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include -#include - -#define pa_init_i18n() -#define _(String) (String) - -SPA_EXPORT -int pa_direction_valid(pa_direction_t direction) -{ - if (direction != PA_DIRECTION_INPUT - && direction != PA_DIRECTION_OUTPUT - && direction != (PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT)) - return 0; - return 1; -} - -SPA_EXPORT -const char *pa_direction_to_string(pa_direction_t direction) { - pa_init_i18n(); - - if (direction == PA_DIRECTION_INPUT) - return _("input"); - if (direction == PA_DIRECTION_OUTPUT) - return _("output"); - if (direction == (PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT)) - return _("bidirectional"); - - return _("invalid"); -} diff --git a/pipewire-pulseaudio/src/error.c b/pipewire-pulseaudio/src/error.c deleted file mode 100644 index abf05b634..000000000 --- a/pipewire-pulseaudio/src/error.c +++ /dev/null @@ -1,75 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include -#include - -#include - -#include -#include - -#define N_(String) (String) -#define _(String) (String) -#define pa_init_i18n() - -SPA_EXPORT -const char*pa_strerror(int error) -{ - static const char* const errortab[PA_ERR_MAX] = { - [PA_OK] = N_("OK"), - [PA_ERR_ACCESS] = N_("Access denied"), - [PA_ERR_COMMAND] = N_("Unknown command"), - [PA_ERR_INVALID] = N_("Invalid argument"), - [PA_ERR_EXIST] = N_("Entity exists"), - [PA_ERR_NOENTITY] = N_("No such entity"), - [PA_ERR_CONNECTIONREFUSED] = N_("Connection refused"), - [PA_ERR_PROTOCOL] = N_("Protocol error"), - [PA_ERR_TIMEOUT] = N_("Timeout"), - [PA_ERR_AUTHKEY] = N_("No authentication key"), - [PA_ERR_INTERNAL] = N_("Internal error"), - [PA_ERR_CONNECTIONTERMINATED] = N_("Connection terminated"), - [PA_ERR_KILLED] = N_("Entity killed"), - [PA_ERR_INVALIDSERVER] = N_("Invalid server"), - [PA_ERR_MODINITFAILED] = N_("Module initialization failed"), - [PA_ERR_BADSTATE] = N_("Bad state"), - [PA_ERR_NODATA] = N_("No data"), - [PA_ERR_VERSION] = N_("Incompatible protocol version"), - [PA_ERR_TOOLARGE] = N_("Too large"), - [PA_ERR_NOTSUPPORTED] = N_("Not supported"), - [PA_ERR_UNKNOWN] = N_("Unknown error code"), - [PA_ERR_NOEXTENSION] = N_("No such extension"), - [PA_ERR_OBSOLETE] = N_("Obsolete functionality"), - [PA_ERR_NOTIMPLEMENTED] = N_("Missing implementation"), - [PA_ERR_FORKED] = N_("Client forked"), - [PA_ERR_IO] = N_("Input/Output error"), - [PA_ERR_BUSY] = N_("Device or resource busy") - }; - - pa_init_i18n(); - - if (error < 0) - error = -error; - - if (error >= PA_ERR_MAX) - return NULL; - - return _(errortab[error]); -} - diff --git a/pipewire-pulseaudio/src/ext-device-manager.c b/pipewire-pulseaudio/src/ext-device-manager.c deleted file mode 100644 index 942d627af..000000000 --- a/pipewire-pulseaudio/src/ext-device-manager.c +++ /dev/null @@ -1,249 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include - -#include "internal.h" - -struct ext_data { - pa_context *context; - pa_ext_device_manager_test_cb_t test_cb; - pa_ext_device_manager_read_cb_t read_cb; - pa_context_success_cb_t success_cb; - int error; - void *userdata; -}; - -static void device_test(pa_operation *o, void *userdata) -{ - struct ext_data *d = userdata; - if (d->test_cb) - d->test_cb(o->context, PA_INVALID_INDEX, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation *pa_ext_device_manager_test( - pa_context *c, - pa_ext_device_manager_test_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, device_test, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->test_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -static void device_read(pa_operation *o, void *userdata) -{ - struct ext_data *d = userdata; - if (d->read_cb) - d->read_cb(o->context, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation *pa_ext_device_manager_read( - pa_context *c, - pa_ext_device_manager_read_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, device_read, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->read_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -static void on_success(pa_operation *o, void *userdata) -{ - struct ext_data *d = userdata; - if (d->success_cb) - d->success_cb(o->context, d->error, d->userdata); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation *pa_ext_device_manager_delete( - pa_context *c, - const char *const s[], - pa_context_success_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation *pa_ext_device_manager_subscribe( - pa_context *c, - int enable, - pa_context_success_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - d->error = PA_ERR_NOTIMPLEMENTED; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -void pa_ext_device_manager_set_subscribe_cb( - pa_context *c, - pa_ext_device_manager_subscribe_cb_t cb, - void *userdata) -{ -} diff --git a/pipewire-pulseaudio/src/ext-device-restore.c b/pipewire-pulseaudio/src/ext-device-restore.c deleted file mode 100644 index e4b8989fb..000000000 --- a/pipewire-pulseaudio/src/ext-device-restore.c +++ /dev/null @@ -1,193 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include "internal.h" - -#define EXT_VERSION 1 - -struct ext_data { - pa_context *context; - pa_ext_device_restore_test_cb_t test_cb; - pa_ext_device_restore_read_device_formats_cb_t read_cb; - pa_context_success_cb_t success_cb; - void *userdata; -}; - -static void restore_test(pa_operation *o, void *userdata) -{ - struct ext_data *d = userdata; - if (d->test_cb) - d->test_cb(o->context, PA_INVALID_INDEX, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation *pa_ext_device_restore_test( - pa_context *c, - pa_ext_device_restore_test_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, restore_test, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->test_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void on_success(pa_operation *o, void *userdata) -{ - struct ext_data *d = userdata; - if (d->success_cb) - d->success_cb(o->context, PA_OK, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation *pa_ext_device_restore_subscribe( - pa_context *c, - int enable, - pa_context_success_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -void pa_ext_device_restore_set_subscribe_cb( - pa_context *c, - pa_ext_device_restore_subscribe_cb_t cb, - void *userdata) -{ -} - -static void read_formats(pa_operation *o, void *userdata) -{ - struct ext_data *d = userdata; - if (d->read_cb) - d->read_cb(o->context, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, read_formats, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->read_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, read_formats, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->read_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct ext_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct ext_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} diff --git a/pipewire-pulseaudio/src/ext-stream-restore.c b/pipewire-pulseaudio/src/ext-stream-restore.c deleted file mode 100644 index bc4001506..000000000 --- a/pipewire-pulseaudio/src/ext-stream-restore.c +++ /dev/null @@ -1,198 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include "internal.h" - -struct stream_data { - pa_context *context; - pa_ext_stream_restore_test_cb_t test_cb; - pa_ext_stream_restore_read_cb_t read_cb; - pa_context_success_cb_t success_cb; - void *userdata; -}; - -static void restore_test(pa_operation *o, void *userdata) -{ - struct stream_data *d = userdata; - - if (d->test_cb) - d->test_cb(o->context, PA_INVALID_INDEX, d->userdata); - - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation *pa_ext_stream_restore_test( - pa_context *c, - pa_ext_stream_restore_test_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct stream_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, restore_test, sizeof(struct stream_data)); - d = o->userdata; - d->context = c; - d->test_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void restore_read(pa_operation *o, void *userdata) -{ - struct stream_data *d = userdata; - - if (d->read_cb) - d->read_cb(o->context, NULL, 1, d->userdata); - - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation *pa_ext_stream_restore_read( - pa_context *c, - pa_ext_stream_restore_read_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct stream_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, restore_read, sizeof(struct stream_data)); - d = o->userdata; - d->context = c; - d->read_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void on_success(pa_operation *o, void *userdata) -{ - struct stream_data *d = userdata; - if (d->success_cb) - d->success_cb(o->context, PA_OK, d->userdata); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct stream_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct stream_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -/** Delete entries from the stream database. \since 0.9.12 */ -SPA_EXPORT -pa_operation *pa_ext_stream_restore_delete( - pa_context *c, - const char *const s[], - pa_context_success_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct stream_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct stream_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -/** Subscribe to changes in the stream database. \since 0.9.12 */ -SPA_EXPORT -pa_operation *pa_ext_stream_restore_subscribe( - pa_context *c, - int enable, - pa_context_success_cb_t cb, - void *userdata) -{ - pa_operation *o; - struct stream_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct stream_data)); - d = o->userdata; - d->context = c; - d->success_cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -/** Set the subscription callback that is called when - * pa_ext_stream_restore_subscribe() was called. \since 0.9.12 */ -SPA_EXPORT -void pa_ext_stream_restore_set_subscribe_cb( - pa_context *c, - pa_ext_stream_restore_subscribe_cb_t cb, - void *userdata) -{ -} diff --git a/pipewire-pulseaudio/src/format.c b/pipewire-pulseaudio/src/format.c deleted file mode 100644 index 1575a4e39..000000000 --- a/pipewire-pulseaudio/src/format.c +++ /dev/null @@ -1,915 +0,0 @@ -/*** - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "core-format.h" -#include "json.h" -#include "internal.h" -#include "strbuf.h" - -#define PA_JSON_MIN_KEY "min" -#define PA_JSON_MAX_KEY "max" - -static int pa_format_info_prop_compatible(const char *one, const char *two); - -static const uint32_t audio_formats[] = { - [PA_SAMPLE_U8] = SPA_AUDIO_FORMAT_U8, - [PA_SAMPLE_ALAW] = SPA_AUDIO_FORMAT_UNKNOWN, - [PA_SAMPLE_ULAW] = SPA_AUDIO_FORMAT_UNKNOWN, - [PA_SAMPLE_S16NE] = SPA_AUDIO_FORMAT_S16, - [PA_SAMPLE_S16RE] = SPA_AUDIO_FORMAT_S16_OE, - [PA_SAMPLE_FLOAT32NE] = SPA_AUDIO_FORMAT_F32, - [PA_SAMPLE_FLOAT32RE] = SPA_AUDIO_FORMAT_F32_OE, - [PA_SAMPLE_S32NE] = SPA_AUDIO_FORMAT_S32, - [PA_SAMPLE_S32RE] = SPA_AUDIO_FORMAT_S32_OE, - [PA_SAMPLE_S24NE] = SPA_AUDIO_FORMAT_S24, - [PA_SAMPLE_S24RE] = SPA_AUDIO_FORMAT_S24_OE, - [PA_SAMPLE_S24_32NE] = SPA_AUDIO_FORMAT_S24_32, - [PA_SAMPLE_S24_32RE] = SPA_AUDIO_FORMAT_S24_32_OE, -}; - -static inline uint32_t format_pa2id(pa_sample_format_t format) -{ - if (format < 0 || (size_t)format >= SPA_N_ELEMENTS(audio_formats)) - return SPA_AUDIO_FORMAT_UNKNOWN; - return audio_formats[format]; -} - -static inline pa_sample_format_t format_id2pa(uint32_t id) -{ - size_t i; - for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) { - if (id == audio_formats[i]) - return i; - } - return PA_SAMPLE_INVALID; -} - -static const char* const _encoding_str_table[]= { - [PA_ENCODING_PCM] = "pcm", - [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937", - [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937", - [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937", - [PA_ENCODING_DTS_IEC61937] = "dts-iec61937", - [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937", -#if PA_CHECK_VERSION(13, 0, 0) - [PA_ENCODING_TRUEHD_IEC61937] = "truehd-iec61937", - [PA_ENCODING_DTSHD_IEC61937] = "dtshd-iec61937", -#endif - [PA_ENCODING_ANY] = "any", -}; - -SPA_EXPORT -const char *pa_encoding_to_string(pa_encoding_t e) { - if (e < 0 || e >= PA_ENCODING_MAX) - return NULL; - - return _encoding_str_table[e]; -} - -SPA_EXPORT -pa_encoding_t pa_encoding_from_string(const char *encoding) { - pa_encoding_t e; - - for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++) - if (pa_streq(_encoding_str_table[e], encoding)) - return e; - - return PA_ENCODING_INVALID; -} - -SPA_EXPORT -pa_format_info* pa_format_info_new(void) { - pa_format_info *f = pa_xnew(pa_format_info, 1); - - f->encoding = PA_ENCODING_INVALID; - f->plist = pa_proplist_new(); - - return f; -} - -SPA_EXPORT -pa_format_info* pa_format_info_copy(const pa_format_info *src) { - pa_format_info *dest; - - pa_assert(src); - - dest = pa_xnew(pa_format_info, 1); - - dest->encoding = src->encoding; - - if (src->plist) - dest->plist = pa_proplist_copy(src->plist); - else - dest->plist = NULL; - - return dest; -} - -SPA_EXPORT -void pa_format_info_free(pa_format_info *f) { - pa_assert(f); - - pa_proplist_free(f->plist); - pa_xfree(f); -} - -SPA_EXPORT -int pa_format_info_valid(const pa_format_info *f) { - return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL); -} - -SPA_EXPORT -int pa_format_info_is_pcm(const pa_format_info *f) { - return f->encoding == PA_ENCODING_PCM; -} - -SPA_EXPORT -char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) { - char *tmp; - - pa_assert(s); - pa_assert(l > 0); - pa_assert(f); - - pa_init_i18n(); - - if (!pa_format_info_valid(f)) - pa_snprintf(s, l, _("(invalid)")); - else { - tmp = pa_proplist_to_string_sep(f->plist, " "); - if (tmp[0]) - pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp); - else - pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding)); - pa_xfree(tmp); - } - - return s; -} - -SPA_EXPORT -pa_format_info* pa_format_info_from_string(const char *str) { - pa_format_info *f = pa_format_info_new(); - char *encoding = NULL, *properties = NULL; - size_t pos; - - pos = strcspn(str, ","); - - encoding = pa_xstrndup(str, pos); - f->encoding = pa_encoding_from_string(pa_strip(encoding)); - if (f->encoding == PA_ENCODING_INVALID) - goto error; - - if (pos != strlen(str)) { - pa_proplist *plist; - - properties = pa_xstrdup(&str[pos+1]); - plist = pa_proplist_from_string(properties); - - if (!plist) - goto error; - - pa_proplist_free(f->plist); - f->plist = plist; - } - -out: - if (encoding) - pa_xfree(encoding); - if (properties) - pa_xfree(properties); - return f; - -error: - pa_format_info_free(f); - f = NULL; - goto out; -} - -SPA_EXPORT -int pa_format_info_is_compatible(const pa_format_info *first, const pa_format_info *second) { - const char *key; - void *state = NULL; - - pa_assert(first); - pa_assert(second); - - if (first->encoding != second->encoding) - return false; - - while ((key = pa_proplist_iterate(first->plist, &state))) { - const char *value_one, *value_two; - - value_one = pa_proplist_gets(first->plist, key); - value_two = pa_proplist_gets(second->plist, key); - - if (!value_two || !pa_format_info_prop_compatible(value_one, value_two)) - return false; - } - - return true; -} - -SPA_EXPORT -pa_format_info* pa_format_info_from_sample_spec(const pa_sample_spec *ss, const pa_channel_map *map) { - char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - pa_format_info *f; - - pa_assert(ss && pa_sample_spec_valid(ss)); - pa_assert(!map || pa_channel_map_valid(map)); - - f = pa_format_info_new(); - f->encoding = PA_ENCODING_PCM; - - pa_format_info_set_sample_format(f, ss->format); - pa_format_info_set_rate(f, ss->rate); - pa_format_info_set_channels(f, ss->channels); - - if (map) { - pa_channel_map_snprint(cm, sizeof(cm), map); - pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm); - } - - return f; -} - -/* For PCM streams */ -SPA_EXPORT -int pa_format_info_to_sample_spec(const pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { - pa_assert(f); - pa_assert(ss); - - if (!pa_format_info_is_pcm(f)) - return pa_format_info_to_sample_spec_fake(f, ss, map); - - if (pa_format_info_get_sample_format(f, &ss->format) < 0) - return -PA_ERR_INVALID; - if (pa_format_info_get_rate(f, &ss->rate) < 0) - return -PA_ERR_INVALID; - if (pa_format_info_get_channels(f, &ss->channels) < 0) - return -PA_ERR_INVALID; - if (map && pa_format_info_get_channel_map(f, map) < 0) - return -PA_ERR_INVALID; - - return 0; -} - -SPA_EXPORT -pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) { - const char *str; - pa_json_object *o; - const pa_json_object *o1; - pa_prop_type_t type; - - pa_assert(f); - pa_assert(key); - - str = pa_proplist_gets(f->plist, key); - if (!str) - return PA_PROP_TYPE_INVALID; - - o = pa_json_parse(str); - if (!o) - return PA_PROP_TYPE_INVALID; - - switch (pa_json_object_get_type(o)) { - case PA_JSON_TYPE_INT: - type = PA_PROP_TYPE_INT; - break; - - case PA_JSON_TYPE_STRING: - type = PA_PROP_TYPE_STRING; - break; - - case PA_JSON_TYPE_ARRAY: - if (pa_json_object_get_array_length(o) == 0) { - /* Unlikely, but let's account for this anyway. We need at - * least one element to figure out the array type. */ - type = PA_PROP_TYPE_INVALID; - break; - } - - o1 = pa_json_object_get_array_member(o, 0); - - if (pa_json_object_get_type(o1) == PA_JSON_TYPE_INT) - type = PA_PROP_TYPE_INT_ARRAY; - else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_STRING) - type = PA_PROP_TYPE_STRING_ARRAY; - else - type = PA_PROP_TYPE_INVALID; - - break; - - case PA_JSON_TYPE_OBJECT: - /* We actually know at this point that it's a int range, but let's - * confirm. */ - if (!pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) { - type = PA_PROP_TYPE_INVALID; - break; - } - - if (!pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) { - type = PA_PROP_TYPE_INVALID; - break; - } - - type = PA_PROP_TYPE_INT_RANGE; - break; - - default: - type = PA_PROP_TYPE_INVALID; - break; - } - - pa_json_object_free(o); - return type; -} - -SPA_EXPORT -int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) { - const char *str; - pa_json_object *o; - - pa_assert(f); - pa_assert(key); - pa_assert(v); - - str = pa_proplist_gets(f->plist, key); - if (!str) - return -PA_ERR_NOENTITY; - - o = pa_json_parse(str); - if (!o) { - pa_log_debug("Failed to parse format info property '%s'.", key); - return -PA_ERR_INVALID; - } - - if (pa_json_object_get_type(o) != PA_JSON_TYPE_INT) { - pa_log_debug("Format info property '%s' type is not int.", key); - pa_json_object_free(o); - return -PA_ERR_INVALID; - } - - *v = pa_json_object_get_int(o); - pa_json_object_free(o); - - return 0; -} - -SPA_EXPORT -int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) { - const char *str; - pa_json_object *o; - const pa_json_object *o1; - int ret = -PA_ERR_INVALID; - - pa_assert(f); - pa_assert(key); - pa_assert(min); - pa_assert(max); - - str = pa_proplist_gets(f->plist, key); - if (!str) - return -PA_ERR_NOENTITY; - - o = pa_json_parse(str); - if (!o) { - pa_log_debug("Failed to parse format info property '%s'.", key); - return -PA_ERR_INVALID; - } - - if (pa_json_object_get_type(o) != PA_JSON_TYPE_OBJECT) - goto out; - - if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) || - (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT)) - goto out; - - *min = pa_json_object_get_int(o1); - - if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) || - (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT)) - goto out; - - *max = pa_json_object_get_int(o1); - - ret = 0; - -out: - if (ret < 0) - pa_log_debug("Format info property '%s' is not a valid int range.", key); - - pa_json_object_free(o); - return ret; -} - -SPA_EXPORT -int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) { - const char *str; - pa_json_object *o; - const pa_json_object *o1; - int i, ret = -PA_ERR_INVALID; - - pa_assert(f); - pa_assert(key); - pa_assert(values); - pa_assert(n_values); - - str = pa_proplist_gets(f->plist, key); - if (!str) - return -PA_ERR_NOENTITY; - - o = pa_json_parse(str); - if (!o) { - pa_log_debug("Failed to parse format info property '%s'.", key); - return -PA_ERR_INVALID; - } - - if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY) - goto out; - - *n_values = pa_json_object_get_array_length(o); - *values = pa_xnew(int, *n_values); - - for (i = 0; i < *n_values; i++) { - o1 = pa_json_object_get_array_member(o, i); - - if (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT) { - goto out; - } - - (*values)[i] = pa_json_object_get_int(o1); - } - - ret = 0; - -out: - if (ret < 0) - pa_log_debug("Format info property '%s' is not a valid int array.", key); - - pa_json_object_free(o); - return ret; -} - -SPA_EXPORT -int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) { - const char *str = NULL; - pa_json_object *o; - - pa_assert(f); - pa_assert(key); - pa_assert(v); - - str = pa_proplist_gets(f->plist, key); - if (!str) - return -PA_ERR_NOENTITY; - - o = pa_json_parse(str); - if (!o) { - pa_log_debug("Failed to parse format info property '%s'.", key); - return -PA_ERR_INVALID; - } - - if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) { - pa_log_debug("Format info property '%s' type is not string.", key); - pa_json_object_free(o); - return -PA_ERR_INVALID; - } - - *v = pa_xstrdup(pa_json_object_get_string(o)); - pa_json_object_free(o); - - return 0; -} - -SPA_EXPORT -int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) { - const char *str; - pa_json_object *o; - const pa_json_object *o1; - int i, ret = -PA_ERR_INVALID; - - pa_assert(f); - pa_assert(key); - pa_assert(values); - pa_assert(n_values); - - str = pa_proplist_gets(f->plist, key); - if (!str) - return -PA_ERR_NOENTITY; - - o = pa_json_parse(str); - if (!o) { - pa_log_debug("Failed to parse format info property '%s'.", key); - return -PA_ERR_INVALID; - } - - if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY) - goto out; - - *n_values = pa_json_object_get_array_length(o); - *values = pa_xnew(char *, *n_values); - - for (i = 0; i < *n_values; i++) { - o1 = pa_json_object_get_array_member(o, i); - - if (pa_json_object_get_type(o1) != PA_JSON_TYPE_STRING) { - goto out; - } - - (*values)[i] = pa_xstrdup(pa_json_object_get_string(o1)); - } - - ret = 0; - -out: - if (ret < 0) - pa_log_debug("Format info property '%s' is not a valid string array.", key); - - pa_json_object_free(o); - return ret; -} - -SPA_EXPORT -void pa_format_info_free_string_array(char **values, int n_values) { - int i; - - for (i = 0; i < n_values; i++) - pa_xfree(values[i]); - - pa_xfree(values); -} - -SPA_EXPORT -void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) { - pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf)); -} - -SPA_EXPORT -void pa_format_info_set_rate(pa_format_info *f, int rate) { - pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate); -} - -SPA_EXPORT -void pa_format_info_set_channels(pa_format_info *f, int channels) { - pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels); -} - -SPA_EXPORT -void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) { - char map_str[PA_CHANNEL_MAP_SNPRINT_MAX]; - - pa_channel_map_snprint(map_str, sizeof(map_str), map); - - pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str); -} - -SPA_EXPORT -void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) { - pa_assert(f); - pa_assert(key); - - pa_proplist_setf(f->plist, key, "%d", value); -} - -SPA_EXPORT -void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) { - pa_strbuf *buf; - char *str; - int i; - - pa_assert(f); - pa_assert(key); - pa_assert(n_values > 0); - - buf = pa_strbuf_new(); - - pa_strbuf_printf(buf, "[ %d", values[0]); - - for (i = 1; i < n_values; i++) - pa_strbuf_printf(buf, ", %d", values[i]); - - pa_strbuf_printf(buf, " ]"); - str = pa_strbuf_to_string_free(buf); - - pa_proplist_sets(f->plist, key, str); - pa_xfree (str); -} - -SPA_EXPORT -void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) { - pa_assert(f); - pa_assert(key); - - pa_proplist_setf(f->plist, key, "{ \"" PA_JSON_MIN_KEY "\": %d, \"" PA_JSON_MAX_KEY "\": %d }", - min, max); -} - -SPA_EXPORT -void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) { - pa_assert(f); - pa_assert(key); - - pa_proplist_setf(f->plist, key, "\"%s\"", value); -} - -SPA_EXPORT -void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) { - pa_strbuf *buf; - char *str; - int i; - - pa_assert(f); - pa_assert(key); - - buf = pa_strbuf_new(); - - pa_strbuf_printf(buf, "[ \"%s\"", values[0]); - - for (i = 1; i < n_values; i++) - pa_strbuf_printf(buf, ", \"%s\"", values[i]); - - pa_strbuf_printf(buf, " ]"); - str = pa_strbuf_to_string_free(buf); - - pa_proplist_sets(f->plist, key, str); - pa_xfree (str); -} - -static bool pa_json_is_fixed_type(pa_json_object *o) { - switch(pa_json_object_get_type(o)) { - case PA_JSON_TYPE_OBJECT: - case PA_JSON_TYPE_ARRAY: - return false; - - default: - return true; - } -} - -static int pa_format_info_prop_compatible(const char *one, const char *two) { - pa_json_object *o1 = NULL, *o2 = NULL; - int i, ret = 0; - - o1 = pa_json_parse(one); - if (!o1) - goto out; - - o2 = pa_json_parse(two); - if (!o2) - goto out; - - /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */ - pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false); - - if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) { - ret = pa_json_object_equal(o1, o2); - goto out; - } - - if (pa_json_is_fixed_type(o1)) { - pa_json_object *tmp = o2; - o2 = o1; - o1 = tmp; - } - - /* o2 is now a fixed type, and o1 is not */ - - if (pa_json_object_get_type(o1) == PA_JSON_TYPE_ARRAY) { - for (i = 0; i < pa_json_object_get_array_length(o1); i++) { - if (pa_json_object_equal(pa_json_object_get_array_member(o1, i), o2)) { - ret = 1; - break; - } - } - } else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_OBJECT) { - /* o1 should be a range type */ - int min, max, v; - const pa_json_object *o_min = NULL, *o_max = NULL; - - if (pa_json_object_get_type(o2) != PA_JSON_TYPE_INT) { - /* We don't support non-integer ranges */ - goto out; - } - - if (!(o_min = pa_json_object_get_object_member(o1, PA_JSON_MIN_KEY)) || - pa_json_object_get_type(o_min) != PA_JSON_TYPE_INT) - goto out; - - if (!(o_max = pa_json_object_get_object_member(o1, PA_JSON_MAX_KEY)) || - pa_json_object_get_type(o_max) != PA_JSON_TYPE_INT) - goto out; - - v = pa_json_object_get_int(o2); - min = pa_json_object_get_int(o_min); - max = pa_json_object_get_int(o_max); - - ret = v >= min && v <= max; - } else { - pa_log_warn("Got a format type that we don't support"); - } - -out: - if (o1) - pa_json_object_free(o1); - if (o2) - pa_json_object_free(o2); - - return ret; -} - -static void format_info_fill_int(pa_format_info *f, const struct spa_pod *val, const char *key) -{ - const struct spa_pod *vals; - int *int_vals; - uint32_t *uvals, i, n_vals, choice; - vals = spa_pod_get_values(val, &n_vals, &choice); - uvals = SPA_POD_BODY(vals); - - int_vals = alloca(n_vals * sizeof(int)); - for (i = 0; i < n_vals; i++) - int_vals[i] = uvals[i]; - - if (n_vals == 1) - choice = SPA_CHOICE_None; - - switch (choice) { - case SPA_CHOICE_None: - if (n_vals > 0) - pa_format_info_set_prop_int(f, - key, int_vals[0]); - break; - - case SPA_CHOICE_Enum: - if (n_vals > 1) - pa_format_info_set_prop_int_array(f, - key, &int_vals[1], n_vals-1); - break; - - case SPA_CHOICE_Range: - if (n_vals > 2) - pa_format_info_set_prop_int_range(f, - key, int_vals[1], int_vals[2]); - break; - } -} - -static void format_info_fill_format(pa_format_info *f, const struct spa_pod *val, const char *key) -{ - const struct spa_pod *vals; - const char **svals; - uint32_t *uvals, i, j, n_vals, choice; - vals = spa_pod_get_values(val, &n_vals, &choice); - uvals = SPA_POD_BODY(vals); - - svals = alloca(n_vals * sizeof(char *)); - for (i = 0, j = 0; i < n_vals; i++) { - pa_sample_format_t fmt = format_id2pa(uvals[i]); - const char *s = pa_sample_format_to_string(fmt); - if (s) - svals[j++] = s; - } - n_vals = j; - if (n_vals == 1) - choice = SPA_CHOICE_None; - - switch (choice) { - case SPA_CHOICE_None: - if (n_vals > 0) - pa_format_info_set_prop_string(f, key, svals[0]); - break; - - case SPA_CHOICE_Enum: - if (n_vals > 1) - pa_format_info_set_prop_string_array(f, - key, &svals[1], n_vals-1); - break; - } -} - -pa_format_info* pa_format_info_from_param(const struct spa_pod *param) -{ - pa_format_info *f = pa_format_info_new(); - struct spa_audio_info info = { 0 }; - const struct spa_pod_object *obj; - const struct spa_pod_prop *p; - - if (param == NULL || - !spa_pod_is_object_type(param, SPA_TYPE_OBJECT_Format)) - goto error; - - spa_format_parse(param, &info.media_type, &info.media_subtype); - if (info.media_type != SPA_MEDIA_TYPE_audio) - goto error; - - switch (info.media_subtype) { - case SPA_MEDIA_SUBTYPE_raw: - f->encoding = PA_ENCODING_PCM; - break; - default: - goto error; - } - - obj = (const struct spa_pod_object*)param; - SPA_POD_OBJECT_FOREACH(obj, p) { - switch (p->key) { - case SPA_FORMAT_AUDIO_format: - format_info_fill_format(f, &p->value, PA_PROP_FORMAT_SAMPLE_FORMAT); - break; - case SPA_FORMAT_AUDIO_rate: - format_info_fill_int(f, &p->value, PA_PROP_FORMAT_RATE); - break; - case SPA_FORMAT_AUDIO_channels: - format_info_fill_int(f, &p->value, PA_PROP_FORMAT_CHANNELS); - break; - case SPA_FORMAT_AUDIO_position: - { - uint32_t pos[SPA_AUDIO_MAX_CHANNELS], n_pos; - - n_pos = spa_pod_copy_array(&p->value, SPA_TYPE_Id, pos, SPA_AUDIO_MAX_CHANNELS); - if (n_pos > 0) { - char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - pa_channel_map map; - pw_channel_map_from_positions(&map, n_pos, pos); - pa_channel_map_snprint(cm, sizeof(cm), &map); - pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm); - } - break; - } - default: - break; - } - } - return f; -error: - pa_format_info_free(f); - return NULL; -} - - -int pa_format_parse_param(const struct spa_pod *param, pa_sample_spec *spec, pa_channel_map *map) -{ - struct spa_audio_info info = { 0 }; - - if (param == NULL) - return -EINVAL; - - spa_format_parse(param, &info.media_type, &info.media_subtype); - - if (info.media_type != SPA_MEDIA_TYPE_audio || - info.media_subtype != SPA_MEDIA_SUBTYPE_raw || - spa_format_audio_raw_parse(param, &info.info.raw) < 0 || - !SPA_AUDIO_FORMAT_IS_INTERLEAVED(info.info.raw.format)) { - return -ENOTSUP; - } - - spec->format = format_id2pa(info.info.raw.format); - if (spec->format == PA_SAMPLE_INVALID) - return -ENOTSUP; - - spec->rate = info.info.raw.rate; - spec->channels = info.info.raw.channels; - - pw_channel_map_from_positions(map, info.info.raw.channels, info.info.raw.position); - - return 0; -} - -const struct spa_pod *pa_format_build_param(struct spa_pod_builder *b, - uint32_t id, pa_sample_spec *spec, pa_channel_map *map) -{ - struct spa_audio_info_raw info; - - info = SPA_AUDIO_INFO_RAW_INIT( .format = format_pa2id(spec->format), - .channels = spec->channels, - .rate = spec->rate); - if (map) - pw_channel_map_to_positions(map, info.position); - - return spa_format_audio_raw_build(b, id, &info); -} diff --git a/pipewire-pulseaudio/src/internal.h b/pipewire-pulseaudio/src/internal.h deleted file mode 100644 index 81156cf32..000000000 --- a/pipewire-pulseaudio/src/internal.h +++ /dev/null @@ -1,542 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#ifndef __PIPEWIRE_PULSEAUDIO_INTERNAL_H__ -#define __PIPEWIRE_PULSEAUDIO_INTERNAL_H__ - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -/* Some PulseAudio API added const qualifiers in 13.0 */ -#if PA_MAJOR >= 13 -#define PA_CONST const -#else -#define PA_CONST -#endif - -#define PA_MAX_FORMATS (PA_ENCODING_MAX) - -#ifdef __cplusplus -extern "C" { -#endif - -#define pa_streq(a,b) (!strcmp((a),(b))) -#define pa_strneq(a,b,n) (!strncmp((a),(b),(n))) - -#ifndef PA_LIKELY -#define PA_UNLIKELY SPA_UNLIKELY -#define PA_LIKELY SPA_LIKELY -#endif -#define PA_MIN SPA_MIN -#define PA_MAX SPA_MAX -#define pa_assert spa_assert -#define pa_assert_se spa_assert_se -#define pa_return_val_if_fail(expr, val) \ - do { \ - if (SPA_UNLIKELY(!(expr))) { \ - pa_log_debug("Assertion '%s' failed at %s:%u %s()\n", \ - #expr , __FILE__, __LINE__, __func__); \ - return (val); \ - } \ - } while(false) - -#define pa_assert_not_reached spa_assert_not_reached - -#define PA_INT_TYPE_SIGNED(type) (!!((type) 0 > (type) -1)) - -#define PA_INT_TYPE_HALF(type) ((type) 1 << (sizeof(type)*8 - 2)) - -#define PA_INT_TYPE_MAX(type) \ - ((type) (PA_INT_TYPE_SIGNED(type) \ - ? (PA_INT_TYPE_HALF(type) - 1 + PA_INT_TYPE_HALF(type)) \ - : (type) -1)) - -#define PA_INT_TYPE_MIN(type) \ - ((type) (PA_INT_TYPE_SIGNED(type) \ - ? (-1 - PA_INT_TYPE_MAX(type)) \ - : (type) 0)) - - -#ifdef __GNUC__ -#define PA_CLAMP_UNLIKELY(x, low, high) \ - __extension__ ({ \ - typeof(x) _x = (x); \ - typeof(low) _low = (low); \ - typeof(high) _high = (high); \ - (PA_UNLIKELY(_x > _high) ? _high : (PA_UNLIKELY(_x < _low) ? _low : _x)); \ - }) -#else -#define PA_CLAMP_UNLIKELY(x, low, high) (PA_UNLIKELY((x) > (high)) ? (high) : (PA_UNLIKELY((x) < (low)) ? (low) : (x))) -#endif - -#ifdef __GNUC__ -#define PA_ROUND_DOWN(a, b) \ - __extension__ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ - (_a / _b) * _b; \ - }) -#else -#define PA_ROUND_DOWN(a, b) (((a) / (b)) * (b)) -#endif - - -#define pa_init_i18n() -#define _(String) (String) -#define N_(String) (String) - -#define pa_snprintf snprintf -#define pa_strip(n) pw_strip(n,"\n\r \t") - -#define pa_log pw_log_info -#define pa_log_debug pw_log_debug -#define pa_log_warn pw_log_warn - -static inline void* PA_ALIGN_PTR(const void *p) { - return (void*) (((size_t) p) & ~(sizeof(void*) - 1)); -} - -/* Rounds up */ -static inline size_t PA_ALIGN(size_t l) { - return ((l + sizeof(void*) - 1) & ~(sizeof(void*) - 1)); -} - -static inline const char *pa_strnull(const char *x) { - return x ? x : "(null)"; -} - -int pa_context_set_error(PA_CONST pa_context *c, int error); -void pa_context_fail(PA_CONST pa_context *c, int error); - -#define PA_CHECK_VALIDITY(context, expression, error) \ -do { \ - if (!(expression)) { \ - pw_log_debug("'%s' failed at %s:%u %s()", \ - #expression, __FILE__, __LINE__, __func__); \ - return -pa_context_set_error((context), (error)); \ - } \ -} while(false) - -#define PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, value) \ -do { \ - if (!(expression)) { \ - pw_log_debug("'%s' failed at %s:%u %s()", \ - #expression, __FILE__, __LINE__, __func__); \ - pa_context_set_error((context), (error)); \ - return value; \ - } \ -} while(false) - -#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) \ - PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL) - -#define PA_FAIL(context, error) \ - do { \ - pw_log_debug("fail at %s:%u %s()", \ - , __FILE__, __LINE__, __func__); \ - return -pa_context_set_error((context), (error)); \ - } while(false) - -#define PA_FAIL_RETURN_ANY(context, error, value) \ - do { \ - pw_log_debug("fail at %s:%u %s()", \ - , __FILE__, __LINE__, __func__); \ - pa_context_set_error((context), (error)); \ - return value; \ - } while(false) - -#define PA_FAIL_RETURN_NULL(context, error) \ - PA_FAIL_RETURN_ANY(context, error, NULL) - - -pa_proplist* pa_proplist_new_props(struct pw_properties *props); -pa_proplist* pa_proplist_new_dict(struct spa_dict *dict); -int pa_proplist_update_dict(pa_proplist *p, struct spa_dict *dict); -int pw_properties_update_proplist(struct pw_properties *props, PA_CONST pa_proplist *p); - -struct pa_io_event { - struct spa_source *source; - struct pa_mainloop *mainloop; - int fd; - pa_io_event_flags_t events; - pa_io_event_cb_t cb; - void *userdata; - pa_io_event_destroy_cb_t destroy; -}; - -struct pa_time_event { - struct spa_source *source; - struct pa_mainloop *mainloop; - pa_time_event_cb_t cb; - void *userdata; - pa_time_event_destroy_cb_t destroy; -}; - -struct pa_defer_event { - struct spa_source *source; - struct pa_mainloop *mainloop; - pa_defer_event_cb_t cb; - void *userdata; - pa_defer_event_destroy_cb_t destroy; -}; - -struct pa_mainloop { - struct pw_loop *loop; - struct spa_source *event; - - pa_mainloop_api api; - - bool quit; - int retval; - - int timeout; - int n_events; - - int fd; - pa_poll_func poll_func; - void *poll_func_userdata; -}; - -struct param { - struct spa_list link; - uint32_t id; - void *param; -}; - -#define PA_IDX_FLAG_MONITOR 0x800000U -#define PA_IDX_MASK_MONITOR 0x7fffffU - -struct port_device { - uint32_t n_devices; - uint32_t *devices; -}; - -struct global; - -struct global_info { - uint32_t version; - const void *events; - pw_destroy_t destroy; - void (*sync) (struct global *g); -}; - -struct global { - struct spa_list link; - uint32_t id; - uint32_t permissions; - char *type; - struct pw_properties *props; - - pa_context *context; - pa_subscription_mask_t mask; - pa_subscription_event_type_t event; - - int priority_driver; - int init:1; - int sync:1; - - int changed; - void *info; - struct global_info *ginfo; - - struct pw_proxy *proxy; - struct spa_hook proxy_listener; - struct spa_hook object_listener; - - pa_stream *stream; - - union { - /* for links */ - struct { - struct global *src; - struct global *dst; - } link_info; - /* for sink/source */ - struct { - uint32_t client_id; /* if of owner client */ - uint32_t monitor; -#define NODE_FLAG_HW_VOLUME (1 << 0) -#define NODE_FLAG_DEVICE_VOLUME (1 << 1) -#define NODE_FLAG_HW_MUTE (1 << 4) -#define NODE_FLAG_DEVICE_MUTE (1 << 5) - uint32_t flags; - float volume; - bool mute; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - uint32_t n_channel_volumes; - float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; - uint32_t device_id; /* id of device (card) */ - uint32_t profile_device_id; /* id in profile */ - float base_volume; - float volume_step; - uint32_t active_port; - enum spa_param_availability available_port; - uint32_t device_index; - struct pw_array formats; - } node_info; - struct { - uint32_t node_id; - } port_info; - /* for devices */ - struct { - struct spa_list profiles; - uint32_t n_profiles; - uint32_t active_profile; - struct spa_list ports; - uint32_t n_ports; - struct spa_list routes; - uint32_t n_routes; - pa_card_info info; - pa_card_profile_info2 *card_profiles; - unsigned int pending_profiles:1; - pa_card_port_info *card_ports; - unsigned int pending_ports:1; - struct port_device *port_devices; - } card_info; - struct { - pa_module_info info; - } module_info; - struct { - pa_client_info info; - } client_info; - }; -}; - -struct module_info { - struct spa_list link; /* link in context modules */ - uint32_t id; - struct pw_proxy *proxy; - struct spa_hook listener; -}; - -struct pa_context { - int refcount; - uint32_t client_index; - - pa_io_event *io; - bool fallback_loop; - struct pw_loop *loop; - struct pw_context *context; - - struct pw_properties *props; - - struct pw_core *core; - struct spa_hook core_listener; - struct pw_core_info *core_info; - - struct pw_registry *registry; - struct spa_hook registry_listener; - - pa_proplist *proplist; - pa_mainloop_api *mainloop; - - int error; - pa_context_state_t state; - - pa_context_notify_cb_t state_callback; - void *state_userdata; - pa_context_event_cb_t event_callback; - void *event_userdata; - pa_context_subscribe_cb_t subscribe_callback; - void *subscribe_userdata; - pa_subscription_mask_t subscribe_mask; - - struct spa_list globals; - - struct spa_list streams; - struct spa_list operations; - struct spa_list modules; - - int no_fail:1; - int disconnect:1; - - int pending_seq; - - struct global *metadata; - uint32_t default_sink; - uint32_t default_source; -}; - -pa_stream *pa_context_find_stream(pa_context *c, uint32_t idx); -struct global *pa_context_find_global(pa_context *c, uint32_t id); -const char *pa_context_find_global_name(pa_context *c, uint32_t id); -struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, const char *name); -struct global *pa_context_find_linked(pa_context *c, uint32_t id); - -struct pa_mem { - struct spa_list link; - void *data; - size_t maxsize; - size_t size; - size_t offset; - void *user_data; -}; - -struct pa_stream { - struct spa_list link; - int refcount; - - struct pw_stream *stream; - struct spa_hook stream_listener; - - pa_context *context; - pa_proplist *proplist; - - pa_stream_direction_t direction; - pa_stream_state_t state; - pa_stream_flags_t flags; - bool disconnecting; - - pa_sample_spec sample_spec; - pa_channel_map channel_map; - uint8_t n_formats; - pa_format_info *req_formats[PA_MAX_FORMATS]; - pa_format_info *format; - - uint32_t stream_index; - struct global *global; - - pa_buffer_attr buffer_attr; - - uint32_t device_index; - char *device_name; - - pa_timing_info timing_info; - uint64_t ticks_base; - size_t queued_bytes; - - uint32_t direct_on_input; - - unsigned int suspended:1; - unsigned int corked:1; - unsigned int timing_info_valid:1; - unsigned int have_time:1; - - pa_stream_notify_cb_t state_callback; - void *state_userdata; - pa_stream_request_cb_t read_callback; - void *read_userdata; - pa_stream_request_cb_t write_callback; - void *write_userdata; - pa_stream_notify_cb_t overflow_callback; - void *overflow_userdata; - pa_stream_notify_cb_t underflow_callback; - void *underflow_userdata; - pa_stream_notify_cb_t latency_update_callback; - void *latency_update_userdata; - pa_stream_notify_cb_t moved_callback; - void *moved_userdata; - pa_stream_notify_cb_t suspended_callback; - void *suspended_userdata; - pa_stream_notify_cb_t started_callback; - void *started_userdata; - pa_stream_event_cb_t event_callback; - void *event_userdata; - pa_stream_notify_cb_t buffer_attr_callback; - void *buffer_attr_userdata; - - size_t maxsize; - size_t maxblock; - - struct pa_mem *mem; /* current mem for playback */ - struct spa_list free; /* free to fill */ - struct spa_list ready; /* ready for playback */ - size_t ready_bytes; - - struct pw_buffer *buffer; /* currently reading for capture */ - - uint32_t n_channel_volumes; - float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; - bool mute; - pa_operation *drain; -}; - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); - -typedef void (*pa_operation_cb_t)(pa_operation *o, void *userdata); - -struct pa_operation -{ - struct spa_list link; - - int refcount; - pa_context *context; - pa_stream *stream; - unsigned int sync:1; - - pa_operation_state_t state; - - pa_operation_cb_t callback; - void *userdata; - - pa_operation_notify_cb_t state_callback; - void *state_userdata; -}; - -bool pa_mainloop_api_is_our_api(pa_mainloop_api *api); - -#define PA_TIMEVAL_RTCLOCK ((time_t) (1LU << 30)) -struct timeval* pa_rtclock_from_wallclock(struct timeval *tv); -struct timeval* pa_rtclock_to_wallclock(struct timeval *tv); -struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, bool rtclock); - -bool pa_endswith(const char *s, const char *sfx); - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, size_t userdata_size); -void pa_operation_done(pa_operation *o); -int pa_operation_sync(pa_operation *o); - -#define METADATA_DEFAULT_SINK "default.audio.sink" -#define METADATA_DEFAULT_SOURCE "default.audio.source" -#define METADATA_TARGET_NODE "target.node" - -int pa_metadata_update(struct global *global, uint32_t subject, const char *key, - const char *type, const char *value); -int pa_metadata_get(struct global *global, uint32_t subject, const char *key, - const char **type, const char **value); - -void pw_channel_map_from_positions(pa_channel_map *map, uint32_t n_pos, const uint32_t *pos); -void pw_channel_map_to_positions(const pa_channel_map *map, uint32_t *pos); - -int pa_format_parse_param(const struct spa_pod *param, - pa_sample_spec *spec, pa_channel_map *map); -const struct spa_pod *pa_format_build_param(struct spa_pod_builder *b, - uint32_t id, pa_sample_spec *spec, pa_channel_map *map); - -pa_format_info* pa_format_info_from_param(const struct spa_pod *param); - -#ifdef __cplusplus -} -#endif - -#endif /* __PIPEWIRE_PULSEAUDIO_INTERNAL_H__ */ diff --git a/pipewire-pulseaudio/src/introspect.c b/pipewire-pulseaudio/src/introspect.c deleted file mode 100644 index c46c91b96..000000000 --- a/pipewire-pulseaudio/src/introspect.c +++ /dev/null @@ -1,2905 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include -#include - -#include -#include - -#include "internal.h" - -struct success_ack { - pa_context_success_cb_t cb; - int error; - void *userdata; - uint32_t idx; -}; - -static void on_success(pa_operation *o, void *userdata) -{ - struct success_ack *d = userdata; - pa_context *c = o->context; - if (d->error != 0) - pa_context_set_error(c, d->error); - if (d->cb) - d->cb(c, d->error ? 0 : 1, d->userdata); - pa_operation_done(o); -} - -struct sink_data { - pa_sink_info_cb_t cb; - void *userdata; - char *name; - uint32_t idx; -}; - -static pa_sink_state_t node_state_to_sink(enum pw_node_state s) -{ - switch(s) { - case PW_NODE_STATE_ERROR: - return PA_SINK_UNLINKED; - case PW_NODE_STATE_CREATING: - return PA_SINK_INIT; - case PW_NODE_STATE_SUSPENDED: - return PA_SINK_SUSPENDED; - case PW_NODE_STATE_IDLE: - return PA_SINK_IDLE; - case PW_NODE_STATE_RUNNING: - return PA_SINK_RUNNING; - default: - return PA_SINK_INVALID_STATE; - } -} - -static int has_profile(pa_card_profile_info2 **list, pa_card_profile_info2 *active) -{ - for(;*list; list++) { - if (*list == active) - return 1; - } - return 0; -} -static int has_device(struct port_device *devices, uint32_t id) -{ - uint32_t i; - - if (devices->devices == NULL || devices->n_devices == 0) - return 1; - - for (i = 0; i < devices->n_devices; i++) { - if (devices->devices[i] == id) - return 1; - } - return 0; -} - -static int sink_callback(pa_context *c, struct global *g, struct sink_data *d) -{ - struct global *cg; - struct pw_node_info *info = g->info; - const char *str; - uint32_t n, j; - char monitor_name[1024]; - pa_sink_info i; - - spa_zero(i); - if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_NAME))) - i.name = str; - else - i.name = "unknown"; - pw_log_debug("sink %d %s monitor %d", g->id, i.name, g->node_info.monitor); - i.index = g->id; - if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION))) - i.description = str; - else - i.description = "Unknown"; - - i.sample_spec = g->node_info.sample_spec; - if (g->node_info.n_channel_volumes) - i.sample_spec.channels = g->node_info.n_channel_volumes; - else - i.sample_spec.channels = 2; - if (i.sample_spec.channels == g->node_info.channel_map.channels) - i.channel_map = g->node_info.channel_map; - else - pa_channel_map_init_extend(&i.channel_map, - i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - i.owner_module = g->id; - i.volume.channels = i.sample_spec.channels; - for (n = 0; n < i.volume.channels; n++) - i.volume.values[n] = pa_sw_volume_from_linear(g->node_info.volume * g->node_info.channel_volumes[n]);; - i.mute = g->node_info.mute; - i.monitor_source = g->node_info.monitor; - snprintf(monitor_name, sizeof(monitor_name)-1, "%s.monitor", i.name); - i.monitor_source_name = monitor_name; - i.latency = 0; - i.driver = "PipeWire"; - i.flags = PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY | - PA_SINK_DECIBEL_VOLUME; - if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_DEVICE_API))) - i.flags |= PA_SINK_HARDWARE; - if (SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_HW_VOLUME)) - i.flags |= PA_SINK_HW_VOLUME_CTRL; - if (SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_HW_MUTE)) - i.flags |= PA_SINK_HW_MUTE_CTRL; - i.proplist = pa_proplist_new_dict(info->props); - i.configured_latency = 0; - i.base_volume = pa_sw_volume_from_linear(g->node_info.base_volume); - i.n_volume_steps = g->node_info.volume_step * (PA_VOLUME_NORM+1); - i.state = node_state_to_sink(info->state); - i.card = g->node_info.device_id; - i.n_ports = 0; - i.ports = NULL; - i.active_port = NULL; - if ((cg = pa_context_find_global(c, i.card)) != NULL) { - pa_sink_port_info *spi; - pa_card_info *ci = &cg->card_info.info; - - spi = alloca(ci->n_ports * sizeof(pa_sink_port_info)); - i.ports = alloca((ci->n_ports + 1) * sizeof(pa_sink_port_info *)); - - for (n = 0,j = 0; n < ci->n_ports; n++) { - if (ci->ports[n]->direction != PA_DIRECTION_OUTPUT) - continue; - if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2)) - continue; - if (!has_device(&cg->card_info.port_devices[n], g->node_info.profile_device_id)) - continue; - - spa_zero(spi[j]); - i.ports[j] = &spi[j]; - spi[j].name = ci->ports[n]->name; - spi[j].description = ci->ports[n]->description; - spi[j].priority = ci->ports[n]->priority; - spi[j].available = ci->ports[n]->available; - if (n == g->node_info.active_port) - i.active_port = i.ports[j]; - j++; - } - i.n_ports = j; - if (i.n_ports == 0) - i.ports = NULL; - else - i.ports[j] = NULL; - } - if (i.active_port == NULL && i.n_ports > 0) - i.active_port = i.ports[0]; - i.n_formats = pw_array_get_len(&g->node_info.formats, pa_format_info *); - i.formats = g->node_info.formats.data; - d->cb(c, &i, 0, d->userdata); - pa_proplist_free(i.proplist); - return 0; -} - -static void sink_info(pa_operation *o, void *userdata) -{ - struct sink_data *d = userdata; - struct global *g; - pa_context *c = o->context; - int error = 0; - - pw_log_debug("%p name:%s idx:%u", c, d->name, d->idx); - - if (d->name) { - g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, d->name); - pa_xfree(d->name); - } else { - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_SINK)) - g = NULL; - } - - if (g) { - error = sink_callback(c, g, d); - } else { - error = PA_ERR_NOENTITY; - } - if (error) - pa_context_set_error(c, error); - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sink_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("%p: name %s", c, name); - - o = pa_operation_new(c, NULL, sink_info, sizeof(struct sink_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sink_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("%p: index %u", c, idx); - - o = pa_operation_new(c, NULL, sink_info, sizeof(struct sink_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - pa_operation_sync(o); - - return o; -} - -static void sink_info_list(pa_operation *o, void *userdata) -{ - struct sink_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK)) - continue; - sink_callback(c, g, d); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sink_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p", c); - o = pa_operation_new(c, NULL, sink_info_list, sizeof(struct sink_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static int set_stream_volume(pa_context *c, pa_stream *s, const pa_cvolume *volume, bool mute) -{ - uint32_t i, n_channel_volumes; - float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; - float *vols; - - if (volume) { - for (i = 0; i < volume->channels; i++) - channel_volumes[i] = pa_sw_volume_to_linear(volume->values[i]);; - vols = channel_volumes; - n_channel_volumes = volume->channels; - } else { - vols = s->channel_volumes; - n_channel_volumes = s->n_channel_volumes; - } - - if (n_channel_volumes != s->n_channel_volumes || - !memcmp(s->channel_volumes, vols, n_channel_volumes * sizeof(float)) || - s->mute != mute) { - float val = s->mute ? 1.0f : 0.0f; - pw_stream_set_control(s->stream, - SPA_PROP_mute, 1, &val, - SPA_PROP_channelVolumes, n_channel_volumes, vols, - 0); - } - return 0; -} - -static int set_node_volume(pa_context *c, struct global *g, const pa_cvolume *volume, bool mute) -{ - char buf[1024]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - uint32_t i, n_channel_volumes; - float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; - float *vols; - - if (volume) { - for (i = 0; i < volume->channels; i++) - channel_volumes[i] = pa_sw_volume_to_linear(volume->values[i]); - vols = channel_volumes; - n_channel_volumes = volume->channels; - - if (n_channel_volumes == g->node_info.n_channel_volumes && - memcmp(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float)) == 0 && - mute == g->node_info.mute) - return 0; - - memcpy(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float)); - g->node_info.n_channel_volumes = n_channel_volumes; - } else { - n_channel_volumes = g->node_info.n_channel_volumes; - vols = g->node_info.channel_volumes; - if (mute == g->node_info.mute) - return 0; - } - g->node_info.mute = mute; - g->changed++; - - if (!SPA_FLAG_IS_SET(g->permissions, PW_PERM_W | PW_PERM_X)) - return PA_ERR_ACCESS; - - pw_log_debug("node %p: id:%u", g, g->id); - pw_node_set_param((struct pw_node*)g->proxy, - SPA_PARAM_Props, 0, - spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, - SPA_PROP_mute, SPA_POD_Bool(mute), - SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - n_channel_volumes, - vols))); - return 0; -} - -static int set_device_volume(pa_context *c, struct global *g, struct global *cg, uint32_t id, - uint32_t device_id, const pa_cvolume *volume, bool mute) -{ - char buf[1024]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - struct spa_pod_frame f[2]; - struct spa_pod *param; - uint32_t i, n_channel_volumes; - float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; - float *vols; - - if (volume) { - for (i = 0; i < volume->channels; i++) - channel_volumes[i] = pa_sw_volume_to_linear(volume->values[i]); - vols = channel_volumes; - n_channel_volumes = volume->channels; - - if (n_channel_volumes == g->node_info.n_channel_volumes && - memcmp(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float)) == 0 && - mute == g->node_info.mute) - return 0; - - memcpy(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float)); - g->node_info.n_channel_volumes = n_channel_volumes; - } else { - n_channel_volumes = g->node_info.n_channel_volumes; - vols = g->node_info.channel_volumes; - if (mute == g->node_info.mute) - return 0; - } - g->node_info.mute = mute; - g->changed++; - - if (!SPA_FLAG_IS_SET(cg->permissions, PW_PERM_W | PW_PERM_X)) - return PA_ERR_ACCESS; - - spa_pod_builder_push_object(&b, &f[0], - SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route); - spa_pod_builder_add(&b, - SPA_PARAM_ROUTE_index, SPA_POD_Int(id), - SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id), - 0); - spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0); - spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, - SPA_PROP_mute, SPA_POD_Bool(mute), - SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - n_channel_volumes, - vols)); - param = spa_pod_builder_pop(&b, &f[0]); - - pw_log_debug("device %p: id:%u", cg, cg->id); - pw_device_set_param((struct pw_node*)cg->proxy, - SPA_PARAM_Route, 0, param); - - return 0; -} - -static int set_volume(pa_context *c, struct global *g, const pa_cvolume *volume, bool mute, - uint32_t mask) -{ - struct global *cg; - uint32_t id = SPA_ID_INVALID, card_id, device_id; - int res; - - card_id = g->node_info.device_id; - device_id = g->node_info.profile_device_id; - - pw_log_debug("card:%u global:%u flags:%08x", card_id, g->id, g->node_info.flags); - - if (SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME | NODE_FLAG_DEVICE_MUTE) && - (cg = pa_context_find_global(c, card_id)) != NULL) { - id = cg->node_info.active_port; - } - if (id != SPA_ID_INVALID && device_id != SPA_ID_INVALID) { - res = set_device_volume(c, g, cg, id, device_id, volume, mute); - } else { - res = set_node_volume(c, g, volume, mute); - } - return res; -} - -struct volume_data { - pa_context_success_cb_t cb; - uint32_t mask; - void *userdata; - char *name; - uint32_t idx; - bool have_volume; - pa_cvolume volume; - int mute; -}; - -static void do_node_volume_mute(pa_operation *o, void *userdata) -{ - struct volume_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error = 0; - - if (d->name) { - g = pa_context_find_global_by_name(c, d->mask, d->name); - pa_xfree(d->name); - } else { - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & d->mask)) - g = NULL; - } - if (g) { - error = set_volume(c, g, - d->have_volume ? &d->volume : NULL, - d->have_volume ? g->node_info.mute : d->mute, - d->mask); - } else { - error = PA_ERR_NOENTITY; - } - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error ? 0 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - pw_log_debug("context %p: index %d", c, idx); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - d->volume = *volume; - d->have_volume = true; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - pw_log_debug("context %p: name %s", c, name); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->cb = cb; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->userdata = userdata; - d->name = pa_xstrdup(name); - d->volume = *volume; - d->have_volume = true; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index %d", c, idx); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - d->mute = mute; - pa_operation_sync(o); - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("context %p: name %s", c, name); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - d->mute = mute; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct success_ack *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: name:%s suspend:%d", c, sink_name, suspend); - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct success_ack *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index:%u suspend:%d", c, idx, suspend); - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static int set_device_route(pa_context *c, struct global *g, const char *port, enum spa_direction direction) -{ - struct global *cg; - struct param *p; - uint32_t id = SPA_ID_INVALID, card_id, device_id; - char buf[1024]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - - card_id = g->node_info.device_id; - device_id = g->node_info.profile_device_id; - - pw_log_info("port \"%s\": card:%u device:%u global:%u", port, card_id, device_id, g->id); - - if ((cg = pa_context_find_global(c, card_id)) == NULL || device_id == SPA_ID_INVALID) - return PA_ERR_NOENTITY; - - spa_list_for_each(p, &cg->card_info.ports, link) { - uint32_t test_id; - const char *name; - enum spa_direction test_direction; - - if (spa_pod_parse_object(p->param, - SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&test_id), - SPA_PARAM_ROUTE_direction, SPA_POD_Id(&test_direction), - SPA_PARAM_ROUTE_name, SPA_POD_String(&name)) < 0) { - pw_log_warn("device %d: can't parse route", g->id); - continue; - } - pw_log_debug("port id:%u name:\"%s\" dir:%d", test_id, name, test_direction); - if (test_direction != direction) - continue; - if (strcmp(name, port) == 0) { - id = test_id; - break; - } - } - pw_log_debug("port %s, id %u", port, id); - if (id == SPA_ID_INVALID) - return PA_ERR_NOENTITY; - - if (!SPA_FLAG_IS_SET(cg->permissions, PW_PERM_W | PW_PERM_X)) - return PA_ERR_ACCESS; - - pw_device_set_param((struct pw_device*)cg->proxy, - SPA_PARAM_Route, 0, - spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route, - SPA_PARAM_ROUTE_index, SPA_POD_Int(id), - SPA_PARAM_ROUTE_direction, SPA_POD_Id(direction), - SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id))); - - return 0; -} - -struct device_route { - uint32_t mask; - pa_context_success_cb_t cb; - void *userdata; - char *name; - uint32_t idx; - char *port; - enum spa_direction direction; -}; - -static void do_device_route(pa_operation *o, void *userdata) -{ - struct device_route *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - pw_log_debug("%p", c); - - if (d->name) { - g = pa_context_find_global_by_name(c, d->mask, d->name); - pa_xfree(d->name); - } else { - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & d->mask)) - g = NULL; - } - if (g) { - error = set_device_route(c, g, d->port, d->direction); - } else { - error = PA_ERR_NOENTITY; - } - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error != 0 ? 0 : 1, d->userdata); - pa_xfree(d->port); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct device_route *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index:%u port:%s", c, idx, port); - o = pa_operation_new(c, NULL, do_device_route, sizeof(struct device_route)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - d->port = pa_xstrdup(port); - d->direction = SPA_DIRECTION_OUTPUT; - pa_operation_sync(o); - return o; -} - -SPA_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) -{ - pa_operation *o; - struct device_route *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("context %p: name:%s port:%s", c, name, port); - o = pa_operation_new(c, NULL, do_device_route, sizeof(struct device_route)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SINK; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - d->port = pa_xstrdup(port); - d->direction = SPA_DIRECTION_OUTPUT; - pa_operation_sync(o); - return o; -} - - -struct source_data { - pa_source_info_cb_t cb; - void *userdata; - char *name; - uint32_t idx; -}; - -static pa_source_state_t node_state_to_source(enum pw_node_state s) -{ - switch(s) { - case PW_NODE_STATE_ERROR: - return PA_SOURCE_UNLINKED; - case PW_NODE_STATE_CREATING: - return PA_SOURCE_INIT; - case PW_NODE_STATE_SUSPENDED: - return PA_SOURCE_SUSPENDED; - case PW_NODE_STATE_IDLE: - return PA_SOURCE_IDLE; - case PW_NODE_STATE_RUNNING: - return PA_SOURCE_RUNNING; - default: - return PA_SOURCE_INVALID_STATE; - } -} -static int source_callback(pa_context *c, struct global *g, struct source_data *d) -{ - struct global *cg; - struct pw_node_info *info = g->info; - const char *str; - uint32_t n, j; - pa_source_info i; - enum pa_source_flags flags; - bool monitor; - - flags = PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY | - PA_SOURCE_DECIBEL_VOLUME; - - monitor = (g->mask & PA_SUBSCRIPTION_MASK_SINK) != 0; - - spa_zero(i); - - i.proplist = pa_proplist_new_dict(info->props); - - if (monitor) { - if ((str = spa_dict_lookup(info->props, PW_KEY_NODE_NAME))) - pa_proplist_setf(i.proplist, PW_KEY_NODE_NAME, "%s.monitor", str); - if ((str = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION))) - pa_proplist_setf(i.proplist, PW_KEY_NODE_DESCRIPTION, "Monitor of %s", str); - pa_proplist_setf(i.proplist, PW_KEY_DEVICE_CLASS, "monitor"); - } - - if ((str = pa_proplist_gets(i.proplist, PW_KEY_NODE_NAME))) - i.name = str; - else - i.name = "unknown"; - - pw_log_debug("source %d %s monitor:%d", g->id, i.name, monitor); - - if ((str = pa_proplist_gets(i.proplist, PW_KEY_NODE_DESCRIPTION))) - i.description = str; - else - i.description = "unknown"; - i.sample_spec = g->node_info.sample_spec; - if (g->node_info.n_channel_volumes) - i.sample_spec.channels = g->node_info.n_channel_volumes; - else - i.sample_spec.channels = 2; - if (i.sample_spec.channels == g->node_info.channel_map.channels) - i.channel_map = g->node_info.channel_map; - else - pa_channel_map_init_extend(&i.channel_map, - i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - i.owner_module = g->id; - i.volume.channels = i.sample_spec.channels; - for (n = 0; n < i.volume.channels; n++) - i.volume.values[n] = pa_sw_volume_from_linear(g->node_info.volume * g->node_info.channel_volumes[n]);; - i.mute = g->node_info.mute; - if (monitor) { - i.index = g->node_info.monitor; - i.monitor_of_sink = g->id; - i.monitor_of_sink_name = pa_context_find_global_name(c, g->id); - } else { - i.index = g->id; - i.monitor_of_sink = PA_INVALID_INDEX; - i.monitor_of_sink_name = NULL; - if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_DEVICE_API))) - flags |= PA_SOURCE_HARDWARE; - if (SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_HW_VOLUME)) - flags |= PA_SINK_HW_VOLUME_CTRL; - if (SPA_FLAG_IS_SET(g->node_info.flags, NODE_FLAG_HW_MUTE)) - flags |= PA_SINK_HW_MUTE_CTRL; - } - i.latency = 0; - i.driver = "PipeWire"; - i.flags = flags; - i.configured_latency = 0; - i.base_volume = pa_sw_volume_from_linear(g->node_info.base_volume); - i.n_volume_steps = g->node_info.volume_step * (PA_VOLUME_NORM+1); - i.state = node_state_to_source(info->state); - i.card = g->node_info.device_id; - i.n_ports = 0; - i.ports = NULL; - i.active_port = NULL; - if (!monitor && (cg = pa_context_find_global(c, i.card)) != NULL) { - pa_source_port_info *spi; - pa_card_info *ci = &cg->card_info.info; - - spi = alloca(ci->n_ports * sizeof(pa_source_port_info)); - i.ports = alloca((ci->n_ports + 1) * sizeof(pa_source_port_info *)); - - for (n = 0,j = 0; n < ci->n_ports; n++) { - if (ci->ports[n]->direction != PA_DIRECTION_INPUT) - continue; - if (!has_profile(ci->ports[n]->profiles2, ci->active_profile2)) - continue; - if (!has_device(&cg->card_info.port_devices[n], g->node_info.profile_device_id)) - continue; - - spa_zero(spi[j]); - i.ports[j] = &spi[j]; - spi[j].name = ci->ports[n]->name; - spi[j].description = ci->ports[n]->description; - spi[j].priority = ci->ports[n]->priority; - spi[j].available = ci->ports[n]->available; - if (n == g->node_info.active_port) - i.active_port = i.ports[j]; - j++; - } - i.n_ports = j; - if (i.n_ports == 0) - i.ports = NULL; - else - i.ports[j] = NULL; - } - if (i.active_port == NULL && i.n_ports > 0) - i.active_port = i.ports[0]; - i.n_formats = pw_array_get_len(&g->node_info.formats, pa_format_info *); - i.formats = g->node_info.formats.data; - d->cb(c, &i, 0, d->userdata); - pa_proplist_free(i.proplist); - return 0; -} - -static void source_info(pa_operation *o, void *userdata) -{ - struct source_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - if (d->name) { - g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, d->name); - pa_xfree(d->name); - } else { - if (((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)) && - (((g = pa_context_find_global(c, d->idx & PA_IDX_MASK_MONITOR)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)))) - g = NULL; - } - - if (g) { - error = source_callback(c, g, d); - } else { - error = PA_ERR_NOENTITY; - } - if (error) - pa_context_set_error(c, error); - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct source_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("context %p: name:%s", c, name); - o = pa_operation_new(c, NULL, source_info, sizeof(struct source_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct source_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index %d", c, idx); - - o = pa_operation_new(c, NULL, source_info, sizeof(struct source_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - pa_operation_sync(o); - - return o; -} - -static void source_info_list(pa_operation *o, void *userdata) -{ - struct source_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)) - continue; - source_callback(c, g, d); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct source_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p", c); - o = pa_operation_new(c, NULL, source_info_list, sizeof(struct source_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - pw_log_debug("context %p: index %d", c, idx); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - d->volume = *volume; - d->have_volume = true; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - pw_log_debug("context %p: name %s", c, name); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - d->volume = *volume; - d->have_volume = true; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index %d", c, idx); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - d->mute = mute; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct volume_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("context %p: name %s", c, name); - - o = pa_operation_new(c, NULL, do_node_volume_mute, sizeof(struct volume_data)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - d->mute = mute; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct success_ack *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: name:%s", c, source_name); - - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct success_ack *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index:%u", c, idx); - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct device_route *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: idx %d port:%s", c, idx, port); - - o = pa_operation_new(c, NULL, do_device_route, sizeof(struct device_route)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->cb = cb; - d->userdata = userdata; - d->idx = idx; - d->port = pa_xstrdup(port); - d->direction = SPA_DIRECTION_INPUT; - pa_operation_sync(o); - return o; -} - -SPA_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) -{ - pa_operation *o; - struct device_route *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("context %p: name %s port:%s", c, name, port); - - o = pa_operation_new(c, NULL, do_device_route, sizeof(struct device_route)); - d = o->userdata; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->cb = cb; - d->userdata = userdata; - d->name = pa_xstrdup(name); - d->port = pa_xstrdup(port); - d->direction = SPA_DIRECTION_INPUT; - pa_operation_sync(o); - return o; -} - -struct server_data { - pa_server_info_cb_t cb; - void *userdata; - struct global *global; -}; - -static const char *get_default_name(pa_context *c, uint32_t mask) -{ - struct global *g; - const char *str; - uint32_t id = SPA_ID_INVALID; - - - if (c->metadata) { - if (mask & PA_SUBSCRIPTION_MASK_SINK) - id = c->default_sink; - else if (mask & PA_SUBSCRIPTION_MASK_SOURCE) - id = c->default_source; - else - return NULL; - } - spa_list_for_each(g, &c->globals, link) { - if ((g->mask & mask) != mask) - continue; - if (g->props != NULL && - (str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) != NULL && - (id == SPA_ID_INVALID || id == g->id)) - return str; - } - return "unknown"; -} - -static void server_callback(struct server_data *d, pa_context *c) -{ - const struct pw_core_info *info = c->core_info; - const char *str; - pa_server_info i; - char name[1024]; - - snprintf(name, sizeof(name)-1, "pulseaudio (on PipeWire %s)", info->version); - - spa_zero(i); - i.user_name = info->user_name; - i.host_name = info->host_name; - i.server_version = pa_get_headers_version(); - i.server_name = name; - i.sample_spec.format = PA_SAMPLE_FLOAT32NE; - if (info->props && (str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL) - i.sample_spec.rate = atoi(str); - else - i.sample_spec.rate = 44100; - i.sample_spec.channels = 2; - i.default_sink_name = get_default_name(c, PA_SUBSCRIPTION_MASK_SINK); - i.default_source_name = get_default_name(c, PA_SUBSCRIPTION_MASK_SOURCE); - i.cookie = info->cookie; - pa_channel_map_init_extend(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - d->cb(c, &i, d->userdata); -} - -static void server_info(pa_operation *o, void *userdata) -{ - struct server_data *d = userdata; - server_callback(d, o->context); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct server_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p", c); - o = pa_operation_new(c, NULL, server_info, sizeof(struct server_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct module_data { - uint32_t idx; - pa_module_info_cb_t cb; - void *userdata; -}; - -static int module_callback(pa_context *c, struct module_data *d, struct global *g) -{ - d->cb(c, &g->module_info.info, 0, d->userdata); - return 0; -} - -static void module_info(pa_operation *o, void *userdata) -{ - struct module_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_MODULE)) - g = NULL; - - if (g) { - error = module_callback(c, d, g); - } else { - error = PA_ERR_NOENTITY; - } - if (error) - pa_context_set_error(c, error); - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct module_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p index:%u", c, idx); - o = pa_operation_new(c, NULL, module_info, sizeof(struct module_data)); - d = o->userdata; - d->idx = idx; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void module_info_list(pa_operation *o, void *userdata) -{ - struct module_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_MODULE)) - continue; - module_callback(c, d, g); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct module_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p", c); - o = pa_operation_new(c, NULL, module_info_list, sizeof(struct module_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct load_module { - pa_context_index_cb_t cb; - int error; - void *userdata; - uint32_t idx; - struct pw_properties *props; - struct pw_proxy *proxy; - struct spa_hook listener; -}; - -static struct module_info *find_module(pa_context *c, uint32_t idx) -{ - struct module_info *m; - spa_list_for_each(m, &c->modules, link) { - if (m->id == idx) - return m; - } - return NULL; -} - -static void on_load_module(pa_operation *o, void *userdata) -{ - struct load_module *d = userdata; - pa_context *c = o->context; - if (d->error != 0) - pa_context_set_error(c, d->error); - if (d->cb) - d->cb(c, d->idx, d->userdata); - if (d->props) - pw_properties_free(d->props); - if (d->proxy) - spa_hook_remove(&d->listener); - pa_operation_done(o); -} - -static void module_proxy_removed(void *data) -{ - struct module_info *m = data; - pw_proxy_destroy(m->proxy); -} - -static void module_proxy_destroy(void *data) -{ - struct module_info *m = data; - spa_hook_remove(&m->listener); - spa_list_remove(&m->link); - free(m); -} - -static void module_proxy_bound(void *data, uint32_t global_id) -{ - struct module_info *m; - pa_operation *o = data; - pa_context *c = o->context; - struct load_module *d = o->userdata; - static const struct pw_proxy_events proxy_events = { - .removed = module_proxy_removed, - .destroy = module_proxy_destroy, - }; - d->idx = global_id; - - m = calloc(1, sizeof(struct module_info)); - m->id = global_id; - m->proxy = d->proxy; - pw_proxy_add_listener(m->proxy, &m->listener, &proxy_events, m); - spa_list_append(&c->modules, &m->link); - on_load_module(o, d); -} - -static void module_proxy_error(void *data, int seq, int res, const char *message) -{ - pa_operation *o = data; - struct load_module *d = o->userdata; - d->error = res; - d->idx = PA_INVALID_INDEX; - pw_proxy_destroy(d->proxy); - on_load_module(o, d); -} - -static int load_null_sink_module(pa_operation *o) -{ - struct load_module *d = o->userdata; - pa_context *c = o->context; - static const struct pw_proxy_events proxy_events = { - .bound = module_proxy_bound, - .error = module_proxy_error, - }; - - if (d->proxy != NULL) - return -EBUSY; - - d->proxy = pw_core_create_object(c->core, - "adapter", - PW_TYPE_INTERFACE_Node, - PW_VERSION_NODE, - d->props ? &d->props->dict : NULL, 0); - if (d->proxy == NULL) - return -errno; - - pw_proxy_add_listener(d->proxy, &d->listener, &proxy_events, o); - return 0; -} - -static void add_props(struct pw_properties *props, const char *str) -{ - char *s = strdup(str), *p = s, *e, f; - const char *k, *v; - - while (*p) { - e = strchr(p, '='); - if (e == NULL) - break; - *e = '\0'; - k = p; - p = e+1; - - if (*p == '\"') { - p++; - f = '\"'; - } else { - f = ' '; - } - e = strchr(p, f); - if (e == NULL) - break; - *e = '\0'; - v = p; - p = e + 1; - pw_properties_set(props, k, v); - } - free(s); -} - -SPA_EXPORT -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata) -{ - pa_operation *o; - struct load_module *d; - int error = PA_ERR_NOTIMPLEMENTED;; - struct pw_properties *props = NULL; - const char *str; - bool sync = true; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(name != NULL); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: name:%s arg:%s", c, name, argument); - - o = pa_operation_new(c, NULL, on_load_module, sizeof(struct load_module)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - d->idx = PA_INVALID_INDEX; - - if (strcmp(name, "module-null-sink") == 0) { - props = pw_properties_new_string(argument); - if (props == NULL) { - error = PA_ERR_INVALID; - goto done; - } - if ((str = pw_properties_get(props, "sink_name")) != NULL) { - pw_properties_set(props, "node.name", str); - pw_properties_set(props, "sink_name", NULL); - } else { - pw_properties_set(props, "node.name", "null"); - } - if ((str = pw_properties_get(props, "sink_properties")) != NULL) { - add_props(props, str); - pw_properties_set(props, "sink_properties", NULL); - } - if ((str = pw_properties_get(props, "device.description")) != NULL) { - pw_properties_set(props, "node.description", str); - pw_properties_set(props, "device.description", NULL); - } - pw_properties_set(props, "factory.name", "support.null-audio-sink"); - - d->props = props; - error = load_null_sink_module(o); - sync = error < 0; - } -done: - d->error = error; - if (sync) - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - struct module_info *m; - int error; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: %u", c, idx); - if ((m = find_module(c, idx)) != NULL) { - pw_proxy_destroy(m->proxy); - error = 0; - } else { - error = PA_ERR_NOENTITY; - } - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - d->error = error; - d->idx = idx; - pa_operation_sync(o); - - return o; -} - -struct client_data { - uint32_t idx; - pa_client_info_cb_t cb; - void *userdata; -}; - -static int client_callback(pa_context *c, struct client_data *d, struct global *g) -{ - d->cb(c, &g->client_info.info, 0, d->userdata); - return 0; -} - -static void client_info(pa_operation *o, void *userdata) -{ - struct client_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_CLIENT)) - g = NULL; - - if (g) { - error = client_callback(c, d, g); - } else { - error = PA_ERR_NOENTITY; - } - if (error) - pa_context_set_error(c, error); - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct client_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index:%u", c, idx); - o = pa_operation_new(c, NULL, client_info, sizeof(struct client_data)); - d = o->userdata; - d->idx = idx; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void client_info_list(pa_operation *o, void *userdata) -{ - struct client_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_CLIENT)) - continue; - client_callback(c, d, g); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct client_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p", c); - o = pa_operation_new(c, NULL, client_info_list, sizeof(struct client_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct kill_client { - uint32_t idx; - pa_context_success_cb_t cb; - void *userdata; -}; - -static void do_kill_client(pa_operation *o, void *userdata) -{ - struct kill_client *d = userdata; - pa_context *c = o->context; - struct global *g; - int error = 0; - - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_CLIENT)) - g = NULL; - - if (g) { - pw_registry_destroy(c->registry, g->id); - } else { - error = PA_ERR_NOENTITY; - } - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error ? 0 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct kill_client *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index:%u", c, idx); - o = pa_operation_new(c, NULL, do_kill_client, sizeof(struct kill_client)); - d = o->userdata; - d->idx = idx; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct card_data { - pa_card_info_cb_t cb; - pa_context_success_cb_t success_cb; - char *name; - uint32_t idx; - void *userdata; - char *profile; -}; - -static int card_callback(pa_context *c, struct card_data *d, struct global *g) -{ - pa_card_info *i = &g->card_info.info; - d->cb(c, i, 0, d->userdata); - return 0; -} - -static void card_info(pa_operation *o, void *userdata) -{ - struct card_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - if (d->name) { - g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_CARD, d->name); - pa_xfree(d->name); - } else if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_CARD)) - g = NULL; - - if (g) { - error = card_callback(c, d, g); - } else { - error = PA_ERR_NOENTITY; - } - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_card_info_by_index(pa_context *c, uint32_t idx, pa_card_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct card_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: index:%u", c, idx); - o = pa_operation_new(c, NULL, card_info, sizeof(struct card_data)); - d = o->userdata; - d->idx = idx; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_EXPORT -pa_operation* pa_context_get_card_info_by_name(pa_context *c, const char *name, pa_card_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct card_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("context %p: name:%s", c, name); - o = pa_operation_new(c, NULL, card_info, sizeof(struct card_data)); - d = o->userdata; - d->name = pa_xstrdup(name); - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -static void card_info_list(pa_operation *o, void *userdata) -{ - struct card_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_CARD)) - continue; - card_callback(c, d, g); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_card_info_list(pa_context *c, pa_card_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct card_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p", c); - o = pa_operation_new(c, NULL, card_info_list, sizeof(struct card_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void card_profile(pa_operation *o, void *userdata) -{ - struct card_data *d = userdata; - struct global *g; - pa_context *c = o->context; - int error = 0; - uint32_t id = SPA_ID_INVALID; - char buf[1024]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - struct param *p; - - if (d->name) { - g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_CARD, d->name); - pa_xfree(d->name); - } else if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_CARD)) - g = NULL; - - if (g == NULL) { - error = PA_ERR_NOENTITY; - goto done; - } - - spa_list_for_each(p, &g->card_info.profiles, link) { - uint32_t test_id; - const char *name; - - if (spa_pod_parse_object(p->param, - SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&test_id), - SPA_PARAM_PROFILE_name, SPA_POD_String(&name)) < 0) { - pw_log_warn("device %d: can't parse profile", g->id); - continue; - } - if (strcmp(name, d->profile) == 0) { - id = test_id; - break; - } - } - if (id == SPA_ID_INVALID) { - error = PA_ERR_NOENTITY; - goto done; - } - - if (!SPA_FLAG_IS_SET(g->permissions, PW_PERM_W | PW_PERM_X)) { - error = PA_ERR_ACCESS; - goto done; - } - - pw_device_set_param((struct pw_device*)g->proxy, - SPA_PARAM_Profile, 0, - spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile, - SPA_PARAM_PROFILE_index, SPA_POD_Int(id))); -done: - if (error) - pa_context_set_error(c, error); - if (d->success_cb) - d->success_cb(c, error ? 0 : 1, d->userdata); - free(d->profile); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct card_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("%p: index:%u profile:%s", c, idx, profile); - o = pa_operation_new(c, NULL, card_profile, sizeof(struct card_data)); - d = o->userdata; - d->idx = idx; - d->success_cb = cb; - d->userdata = userdata; - d->profile = strdup(profile); - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct card_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - pw_log_debug("%p: name:%s profile:%s", c, name, profile); - o = pa_operation_new(c, NULL, card_profile, sizeof(struct card_data)); - d = o->userdata; - d->name = pa_xstrdup(name); - d->success_cb = cb; - d->userdata = userdata; - d->profile = strdup(profile); - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct success_ack *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p: card_name:%s port_name:%s offset:%"PRIi64, c, card_name, port_name, offset); - o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct sink_input_data { - pa_sink_input_info_cb_t cb; - uint32_t idx; - void *userdata; -}; - -static int sink_input_callback(pa_context *c, struct sink_input_data *d, struct global *g) -{ - struct global *cl; - struct pw_node_info *info = g->info; - const char *name = NULL; - uint32_t n; - pa_sink_input_info i; - pa_format_info ii[1]; - pa_stream *s; - - if (info == NULL) - return PA_ERR_INVALID; - - s = pa_context_find_stream(c, g->id); - - if (info->props) { - if ((name = spa_dict_lookup(info->props, PW_KEY_MEDIA_NAME)) == NULL && - (name = spa_dict_lookup(info->props, PW_KEY_APP_NAME)) == NULL && - (name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)) == NULL) - name = NULL; - } - if (name == NULL) - name = "unknown"; - - cl = pa_context_find_global(c, g->node_info.client_id); - - spa_zero(i); - i.index = g->id; - i.name = name; - i.owner_module = g->id; - i.client = g->node_info.client_id; - if (s) - i.sink = s->device_index; - else - i.sink = g->node_info.device_index; - - if (s && s->sample_spec.channels > 0) { - i.sample_spec = s->sample_spec; - if (s->channel_map.channels == s->sample_spec.channels) - i.channel_map = s->channel_map; - else - pa_channel_map_init_extend(&i.channel_map, - i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - i.format = s->format; - } - else { - i.sample_spec = g->node_info.sample_spec; - if (g->node_info.n_channel_volumes) - i.sample_spec.channels = g->node_info.n_channel_volumes; - else - i.sample_spec.channels = 2; - if (i.sample_spec.channels == g->node_info.channel_map.channels) - i.channel_map = g->node_info.channel_map; - else - pa_channel_map_init_extend(&i.channel_map, - i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - ii[0].encoding = PA_ENCODING_PCM; - ii[0].plist = pa_proplist_new(); - i.format = ii; - } - pa_cvolume_init(&i.volume); - i.volume.channels = i.sample_spec.channels; - for (n = 0; n < i.volume.channels; n++) - i.volume.values[n] = pa_sw_volume_from_linear(g->node_info.volume * g->node_info.channel_volumes[n]); - - i.mute = g->node_info.mute; - i.buffer_usec = 0; - i.sink_usec = 0; - i.resample_method = "PipeWire resampler"; - i.driver = "PipeWire"; - i.proplist = pa_proplist_new_dict(info->props); - if (cl && cl->client_info.info.proplist) - pa_proplist_update(i.proplist, PA_UPDATE_MERGE, cl->client_info.info.proplist); - i.corked = false; - i.has_volume = true; - i.volume_writable = true; - - pw_log_debug("context %p: sink info for %d sink:%d", c, i.index, i.sink); - - d->cb(c, &i, 0, d->userdata); - - pa_proplist_free(i.proplist); - return 0; -} - -static void sink_input_info(pa_operation *o, void *userdata) -{ - struct sink_input_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_SINK_INPUT)) - g = NULL; - - if (g) { - error = sink_input_callback(c, d, g); - } else { - error = PA_ERR_NOENTITY; - } - if (error) - pa_context_set_error(c, error); - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sink_input_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("context %p: info for %d", c, idx); - o = pa_operation_new(c, NULL, sink_input_info, sizeof(struct sink_input_data)); - d = o->userdata; - d->idx = idx; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void sink_input_info_list(pa_operation *o, void *userdata) -{ - struct sink_input_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK_INPUT)) - continue; - sink_input_callback(c, d, g); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sink_input_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p", c); - o = pa_operation_new(c, NULL, sink_input_info_list, sizeof(struct sink_input_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct target_node { - uint32_t idx; - uint32_t mask; - uint32_t target_idx; - uint32_t target_mask; - char *target_name; - pa_context_success_cb_t cb; - void *userdata; - const char *key; -}; - -static void do_target_node(pa_operation *o, void *userdata) -{ - struct target_node *d = userdata; - pa_context *c = o->context; - struct global *g, *t; - int error = 0; - - pw_log_debug("%p", c); - - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & d->mask)) { - error = PA_ERR_NOENTITY; - goto done; - } - - if (d->target_name) { - t = pa_context_find_global_by_name(c, d->target_mask, d->target_name); - } else { - if ((t = pa_context_find_global(c, d->target_idx)) == NULL || - !(t->mask & d->target_mask)) - t = NULL; - } - if (t == NULL) { - error = PA_ERR_NOENTITY; - } else if (!SPA_FLAG_IS_SET(g->permissions, PW_PERM_M) || - (c->metadata && !SPA_FLAG_IS_SET(c->metadata->permissions, PW_PERM_W|PW_PERM_X))) { - error = PA_ERR_ACCESS; - } else if (c->metadata) { - char buf[16]; - snprintf(buf, sizeof(buf), "%d", t->id); - pw_metadata_set_property(c->metadata->proxy, - g->id, d->key, SPA_TYPE_INFO_BASE "Id", buf); - } else { - error = PA_ERR_NOTIMPLEMENTED; - } -done: - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error != 0 ? 0 : 1, d->userdata); - pa_xfree(d->target_name); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct target_node *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p: index:%u name:%s", c, idx, sink_name); - o = pa_operation_new(c, NULL, do_target_node, sizeof(struct target_node)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT; - d->target_name = pa_xstrdup(sink_name); - d->target_mask = PA_SUBSCRIPTION_MASK_SINK; - d->key = METADATA_TARGET_NODE; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct target_node *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p: index:%u sink_index:%u", c, idx, sink_idx); - o = pa_operation_new(c, NULL, do_target_node, sizeof(struct target_node)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT; - d->target_idx = sink_idx; - d->target_mask = PA_SUBSCRIPTION_MASK_SINK; - d->key = METADATA_TARGET_NODE; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct stream_volume { - uint32_t idx; - uint32_t mask; - bool have_volume; - pa_cvolume volume; - int mute; - pa_context_success_cb_t cb; - void *userdata; -}; - -static void do_stream_volume_mute(pa_operation *o, void *userdata) -{ - struct stream_volume *d = userdata; - pa_context *c = o->context; - struct global *g; - int error = 0; - pa_stream *s; - - if ((s = pa_context_find_stream(c, d->idx)) == NULL) { - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & d->mask)) - g = NULL; - } - if (s) { - error = set_stream_volume(c, s, - d->have_volume ? &d->volume : NULL, - d->have_volume ? s->mute : d->mute); - } else if (g) { - error = set_node_volume(c, g, - d->have_volume ? &d->volume : NULL, - d->have_volume ? g->node_info.mute : d->mute); - } else { - error = PA_ERR_NOENTITY; - } - - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error != 0 ? 0 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_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) -{ - pa_operation *o; - struct stream_volume *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index %d", c, idx); - o = pa_operation_new(c, NULL, do_stream_volume_mute, sizeof(struct stream_volume)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT; - d->volume = *volume; - d->have_volume = true; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct stream_volume *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index %d", c, idx); - o = pa_operation_new(c, NULL, do_stream_volume_mute, sizeof(struct stream_volume)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT; - d->mute = mute; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct kill_stream { - uint32_t idx; - uint32_t mask; - pa_context_success_cb_t cb; - void *userdata; -}; - -static void do_kill_stream(pa_operation *o, void *userdata) -{ - struct kill_stream *d = userdata; - pa_context *c = o->context; - struct global *g; - int error = 0; - pa_stream *s; - - if ((s = pa_context_find_stream(c, d->idx)) == NULL) { - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & d->mask)) - g = NULL; - } - if (s) { - pw_stream_destroy(s->stream); - } else if (g) { - pw_registry_destroy(c->registry, g->id); - } else { - error = PA_ERR_NOENTITY; - } - if (error != 0) - pa_context_set_error(c, error); - if (d->cb) - d->cb(c, error != 0 ? 0 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct kill_stream *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index %d", c, idx); - o = pa_operation_new(c, NULL, do_kill_stream, sizeof(struct kill_stream)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct source_output_data { - uint32_t idx; - pa_source_output_info_cb_t cb; - void *userdata; -}; - -static int source_output_callback(struct source_output_data *d, pa_context *c, struct global *g) -{ - struct global *cl; - struct pw_node_info *info = g->info; - const char *name = NULL; - uint32_t n; - pa_source_output_info i; - pa_format_info ii[1]; - pa_stream *s; - - pw_log_debug("index %d", g->id); - if (info == NULL) - return PA_ERR_INVALID; - - s = pa_context_find_stream(c, g->id); - - if (info->props) { - if ((name = spa_dict_lookup(info->props, PW_KEY_MEDIA_NAME)) == NULL && - (name = spa_dict_lookup(info->props, PW_KEY_APP_NAME)) == NULL && - (name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)) == NULL) - name = NULL; - } - if (name == NULL) - name = "unknown"; - - cl = pa_context_find_global(c, g->node_info.client_id); - - spa_zero(i); - i.index = g->id; - i.name = name; - i.owner_module = g->id; - i.client = g->node_info.client_id; - if (s) - i.source = s->device_index; - else - i.source = g->node_info.device_index; - if (s && s->sample_spec.channels > 0) { - i.sample_spec = s->sample_spec; - if (s->channel_map.channels == s->sample_spec.channels) - i.channel_map = s->channel_map; - else - pa_channel_map_init_extend(&i.channel_map, - i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - i.format = s->format; - } - else { - i.sample_spec = g->node_info.sample_spec; - if (g->node_info.n_channel_volumes) - i.sample_spec.channels = g->node_info.n_channel_volumes; - else - i.sample_spec.channels = 2; - if (i.sample_spec.channels == g->node_info.channel_map.channels) - i.channel_map = g->node_info.channel_map; - else - pa_channel_map_init_extend(&i.channel_map, - i.sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - ii[0].encoding = PA_ENCODING_PCM; - ii[0].plist = pa_proplist_new(); - i.format = ii; - } - pa_cvolume_init(&i.volume); - i.volume.channels = i.sample_spec.channels; - for (n = 0; n < i.volume.channels; n++) - i.volume.values[n] = pa_sw_volume_from_linear(g->node_info.volume * g->node_info.channel_volumes[n]); - - i.mute = g->node_info.mute; - i.buffer_usec = 0; - i.source_usec = 0; - i.resample_method = "PipeWire resampler"; - i.driver = "PipeWire"; - i.proplist = pa_proplist_new_dict(info->props); - if (cl && cl->client_info.info.proplist) - pa_proplist_update(i.proplist, PA_UPDATE_MERGE, cl->client_info.info.proplist); - i.corked = false; - i.has_volume = true; - i.volume_writable = true; - - d->cb(c, &i, 0, d->userdata); - - pa_proplist_free(i.proplist); - return 0; -} - -static void source_output_info(pa_operation *o, void *userdata) -{ - struct source_output_data *d = userdata; - pa_context *c = o->context; - struct global *g; - int error; - - if ((g = pa_context_find_global(c, d->idx)) == NULL || - !(g->mask & PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT)) - g = NULL; - - if (g) { - error = source_output_callback(d, c, g); - } else { - error = PA_ERR_NOENTITY; - } - if (error) - pa_context_set_error(c, error); - d->cb(c, NULL, error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct source_output_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - pw_log_debug("%p: index:%u", c, idx); - o = pa_operation_new(c, NULL, source_output_info, sizeof(struct source_output_data)); - d = o->userdata; - d->idx = idx; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -static void source_output_info_list(pa_operation *o, void *userdata) -{ - struct source_output_data *d = userdata; - pa_context *c = o->context; - struct global *g; - - spa_list_for_each(g, &c->globals, link) { - if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT)) - continue; - source_output_callback(d, c, g); - } - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct source_output_data *d; - - pa_assert(c); - pa_assert(c->refcount >= 1); - pa_assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p", c); - o = pa_operation_new(c, NULL, source_output_info_list, sizeof(struct source_output_data)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct target_node *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p index:%u name:%s", c, idx, source_name); - o = pa_operation_new(c, NULL, do_target_node, sizeof(struct target_node)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT; - d->target_name = pa_xstrdup(source_name); - d->target_mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->key = METADATA_TARGET_NODE; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct target_node *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p index:%u source_index:%u", c, idx, source_idx); - o = pa_operation_new(c, NULL, do_target_node, sizeof(struct target_node)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT; - d->target_idx = source_idx; - d->target_mask = PA_SUBSCRIPTION_MASK_SOURCE; - d->key = METADATA_TARGET_NODE; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct stream_volume *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index %d", c, idx); - o = pa_operation_new(c, NULL, do_stream_volume_mute, sizeof(struct stream_volume)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT; - d->volume = *volume; - d->have_volume = true; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pa_operation *o; - struct stream_volume *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index %d", c, idx); - o = pa_operation_new(c, NULL, do_stream_volume_mute, sizeof(struct stream_volume)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT; - d->mute = mute; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct kill_stream *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("context %p: index %d", c, idx); - o = pa_operation_new(c, NULL, do_kill_stream, sizeof(struct kill_stream)); - d = o->userdata; - d->idx = idx; - d->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct stat_ack { - pa_stat_info_cb_t cb; - int error; - void *userdata; -}; - -static void on_stat_info(pa_operation *o, void *userdata) -{ - struct stat_ack *d = userdata; - pa_context *c = o->context; - pa_stat_info i; - spa_zero(i); - if (d->error != 0) - pa_context_set_error(c, d->error); - if (d->cb) - d->cb(c, &i, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct stat_ack *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p", c); - o = pa_operation_new(c, NULL, on_stat_info, sizeof(struct stat_ack)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -struct sample_info { - pa_sample_info_cb_t cb; - int error; - void *userdata; -}; - -static void on_sample_info(pa_operation *o, void *userdata) -{ - struct sample_info *d = userdata; - pa_context *c = o->context; - if (d->error != 0) - pa_context_set_error(c, d->error); - if (d->cb) - d->cb(c, NULL, d->error ? -1 : 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sample_info *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p nane:%s", c, name); - o = pa_operation_new(c, NULL, on_sample_info, sizeof(struct sample_info)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sample_info *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p index:%u", c, idx); - o = pa_operation_new(c, NULL, on_sample_info, sizeof(struct sample_info)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - - -static void on_sample_info_list(pa_operation *o, void *userdata) -{ - struct sample_info *d = userdata; - pa_context *c = o->context; - if (d->error != 0) - pa_context_set_error(c, d->error); - if (d->cb) - d->cb(c, NULL, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata) -{ - pa_operation *o; - struct sample_info *d; - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("%p", c); - o = pa_operation_new(c, NULL, on_sample_info_list, sizeof(struct sample_info)); - d = o->userdata; - d->cb = cb; - d->error = PA_ERR_NOTIMPLEMENTED; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_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) -{ - pw_log_warn("Deprecated: Not Implemented"); - return NULL; -} - -SPA_EXPORT -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) -{ - pw_log_warn("Deprecated: Not Implemented"); - return NULL; -} - -SPA_EXPORT -pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) -{ - pw_log_warn("Deprecated: Not Implemented"); - return NULL; -} - -SPA_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) -{ - pw_log_warn("Deprecated: Not Implemented"); - return NULL; -} - -SPA_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) -{ - pw_log_warn("Deprecated: Not Implemented"); - return NULL; -} - -SPA_EXPORT -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) -{ - pw_log_warn("Deprecated: Not Implemented"); - return NULL; -} diff --git a/pipewire-pulseaudio/src/json.c b/pipewire-pulseaudio/src/json.c deleted file mode 100644 index 8704264b0..000000000 --- a/pipewire-pulseaudio/src/json.c +++ /dev/null @@ -1,659 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2016 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "internal.h" -#include "json.h" -#include "strbuf.h" - -#define MAX_NESTING_DEPTH 20 /* Arbitrary number to make sure we don't have a stack overflow */ - -typedef struct pa_json_item { - char *key; - pa_json_object *value; -} pa_json_item; - -struct pa_json_object { - pa_json_type type; - - union { - int int_value; - double double_value; - bool bool_value; - char *string_value; - struct pw_array values; /* objects */ - }; -}; - -static void clear_array(struct pw_array *array) -{ - pa_json_object **value; - pw_array_for_each(value, array) - pa_json_object_free(*value); - pw_array_clear(array); -} - -static void clear_item(pa_json_item *item) -{ - free(item->key); - pa_json_object_free(item->value); -} - -static void clear_object(struct pw_array *array) -{ - pa_json_item *item; - pw_array_for_each(item, array) - clear_item(item); - pw_array_clear(array); -} - -static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth); - -static pa_json_object* json_object_new(void) { - pa_json_object *obj; - - obj = pa_xnew0(pa_json_object, 1); - - return obj; -} - -static bool is_whitespace(char c) { - return c == '\t' || c == '\n' || c == '\r' || c == ' '; -} - -static bool is_digit(char c) { - return c >= '0' && c <= '9'; -} - -static bool is_end(const char c, const char *end) { - if (!end) - return c == '\0'; - else { - while (*end) { - if (c == *end) - return true; - end++; - } - } - - return false; -} - -static const char* consume_string(const char *str, const char *expect) { - while (*expect) { - if (*str != *expect) - return NULL; - - str++; - expect++; - } - - return str; -} - -static const char* parse_null(const char *str, pa_json_object *obj) { - str = consume_string(str, "null"); - - if (str) - obj->type = PA_JSON_TYPE_NULL; - - return str; -} - -static const char* parse_boolean(const char *str, pa_json_object *obj) { - const char *tmp; - - tmp = consume_string(str, "true"); - - if (tmp) { - obj->type = PA_JSON_TYPE_BOOL; - obj->bool_value = true; - } else { - tmp = consume_string(str, "false"); - - if (str) { - obj->type = PA_JSON_TYPE_BOOL; - obj->bool_value = false; - } - } - - return tmp; -} - -static const char* parse_string(const char *str, pa_json_object *obj) { - pa_strbuf *buf = pa_strbuf_new(); - - str++; /* Consume leading '"' */ - - while (*str && *str != '"') { - if (*str != '\\') { - /* We only accept ASCII printable characters. */ - if (*str < 0x20 || *str > 0x7E) { - pa_log("Invalid non-ASCII character: 0x%x", (unsigned int) *str); - goto error; - } - - /* Normal character, juts consume */ - pa_strbuf_putc(buf, *str); - } else { - /* Need to unescape */ - str++; - - switch (*str) { - case '"': - case '\\': - case '/': - pa_strbuf_putc(buf, *str); - break; - - case 'b': - pa_strbuf_putc(buf, '\b' /* backspace */); - break; - - case 'f': - pa_strbuf_putc(buf, '\f' /* form feed */); - break; - - case 'n': - pa_strbuf_putc(buf, '\n' /* new line */); - break; - - case 'r': - pa_strbuf_putc(buf, '\r' /* carriage return */); - break; - - case 't': - pa_strbuf_putc(buf, '\t' /* horizontal tab */); - break; - - case 'u': - pa_log("Unicode code points are currently unsupported"); - goto error; - - default: - pa_log("Unexpected escape value: %c", *str); - goto error; - } - } - - str++; - } - - if (*str != '"') { - pa_log("Failed to parse remainder of string: %s", str); - goto error; - } - - str++; - - obj->type = PA_JSON_TYPE_STRING; - obj->string_value = pa_strbuf_to_string_free(buf); - - return str; - -error: - pa_strbuf_free(buf); - return NULL; -} - -static const char* parse_number(const char *str, pa_json_object *obj) { - bool negative = false, has_fraction = false, has_exponent = false, valid = false; - unsigned int integer = 0; - unsigned int fraction = 0; - unsigned int fraction_digits = 0; - int exponent = 0; - - if (*str == '-') { - negative = true; - str++; - } - - if (*str == '0') { - valid = true; - str++; - goto fraction; - } - - while (is_digit(*str)) { - valid = true; - - if (integer > ((negative ? INT_MAX : UINT_MAX) / 10)) { - pa_log("Integer overflow while parsing number"); - goto error; - } - - integer = (integer * 10) + (*str - '0'); - str++; - } - -fraction: - - if (!valid) { - pa_log("Missing digits while parsing number"); - goto error; - } - - if (*str == '.') { - has_fraction = true; - str++; - valid = false; - - while (is_digit(*str)) { - valid = true; - - if (fraction > (UINT_MAX / 10)) { - pa_log("Integer overflow while parsing fractional part of number"); - goto error; - } - - fraction = (fraction * 10) + (*str - '0'); - fraction_digits++; - str++; - } - - if (!valid) { - pa_log("No digit after '.' while parsing fraction"); - goto error; - } - } - - if (*str == 'e' || *str == 'E') { - bool exponent_negative = false; - - has_exponent = true; - str++; - valid = false; - - if (*str == '-') { - exponent_negative = true; - str++; - } else if (*str == '+') - str++; - - while (is_digit(*str)) { - valid = true; - - if (exponent > (INT_MAX / 10)) { - pa_log("Integer overflow while parsing exponent part of number"); - goto error; - } - - exponent = (exponent * 10) + (*str - '0'); - str++; - } - - if (!valid) { - pa_log("No digit in exponent while parsing fraction"); - goto error; - } - - if (exponent_negative) - exponent *= -1; - } - - if (has_fraction || has_exponent) { - obj->type = PA_JSON_TYPE_DOUBLE; - obj->double_value = - (negative ? -1.0 : 1.0) * (integer + (double) fraction / pow(10, fraction_digits)) * pow(10, exponent); - } else { - obj->type = PA_JSON_TYPE_INT; - obj->int_value = (negative ? -1 : 1) * integer; - } - - return str; - -error: - return NULL; -} - -static const char *parse_object(const char *str, pa_json_object *obj, unsigned int depth) { - pa_json_object *name = NULL, *value = NULL; - pa_json_item *item; - - obj->values = PW_ARRAY_INIT(64); - - while (*str != '}') { - str++; /* Consume leading '{' or ',' */ - - str = parse_value(str, ":", &name, depth + 1); - if (!str || pa_json_object_get_type(name) != PA_JSON_TYPE_STRING) { - pa_log("Could not parse key for object"); - goto error; - } - - /* Consume the ':' */ - str++; - - str = parse_value(str, ",}", &value, depth + 1); - if (!str) { - pa_log("Could not parse value for object"); - goto error; - } - - item = pw_array_add(&obj->values, sizeof(pa_json_item)); - item->key = strdup(pa_json_object_get_string(name)); - item->value = value; - pa_json_object_free(name); - - name = NULL; - value = NULL; - } - - /* Drop trailing '}' */ - str++; - - /* We now know the value was correctly parsed */ - obj->type = PA_JSON_TYPE_OBJECT; - - return str; - -error: - clear_object(&obj->values); - - if (name) - pa_json_object_free(name); - if (value) - pa_json_object_free(value); - - return NULL; -} - -static const char *parse_array(const char *str, pa_json_object *obj, unsigned int depth) { - pa_json_object *value; - - obj->values = PW_ARRAY_INIT(64); - - while (*str != ']') { - str++; /* Consume leading '[' or ',' */ - - /* Need to chew up whitespaces as a special case to deal with the - * possibility of an empty array */ - while (is_whitespace(*str)) - str++; - - if (*str == ']') - break; - - str = parse_value(str, ",]", &value, depth + 1); - if (!str) { - pa_log("Could not parse value for array"); - goto error; - } - - pw_array_add_ptr(&obj->values, value); - } - - /* Drop trailing ']' */ - str++; - - /* We now know the value was correctly parsed */ - obj->type = PA_JSON_TYPE_ARRAY; - - return str; - -error: - clear_array(&obj->values); - return NULL; -} - -typedef enum { - JSON_PARSER_STATE_INIT, - JSON_PARSER_STATE_FINISH, -} json_parser_state; - -static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth) { - json_parser_state state = JSON_PARSER_STATE_INIT; - pa_json_object *o; - - pa_assert(str != NULL); - - o = json_object_new(); - - if (depth > MAX_NESTING_DEPTH) { - pa_log("Exceeded maximum permitted nesting depth of objects (%u)", MAX_NESTING_DEPTH); - goto error; - } - - while (!is_end(*str, end)) { - switch (state) { - case JSON_PARSER_STATE_INIT: - if (is_whitespace(*str)) { - str++; - } else if (*str == 'n') { - str = parse_null(str, o); - state = JSON_PARSER_STATE_FINISH; - } else if (*str == 't' || *str == 'f') { - str = parse_boolean(str, o); - state = JSON_PARSER_STATE_FINISH; - } else if (*str == '"') { - str = parse_string(str, o); - state = JSON_PARSER_STATE_FINISH; - } else if (is_digit(*str) || *str == '-') { - str = parse_number(str, o); - state = JSON_PARSER_STATE_FINISH; - } else if (*str == '{') { - str = parse_object(str, o, depth); - state = JSON_PARSER_STATE_FINISH; - } else if (*str == '[') { - str = parse_array(str, o, depth); - state = JSON_PARSER_STATE_FINISH; - } else { - pa_log("Invalid JSON string: %s", str); - goto error; - } - - if (!str) - goto error; - - break; - - case JSON_PARSER_STATE_FINISH: - /* Consume trailing whitespaces */ - if (is_whitespace(*str)) { - str++; - } else { - goto error; - } - } - } - - if (pa_json_object_get_type(o) == PA_JSON_TYPE_INIT) { - /* We didn't actually get any data */ - pa_log("No data while parsing json string: '%s' till '%s'", str, pa_strnull(end)); - goto error; - } - - *obj = o; - - return str; - -error: - pa_json_object_free(o); - return NULL; -} - - -SPA_EXPORT -pa_json_object* pa_json_parse(const char *str) { - pa_json_object *obj; - - str = parse_value(str, NULL, &obj, 0); - - if (!str) { - pa_log("JSON parsing failed"); - return NULL; - } - - if (*str != '\0') { - pa_log("Unable to parse complete JSON string, remainder is: %s", str); - pa_json_object_free(obj); - return NULL; - } - - return obj; -} - -SPA_EXPORT -pa_json_type pa_json_object_get_type(const pa_json_object *obj) { - return obj->type; -} - -SPA_EXPORT -void pa_json_object_free(pa_json_object *obj) { - - switch (pa_json_object_get_type(obj)) { - case PA_JSON_TYPE_INIT: - case PA_JSON_TYPE_INT: - case PA_JSON_TYPE_DOUBLE: - case PA_JSON_TYPE_BOOL: - case PA_JSON_TYPE_NULL: - break; - - case PA_JSON_TYPE_STRING: - pa_xfree(obj->string_value); - break; - - case PA_JSON_TYPE_OBJECT: - clear_object(&obj->values); - break; - - case PA_JSON_TYPE_ARRAY: - clear_array(&obj->values); - break; - - default: - pa_assert_not_reached(); - } - - pa_xfree(obj); -} - -SPA_EXPORT -int pa_json_object_get_int(const pa_json_object *o) { - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_INT); - return o->int_value; -} - -SPA_EXPORT -double pa_json_object_get_double(const pa_json_object *o) { - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_DOUBLE); - return o->double_value; -} - -SPA_EXPORT -bool pa_json_object_get_bool(const pa_json_object *o) { - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_BOOL); - return o->bool_value; -} - -SPA_EXPORT -const char* pa_json_object_get_string(const pa_json_object *o) { - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_STRING); - return o->string_value; -} - -SPA_EXPORT -const pa_json_object* pa_json_object_get_object_member(const pa_json_object *o, const char *name) { - pa_json_item *item; - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_OBJECT); - pw_array_for_each(item, &o->values) { - if (pa_streq(item->key, name)) - return item->value; - } - return NULL; -} - -SPA_EXPORT -int pa_json_object_get_array_length(const pa_json_object *o) { - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_ARRAY); - return pw_array_get_len(&o->values, const pa_json_object*); -} - -SPA_EXPORT -const pa_json_object* pa_json_object_get_array_member(const pa_json_object *o, int index) { - pa_assert(pa_json_object_get_type(o) == PA_JSON_TYPE_ARRAY); - return pw_array_get_unchecked_s(&o->values, index, sizeof(pa_json_object*), - const pa_json_object); -} - -SPA_EXPORT -bool pa_json_object_equal(const pa_json_object *o1, const pa_json_object *o2) { - int i; - - if (pa_json_object_get_type(o1) != pa_json_object_get_type(o2)) - return false; - - switch (pa_json_object_get_type(o1)) { - case PA_JSON_TYPE_NULL: - return true; - - case PA_JSON_TYPE_BOOL: - return o1->bool_value == o2->bool_value; - - case PA_JSON_TYPE_INT: - return o1->int_value == o2->int_value; - - case PA_JSON_TYPE_DOUBLE: - return PA_DOUBLE_IS_EQUAL(o1->double_value, o2->double_value); - - case PA_JSON_TYPE_STRING: - return pa_streq(o1->string_value, o2->string_value); - - case PA_JSON_TYPE_ARRAY: - if (pa_json_object_get_array_length(o1) != pa_json_object_get_array_length(o2)) - return false; - - for (i = 0; i < pa_json_object_get_array_length(o1); i++) { - if (!pa_json_object_equal(pa_json_object_get_array_member(o1, i), - pa_json_object_get_array_member(o2, i))) - return false; - } - - return true; - - case PA_JSON_TYPE_OBJECT: { - const pa_json_object *value; - const pa_json_item *item; - - if (o1->values.size != o2->values.size) - return false; - - pw_array_for_each(item, &o1->values) { - value = pa_json_object_get_object_member(o2, item->key); - if (!value || !pa_json_object_equal(item->value, value)) - return false; - } - - return true; - } - - default: - pa_assert_not_reached(); - } -} diff --git a/pipewire-pulseaudio/src/json.h b/pipewire-pulseaudio/src/json.h deleted file mode 100644 index 7759bf2db..000000000 --- a/pipewire-pulseaudio/src/json.h +++ /dev/null @@ -1,53 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2016 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, see . -***/ - -#include - -#define PA_DOUBLE_IS_EQUAL(x, y) (((x) - (y)) < 0.000001 && ((x) - (y)) > -0.000001) - -typedef enum { - PA_JSON_TYPE_INIT = 0, - PA_JSON_TYPE_NULL, - PA_JSON_TYPE_INT, - PA_JSON_TYPE_DOUBLE, - PA_JSON_TYPE_BOOL, - PA_JSON_TYPE_STRING, - PA_JSON_TYPE_ARRAY, - PA_JSON_TYPE_OBJECT, -} pa_json_type; - -typedef struct pa_json_object pa_json_object; - -pa_json_object* pa_json_parse(const char *str); -pa_json_type pa_json_object_get_type(const pa_json_object *obj); -void pa_json_object_free(pa_json_object *obj); - -/* All pointer members that are returned are valid while the corresponding object is valid */ - -int pa_json_object_get_int(const pa_json_object *o); -double pa_json_object_get_double(const pa_json_object *o); -bool pa_json_object_get_bool(const pa_json_object *o); -const char* pa_json_object_get_string(const pa_json_object *o); - -const pa_json_object* pa_json_object_get_object_member(const pa_json_object *o, const char *name); - -int pa_json_object_get_array_length(const pa_json_object *o); -const pa_json_object* pa_json_object_get_array_member(const pa_json_object *o, int index); - -bool pa_json_object_equal(const pa_json_object *o1, const pa_json_object *o2); diff --git a/pipewire-pulseaudio/src/mainloop-glib.c b/pipewire-pulseaudio/src/mainloop-glib.c deleted file mode 100644 index 7295256e0..000000000 --- a/pipewire-pulseaudio/src/mainloop-glib.c +++ /dev/null @@ -1,122 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include -#include - -#include -#include - -#include "internal.h" - -struct source { - GSource base; - struct pw_loop *loop; -}; - -struct pa_glib_mainloop { - GMainContext *context; - pa_mainloop *loop; - struct source *source; - guint id; -}; - -static gboolean source_prepare (GSource *base, int *timeout) -{ - *timeout = -1; - return FALSE; -} - -static gboolean source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) -{ - struct source *s = (struct source *) source; - int result; - - pw_loop_enter (s->loop); - do { - result = pw_loop_iterate (s->loop, 0); - } while (result == -EINTR); - pw_loop_leave (s->loop); - - if (result < 0) - g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result)); - - return TRUE; -} - -static GSourceFuncs source_funcs = -{ - source_prepare, - NULL, - source_dispatch, - NULL, - NULL, - NULL, -}; - -SPA_EXPORT -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) -{ - - pa_glib_mainloop *loop; - - loop = calloc(1, sizeof(pa_glib_mainloop)); - if (loop == NULL) - goto error; - - loop->context = c; - loop->loop = pa_mainloop_new(); - if (loop->loop == NULL) - goto error_free; - - loop->source = (struct source *) g_source_new(&source_funcs, sizeof(struct source)); - loop->source->loop = loop->loop->loop; - - g_source_add_unix_fd (&loop->source->base, - pw_loop_get_fd(loop->source->loop), - G_IO_IN | G_IO_ERR); - - loop->id = g_source_attach (&loop->source->base, loop->context); - - return loop; - - error_free: - free(loop); - error: - return NULL; - -} - -SPA_EXPORT -void pa_glib_mainloop_free(pa_glib_mainloop* g) -{ - g_source_destroy(&g->source->base); - pa_mainloop_free(g->loop); - free(g); -} - -SPA_EXPORT -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) -{ - return pa_mainloop_get_api(g->loop); -} diff --git a/pipewire-pulseaudio/src/mainloop-signal.c b/pipewire-pulseaudio/src/mainloop-signal.c deleted file mode 100644 index 19fe31225..000000000 --- a/pipewire-pulseaudio/src/mainloop-signal.c +++ /dev/null @@ -1,116 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include -#include - -#include -#include - -#include - -#include "internal.h" - - -static pa_mainloop_api *api = NULL; -static bool have_signals = false; -static struct spa_list signals; -static struct pw_loop *loop = NULL; - -struct pa_signal_event { - struct spa_list link; - struct spa_source *source; - pa_signal_cb_t callback; - pa_signal_destroy_cb_t destroy; - void *userdata; -}; - -SPA_EXPORT -int pa_signal_init(pa_mainloop_api *a) -{ - pa_assert(a); - pa_assert(!api); - - api = a; - spa_list_init(&signals); - loop = a->userdata; - - return 0; -} - -SPA_EXPORT -void pa_signal_done(void) -{ - pa_signal_event *ev; - - if (have_signals) { - spa_list_consume(ev, &signals, link) - pa_signal_free(ev); - } - api = NULL; -} - -static void source_signal_func (void *data, int signal_number) -{ - pa_signal_event *ev = data; - if (ev->callback) - ev->callback(api, ev, signal_number, ev->userdata); -} - -SPA_EXPORT -pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t callback, void *userdata) -{ - pa_signal_event *ev; - - pa_assert(sig > 0); - pa_assert(callback); - - ev = calloc(1, sizeof(pa_signal_event)); - ev->source = spa_loop_utils_add_signal(loop->utils, sig, source_signal_func, ev); - ev->callback = callback; - ev->userdata = userdata; - - if (!have_signals) - spa_list_init(&signals); - have_signals = true; - spa_list_append(&signals, &ev->link); - - return ev; -} - -SPA_EXPORT -void pa_signal_free(pa_signal_event *e) -{ - pa_assert(e); - - spa_list_remove(&e->link); - spa_loop_utils_destroy_source(loop->utils, e->source); - if (e->destroy) - e->destroy(api, e, e->userdata); - free(e); -} - -SPA_EXPORT -void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t callback) -{ - pa_assert(e); - e->destroy = callback; -} diff --git a/pipewire-pulseaudio/src/mainloop.c b/pipewire-pulseaudio/src/mainloop.c deleted file mode 100644 index f19257488..000000000 --- a/pipewire-pulseaudio/src/mainloop.c +++ /dev/null @@ -1,499 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include -#include - -#include -#include - -#include -#include -#include - -#include "internal.h" - -static void do_stop(void *data, uint64_t count) -{ - struct pa_mainloop *this = data; - this->quit = true; -} - -static uint32_t map_flags_to_spa(pa_io_event_flags_t flags) { - return (uint32_t) - ((flags & PA_IO_EVENT_INPUT ? SPA_IO_IN : 0) | - (flags & PA_IO_EVENT_OUTPUT ? SPA_IO_OUT : 0) | - (flags & PA_IO_EVENT_ERROR ? SPA_IO_ERR : 0) | - (flags & PA_IO_EVENT_HANGUP ? SPA_IO_HUP : 0)); -} - -static pa_io_event_flags_t map_flags_from_spa(uint32_t flags) { - return (flags & SPA_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (flags & SPA_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (flags & SPA_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (flags & SPA_IO_HUP ? PA_IO_EVENT_HANGUP : 0); -} - -static void source_io_func(void *data, int fd, uint32_t mask) -{ - pa_io_event *ev = data; - if (ev->cb) - ev->cb(&ev->mainloop->api, ev, ev->fd, map_flags_from_spa(mask), ev->userdata); -} - -static pa_io_event* api_io_new(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) -{ - pa_mainloop *mainloop = SPA_CONTAINER_OF(a, pa_mainloop, api); - pa_io_event *ev; - - pa_assert(a); - pa_assert(fd >= 0); - pa_assert(cb); - - ev = calloc(1, sizeof(pa_io_event)); - ev->source = pw_loop_add_io(mainloop->loop, fd, - map_flags_to_spa(events), false, source_io_func, ev); - ev->fd = fd; - ev->events = events; - ev->mainloop = mainloop; - ev->cb = cb; - ev->userdata = userdata; - pw_log_debug("new io %p %p %08x", ev, ev->source, events); - - return ev; -} - -static void api_io_enable(pa_io_event* e, pa_io_event_flags_t events) -{ - pa_assert(e); - - if (e->events == events || e->source == NULL) - return; - - pw_log_debug("io %p", e); - e->events = events; - pw_loop_update_io(e->mainloop->loop, e->source, map_flags_to_spa(events)); -} - -static void api_io_free(pa_io_event* e) -{ - pa_assert(e); - pw_log_debug("io %p", e); - if (e->source) - pw_loop_destroy_source(e->mainloop->loop, e->source); - if (e->destroy) - e->destroy(&e->mainloop->api, e, e->userdata); - free(e); -} - -static void api_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) -{ - pa_assert(e); - e->destroy = cb; -} - -static void source_timer_func(void *data, uint64_t expirations) -{ - pa_time_event *ev = data; - struct timeval tv; - if (ev->cb) - ev->cb(&ev->mainloop->api, ev, &tv, ev->userdata); -} - -static void set_timer(pa_time_event *ev, const struct timeval *tv) -{ - pa_mainloop *mainloop = ev->mainloop; - struct timespec ts; - - if (tv == NULL) { - ts.tv_sec = 0; - ts.tv_nsec = 1; - } else { - struct timeval ttv = *tv; - - if ((ttv.tv_usec & PA_TIMEVAL_RTCLOCK) != 0) - ttv.tv_usec &= ~PA_TIMEVAL_RTCLOCK; - else - pa_rtclock_from_wallclock(&ttv); - - /* something strange, probably not wallclock time, try to - * use the timeval directly */ - if (ttv.tv_sec == 0 && ttv.tv_usec == 0) - ttv = *tv; - - ts.tv_sec = ttv.tv_sec; - ts.tv_nsec = ttv.tv_usec * SPA_NSEC_PER_USEC; - - /* make sure we never disable the timer */ - if (ts.tv_sec == 0 && ts.tv_nsec == 0) - ts.tv_nsec++; - } - pw_log_debug("set timer %p %ld %ld", ev, ts.tv_sec, ts.tv_nsec); - pw_loop_update_timer(mainloop->loop, ev->source, &ts, NULL, true); -} - -static pa_time_event* api_time_new(pa_mainloop_api*a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) -{ - pa_mainloop *mainloop = SPA_CONTAINER_OF(a, pa_mainloop, api); - pa_time_event *ev; - - ev = calloc(1, sizeof(pa_time_event)); - ev->source = pw_loop_add_timer(mainloop->loop, source_timer_func, ev); - ev->mainloop = mainloop; - ev->cb = cb; - ev->userdata = userdata; - pw_log_debug("new timer %p", ev); - - set_timer(ev, tv); - - return ev; -} - -static void api_time_restart(pa_time_event* e, const struct timeval *tv) -{ - pa_assert(e); - set_timer(e, tv); -} - -static void api_time_free(pa_time_event* e) -{ - pa_assert(e); - pw_log_debug("io %p", e); - pw_loop_destroy_source(e->mainloop->loop, e->source); - if (e->destroy) - e->destroy(&e->mainloop->api, e, e->userdata); - free(e); -} - -static void api_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) -{ - pa_assert(e); - e->destroy = cb; -} - -static void source_idle_func(void *data) -{ - pa_defer_event *ev = data; - if (ev->cb) - ev->cb(&ev->mainloop->api, ev, ev->userdata); -} - -static pa_defer_event* api_defer_new(pa_mainloop_api*a, pa_defer_event_cb_t cb, void *userdata) -{ - pa_mainloop *mainloop = SPA_CONTAINER_OF(a, pa_mainloop, api); - pa_defer_event *ev; - - pa_assert(a); - pa_assert(cb); - - ev = calloc(1, sizeof(pa_defer_event)); - ev->source = pw_loop_add_idle(mainloop->loop, true, source_idle_func, ev); - ev->mainloop = mainloop; - ev->cb = cb; - ev->userdata = userdata; - pw_log_debug("new defer %p", ev); - - return ev; -} - -static void api_defer_enable(pa_defer_event* e, int b) -{ - pa_assert(e); - pw_loop_enable_idle(e->mainloop->loop, e->source, b ? true : false); -} - -static void api_defer_free(pa_defer_event* e) -{ - pa_assert(e); - pw_log_debug("io %p", e); - pw_loop_destroy_source(e->mainloop->loop, e->source); - if (e->destroy) - e->destroy(&e->mainloop->api, e, e->userdata); - free(e); -} - -static void api_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) -{ - pa_assert(e); - e->destroy = cb; -} - -static void api_quit(pa_mainloop_api*a, int retval) -{ - pa_mainloop *m = SPA_CONTAINER_OF(a, pa_mainloop, api); - m->quit = true; - m->retval = retval; - pa_mainloop_wakeup(m); -} - -static const pa_mainloop_api api = -{ - .io_new = api_io_new, - .io_enable = api_io_enable, - .io_free = api_io_free, - .io_set_destroy = api_io_set_destroy, - - .time_new = api_time_new, - .time_restart = api_time_restart, - .time_free = api_time_free, - .time_set_destroy = api_time_set_destroy, - - .defer_new = api_defer_new, - .defer_enable = api_defer_enable, - .defer_free = api_defer_free, - .defer_set_destroy = api_defer_set_destroy, - - .quit = api_quit, -}; - -SPA_EXPORT -pa_mainloop *pa_mainloop_new(void) -{ - pa_mainloop *loop; - - if (getenv("PULSE_INTERNAL")) - return NULL; - - loop = calloc(1, sizeof(pa_mainloop)); - if (loop == NULL) - return NULL; - - loop->loop = pw_loop_new(NULL); - if (loop->loop == NULL) - goto no_loop; - - loop->fd = pw_loop_get_fd(loop->loop); - loop->event = pw_loop_add_event(loop->loop, do_stop, loop); - loop->api = api; - loop->api.userdata = loop->loop; - - pw_log_debug("%p: %p fd:%d", loop, loop->loop, loop->fd); - - return loop; - - no_loop: - free(loop); - return NULL; -} - -bool pa_mainloop_api_is_our_api(pa_mainloop_api *api) -{ - pa_assert(api); - return api->io_new == api_io_new; -} - -SPA_EXPORT -void pa_mainloop_free(pa_mainloop* m) -{ - pw_log_debug("%p", m); - pw_loop_destroy(m->loop); - free(m); -} - -SPA_EXPORT -int pa_mainloop_prepare(pa_mainloop *m, int timeout) -{ - if (m->quit) - return -2; - m->timeout = timeout; - m->n_events = -EIO; - return 0; -} - -static int usec_to_timeout(pa_usec_t u) -{ - if (u == PA_USEC_INVALID) - return -1; - return (u + PA_USEC_PER_MSEC - 1) / PA_USEC_PER_MSEC; -} - -/** Execute the previously prepared poll. Returns a negative value on error.*/ -SPA_EXPORT -int pa_mainloop_poll(pa_mainloop *m) -{ - int res, timeout; - bool do_iterate; - - if (m->quit) - return -2; - - if (m->poll_func) { - struct pollfd fds[1]; - - fds[0].fd = m->fd; - fds[0].events = POLLIN; - fds[0].revents = 0; - - do { - res = m->poll_func(fds, 1, - usec_to_timeout(m->timeout), - m->poll_func_userdata); - } while (res == -EINTR); - do_iterate = res == 1 && SPA_FLAG_IS_SET(fds[0].revents, POLLIN); - timeout = 0; - } else { - do_iterate = true; - timeout = m->timeout; - } - - if (do_iterate) { - pw_loop_enter(m->loop); - do { - res = pw_loop_iterate(m->loop, timeout); - } while (res == -EINTR); - pw_loop_leave(m->loop); - } - m->n_events = res; - return res; -} - -SPA_EXPORT -int pa_mainloop_dispatch(pa_mainloop *m) -{ - if (m->quit) - return -2; - - return m->n_events; -} - -SPA_EXPORT -int pa_mainloop_get_retval(PA_CONST pa_mainloop *m) -{ - return m->retval; -} - -/** 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. */ -SPA_EXPORT -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) -{ - int r; - pa_assert(m); - - if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) - goto quit; - - if ((r = pa_mainloop_poll(m)) < 0) - goto quit; - - if ((r = pa_mainloop_dispatch(m)) < 0) - goto quit; - - return r; - - quit: - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; -} - -SPA_EXPORT -int pa_mainloop_run(pa_mainloop *m, int *retval) -{ - int r; - - while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0) - ; - - if (r == -2) - return 1; - else - return -1; -} - - -SPA_EXPORT -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop *m) -{ - pa_assert(m); - return &m->api; -} - -SPA_EXPORT -void pa_mainloop_quit(pa_mainloop *m, int retval) -{ - pa_assert(m); - m->api.quit(&m->api, retval); -} - -SPA_EXPORT -void pa_mainloop_wakeup(pa_mainloop *m) -{ - pa_assert(m); - pw_loop_signal_event(m->loop, m->event); -} - -SPA_EXPORT -void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) -{ - pa_assert(m); - m->poll_func = poll_func; - m->poll_func_userdata = userdata; -} - -struct once_info { - void (*callback)(pa_mainloop_api*m, void *userdata); - void *userdata; -}; - -static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - - pa_assert(m); - pa_assert(i); - - pa_assert(i->callback); - i->callback(m, i->userdata); - - pa_assert(m->defer_free); - m->defer_free(e); -} - -static void free_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - - pa_assert(m); - pa_assert(i); - pa_xfree(i); -} - - -SPA_EXPORT -void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { - struct once_info *i; - pa_defer_event *e; - - pa_assert(m); - pa_assert(callback); - - pa_init_i18n(); - - i = pa_xnew(struct once_info, 1); - i->callback = callback; - i->userdata = userdata; - - pa_assert(m->defer_new); - pa_assert_se(e = m->defer_new(m, once_callback, i)); - m->defer_set_destroy(e, free_callback); -} - diff --git a/pipewire-pulseaudio/src/map-file b/pipewire-pulseaudio/src/map-file deleted file mode 100644 index 9b6cba223..000000000 --- a/pipewire-pulseaudio/src/map-file +++ /dev/null @@ -1,386 +0,0 @@ -PULSE_0 { -global: -pa_ascii_filter; -pa_ascii_valid; -pa_bytes_per_second; -pa_bytes_snprint; -pa_bytes_to_usec; -pa_channel_map_can_balance; -pa_channel_map_can_fade; -pa_channel_map_can_lfe_balance; -pa_channel_map_compatible; -pa_channel_map_equal; -pa_channel_map_has_position; -pa_channel_map_init; -pa_channel_map_init_auto; -pa_channel_map_init_extend; -pa_channel_map_init_mono; -pa_channel_map_init_stereo; -pa_channel_map_mask; -pa_channel_map_parse; -pa_channel_map_snprint; -pa_channel_map_superset; -pa_channel_map_to_name; -pa_channel_map_to_pretty_name; -pa_channel_map_valid; -pa_channel_position_from_string; -pa_channel_position_to_pretty_string; -pa_channel_position_to_string; -pa_channels_valid; -pa_context_add_autoload; -pa_context_connect; -pa_context_disconnect; -pa_context_drain; -pa_context_errno; -pa_context_exit_daemon; -pa_context_get_autoload_info_by_index; -pa_context_get_autoload_info_by_name; -pa_context_get_autoload_info_list; -pa_context_get_card_info_by_index; -pa_context_get_card_info_by_name; -pa_context_get_card_info_list; -pa_context_get_client_info; -pa_context_get_client_info_list; -pa_context_get_index; -pa_context_get_module_info; -pa_context_get_module_info_list; -pa_context_get_protocol_version; -pa_context_get_sample_info_by_index; -pa_context_get_sample_info_by_name; -pa_context_get_sample_info_list; -pa_context_get_server; -pa_context_get_server_info; -pa_context_get_server_protocol_version; -pa_context_get_sink_info_by_index; -pa_context_get_sink_info_by_name; -pa_context_get_sink_info_list; -pa_context_get_sink_input_info; -pa_context_get_sink_input_info_list; -pa_context_get_source_info_by_index; -pa_context_get_source_info_by_name; -pa_context_get_source_info_list; -pa_context_get_source_output_info; -pa_context_get_source_output_info_list; -pa_context_set_port_latency_offset; -pa_context_get_state; -pa_context_get_tile_size; -pa_context_is_local; -pa_context_is_pending; -pa_context_kill_client; -pa_context_kill_sink_input; -pa_context_kill_source_output; -pa_context_load_cookie_from_file; -pa_context_load_module; -pa_context_move_sink_input_by_index; -pa_context_move_sink_input_by_name; -pa_context_move_source_output_by_index; -pa_context_move_source_output_by_name; -pa_context_new; -pa_context_new_with_proplist; -pa_context_play_sample; -pa_context_play_sample_with_proplist; -pa_context_proplist_remove; -pa_context_proplist_update; -pa_context_ref; -pa_context_remove_autoload_by_index; -pa_context_remove_autoload_by_name; -pa_context_remove_sample; -pa_context_rttime_new; -pa_context_rttime_restart; -pa_context_set_card_profile_by_index; -pa_context_set_card_profile_by_name; -pa_context_set_default_sink; -pa_context_set_default_source; -pa_context_set_event_callback; -pa_context_set_name; -pa_context_set_sink_input_mute; -pa_context_set_sink_input_volume; -pa_context_set_sink_mute_by_index; -pa_context_set_sink_mute_by_name; -pa_context_set_sink_port_by_index; -pa_context_set_sink_port_by_name; -pa_context_set_sink_volume_by_index; -pa_context_set_sink_volume_by_name; -pa_context_set_source_output_mute; -pa_context_set_source_output_volume; -pa_context_set_source_mute_by_index; -pa_context_set_source_mute_by_name; -pa_context_set_source_port_by_index; -pa_context_set_source_port_by_name; -pa_context_set_source_volume_by_index; -pa_context_set_source_volume_by_name; -pa_context_set_state_callback; -pa_context_set_subscribe_callback; -pa_context_stat; -pa_context_subscribe; -pa_context_suspend_sink_by_index; -pa_context_suspend_sink_by_name; -pa_context_suspend_source_by_index; -pa_context_suspend_source_by_name; -pa_context_unload_module; -pa_context_unref; -pa_cvolume_avg; -pa_cvolume_avg_mask; -pa_cvolume_channels_equal_to; -pa_cvolume_compatible; -pa_cvolume_compatible_with_channel_map; -pa_cvolume_dec; -pa_cvolume_equal; -pa_cvolume_get_balance; -pa_cvolume_get_fade; -pa_cvolume_get_lfe_balance; -pa_cvolume_get_position; -pa_cvolume_inc; -pa_cvolume_inc_clamp; -pa_cvolume_init; -pa_cvolume_max; -pa_cvolume_max_mask; -pa_cvolume_merge; -pa_cvolume_min; -pa_cvolume_min_mask; -pa_cvolume_remap; -pa_cvolume_scale; -pa_cvolume_scale_mask; -pa_cvolume_set; -pa_cvolume_set_balance; -pa_cvolume_set_fade; -pa_cvolume_set_lfe_balance; -pa_cvolume_set_position; -pa_cvolume_snprint; -pa_cvolume_snprint_verbose; -pa_cvolume_valid; -pa_direction_to_string; -pa_direction_valid; -pa_encoding_from_string; -pa_encoding_to_string; -pa_ext_device_manager_delete; -pa_ext_device_manager_enable_role_device_priority_routing; -pa_ext_device_manager_read; -pa_ext_device_manager_reorder_devices_for_role; -pa_ext_device_manager_set_device_description; -pa_ext_device_manager_set_subscribe_cb; -pa_ext_device_manager_subscribe; -pa_ext_device_manager_test; -pa_ext_device_restore_read_formats; -pa_ext_device_restore_read_formats_all; -pa_ext_device_restore_save_formats; -pa_ext_device_restore_set_subscribe_cb; -pa_ext_device_restore_subscribe; -pa_ext_device_restore_test; -pa_ext_stream_restore_delete; -pa_ext_stream_restore_read; -pa_ext_stream_restore_set_subscribe_cb; -pa_ext_stream_restore_subscribe; -pa_ext_stream_restore_test; -pa_ext_stream_restore_write; -pa_format_info_copy; -pa_format_info_free; -pa_format_info_from_string; -pa_format_info_from_sample_spec; -pa_format_info_get_prop_type; -pa_format_info_get_prop_int; -pa_format_info_get_prop_int_range; -pa_format_info_get_prop_int_array; -pa_format_info_get_prop_string; -pa_format_info_get_prop_string_array; -pa_format_info_free_string_array; -pa_format_info_is_compatible; -pa_format_info_is_pcm; -pa_format_info_new; -pa_format_info_set_channel_map; -pa_format_info_set_channels; -pa_format_info_set_prop_int; -pa_format_info_set_prop_int_array; -pa_format_info_set_prop_int_range; -pa_format_info_set_prop_string; -pa_format_info_set_prop_string_array; -pa_format_info_set_rate; -pa_format_info_set_sample_format; -pa_format_info_snprint; -pa_format_info_to_sample_spec; -pa_format_info_valid; -pa_frame_size; -pa_get_binary_name; -pa_get_fqdn; -pa_get_home_dir; -pa_get_host_name; -pa_get_library_version; -pa_gettimeofday; -pa_get_user_name; -pa_glib_mainloop_free; -pa_glib_mainloop_get_api; -pa_glib_mainloop_new; -pa_locale_to_utf8; -pa_mainloop_api_once; -pa_mainloop_dispatch; -pa_mainloop_free; -pa_mainloop_get_api; -pa_mainloop_get_retval; -pa_mainloop_iterate; -pa_mainloop_new; -pa_mainloop_poll; -pa_mainloop_prepare; -pa_mainloop_quit; -pa_mainloop_run; -pa_mainloop_set_poll_func; -pa_mainloop_wakeup; -pa_msleep; -pa_operation_cancel; -pa_operation_get_state; -pa_operation_ref; -pa_operation_set_state_callback; -pa_operation_unref; -pa_parse_sample_format; -pa_path_get_filename; -pa_proplist_clear; -pa_proplist_contains; -pa_proplist_copy; -pa_proplist_equal; -pa_proplist_free; -pa_proplist_from_string; -pa_proplist_get; -pa_proplist_gets; -pa_proplist_isempty; -pa_proplist_iterate; -pa_proplist_key_valid; -pa_proplist_new; -pa_proplist_set; -pa_proplist_setf; -pa_proplist_setp; -pa_proplist_sets; -pa_proplist_size; -pa_proplist_to_string; -pa_proplist_to_string_sep; -pa_proplist_unset; -pa_proplist_unset_many; -pa_proplist_update; -pa_rtclock_now; -pa_sample_format_is_be; -pa_sample_format_is_le; -pa_sample_format_to_string; -pa_sample_format_valid; -pa_sample_rate_valid; -pa_sample_size; -pa_sample_size_of_format; -pa_sample_spec_equal; -pa_sample_spec_init; -pa_sample_spec_snprint; -pa_sample_spec_valid; -pa_signal_done; -pa_signal_free; -pa_signal_init; -pa_signal_new; -pa_signal_set_destroy; -pa_simple_drain; -pa_simple_flush; -pa_simple_free; -pa_simple_get_latency; -pa_simple_new; -pa_simple_read; -pa_simple_write; -pa_stream_begin_write; -pa_stream_cancel_write; -pa_stream_connect_playback; -pa_stream_connect_record; -pa_stream_connect_upload; -pa_stream_cork; -pa_stream_disconnect; -pa_stream_drain; -pa_stream_drop; -pa_stream_finish_upload; -pa_stream_flush; -pa_stream_get_buffer_attr; -pa_stream_get_channel_map; -pa_stream_get_context; -pa_stream_get_device_index; -pa_stream_get_device_name; -pa_stream_get_format_info; -pa_stream_get_index; -pa_stream_get_latency; -pa_stream_get_monitor_stream; -pa_stream_get_sample_spec; -pa_stream_get_state; -pa_stream_get_time; -pa_stream_get_timing_info; -pa_stream_get_underflow_index; -pa_stream_is_corked; -pa_stream_is_suspended; -pa_stream_new; -pa_stream_new_extended; -pa_stream_new_with_proplist; -pa_stream_peek; -pa_stream_prebuf; -pa_stream_proplist_remove; -pa_stream_proplist_update; -pa_stream_readable_size; -pa_stream_ref; -pa_stream_set_buffer_attr; -pa_stream_set_buffer_attr_callback; -pa_stream_set_event_callback; -pa_stream_set_latency_update_callback; -pa_stream_set_monitor_stream; -pa_stream_set_moved_callback; -pa_stream_set_name; -pa_stream_set_overflow_callback; -pa_stream_set_read_callback; -pa_stream_set_started_callback; -pa_stream_set_state_callback; -pa_stream_set_suspended_callback; -pa_stream_set_underflow_callback; -pa_stream_set_write_callback; -pa_stream_trigger; -pa_stream_unref; -pa_stream_update_sample_rate; -pa_stream_update_timing_info; -pa_stream_writable_size; -pa_stream_write; -pa_stream_write_ext_free; -pa_strerror; -pa_sw_cvolume_divide; -pa_sw_cvolume_divide_scalar; -pa_sw_cvolume_multiply; -pa_sw_cvolume_multiply_scalar; -pa_sw_cvolume_snprint_dB; -pa_sw_volume_divide; -pa_sw_volume_from_dB; -pa_sw_volume_from_linear; -pa_sw_volume_multiply; -pa_sw_volume_snprint_dB; -pa_sw_volume_to_dB; -pa_sw_volume_to_linear; -pa_threaded_mainloop_accept; -pa_threaded_mainloop_free; -pa_threaded_mainloop_get_api; -pa_threaded_mainloop_get_retval; -pa_threaded_mainloop_in_thread; -pa_threaded_mainloop_lock; -pa_threaded_mainloop_new; -pa_threaded_mainloop_set_name; -pa_threaded_mainloop_signal; -pa_threaded_mainloop_start; -pa_threaded_mainloop_stop; -pa_threaded_mainloop_unlock; -pa_threaded_mainloop_wait; -pa_timeval_add; -pa_timeval_age; -pa_timeval_cmp; -pa_timeval_diff; -pa_timeval_load; -pa_timeval_store; -pa_timeval_sub; -pa_usec_to_bytes; -pa_utf8_filter; -pa_utf8_to_locale; -pa_utf8_valid; -pa_volume_snprint; -pa_volume_snprint_verbose; -pa_xfree; -pa_xmalloc; -pa_xmalloc0; -pa_xmemdup; -pa_xrealloc; -pa_xstrdup; -pa_xstrndup; -local: -*; -}; diff --git a/pipewire-pulseaudio/src/meson.build b/pipewire-pulseaudio/src/meson.build deleted file mode 100644 index 1a2d0b68d..000000000 --- a/pipewire-pulseaudio/src/meson.build +++ /dev/null @@ -1,103 +0,0 @@ -pipewire_pulseaudio_sources = [ - 'bitset.c', - 'channelmap.c', - 'context.c', - 'core-format.c', - 'direction.c', - 'error.c', - 'ext-device-manager.c', - 'ext-device-restore.c', - 'ext-stream-restore.c', - 'format.c', - 'introspect.c', - 'json.c', - 'mainloop.c', - 'mainloop-signal.c', - 'operation.c', - 'proplist.c', - 'rtclock.c', - 'sample.c', - 'scache.c', - 'stream.c', - 'strbuf.c', - 'subscribe.c', - 'thread-mainloop.c', - 'timeval.c', - 'utf8.c', - 'util.c', - 'version.c', - 'volume.c', - 'xmalloc.c', - 'pipewire-pulseaudio.c', -] - -pipewire_mainloop_glib_sources = [ - 'mainloop-glib.c', -] - -pipewire_simple_sources = [ - 'simple.c', -] - -pipewire_pulseaudio_c_args = [ - '-DHAVE_CONFIG_H', - '-D_GNU_SOURCE', - '-DPIC', -] - -mapfile = 'map-file' -vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) - -libpulse_path = get_option('libpulse-path') -if libpulse_path == '' - libpulse_path = join_paths(modules_install_dir, 'pulse') - libpulse_path_dlopen = join_paths(modules_install_dir_dlopen, 'pulse') -else - libpulse_path_dlopen = libpulse_path -endif - -tools_config = configuration_data() -tools_config.set('LIBPULSE_PATH', libpulse_path_dlopen) - -configure_file(input : 'pw-pulse.in', - output : 'pw-pulse', - configuration : tools_config, - install_dir : pipewire_bindir) - -pipewire_pulse = shared_library('pulse', - pipewire_pulseaudio_sources, - soversion : soversion, - version : libversion, - c_args : pipewire_pulseaudio_c_args, - link_args : vflag, - include_directories : [configinc], - dependencies : [pipewire_dep, pulseaudio_dep, mathlib], - install : true, - install_dir : libpulse_path, -) - -pipewire_pulse_mainloop_glib = shared_library('pulse-mainloop-glib', - pipewire_mainloop_glib_sources, - soversion : soversion, - version : libversion, - c_args : pipewire_pulseaudio_c_args, - link_args : vflag, - include_directories : [configinc], - dependencies : [pipewire_dep, pulseaudio_dep, mathlib, glib_dep], - install : true, - install_rpath : libpulse_path_dlopen, - install_dir : libpulse_path, -) - -pipewire_pulse_simple = shared_library('pulse-simple', - pipewire_simple_sources, - soversion : soversion, - version : libversion, - c_args : pipewire_pulseaudio_c_args, - link_args : vflag, - include_directories : [configinc], - dependencies : [pipewire_dep, pulseaudio_dep, mathlib, glib_dep], - install : true, - install_rpath : libpulse_path_dlopen, - install_dir : libpulse_path, -) diff --git a/pipewire-pulseaudio/src/operation.c b/pipewire-pulseaudio/src/operation.c deleted file mode 100644 index 99c343601..000000000 --- a/pipewire-pulseaudio/src/operation.c +++ /dev/null @@ -1,166 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include - -#include - -#include "internal.h" - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, size_t userdata_size) { - pa_operation *o; - pa_assert(c); - - o = calloc(1, sizeof(pa_operation) + userdata_size); - - o->refcount = 1; - o->context = c; - o->stream = s ? pa_stream_ref(s) : NULL; - - o->state = PA_OPERATION_RUNNING; - o->callback = cb; - o->userdata = SPA_MEMBER(o, sizeof(pa_operation), void); - - spa_list_append(&c->operations, &o->link); - pa_operation_ref(o); - pw_log_debug("new %p", o); - - return o; -} - -int pa_operation_sync(pa_operation *o) -{ - pa_context *c = o->context; - if (c->core != NULL) - c->pending_seq = pw_core_sync(c->core, PW_ID_CORE, 0); - o->sync = true; - pw_log_debug("operation %p: sync seq:%d", o, c->pending_seq); - return 0; -} - -SPA_EXPORT -pa_operation *pa_operation_ref(pa_operation *o) -{ - pa_assert(o); - pa_assert(o->refcount >= 1); - o->refcount++; - return o; -} - -static void operation_free(pa_operation *o) -{ - pa_assert(!o->context); - pa_assert(!o->stream); - pw_log_debug("%p", o); - free(o); -} - -static void operation_unlink(pa_operation *o) { - pa_assert(o); - - pw_log_debug("%p", o); - if (o->context) { - pa_assert(o->refcount >= 2); - - spa_list_remove(&o->link); - pa_operation_unref(o); - - o->context = NULL; - } - if (o->stream) - pa_stream_unref(o->stream); - o->stream = NULL; - o->callback = NULL; - o->userdata = NULL; - o->state_callback = NULL; - o->state_userdata = NULL; -} - -SPA_EXPORT -void pa_operation_unref(pa_operation *o) -{ - pa_assert(o); - pa_assert(o->refcount >= 1); - pw_log_debug("%p ref:%d", o, o->refcount); - if (--o->refcount == 0) - operation_free(o); -} - -static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - pa_assert(o); - pa_assert(o->refcount >= 1); - - if (st == o->state) - return; - - pa_operation_ref(o); - - pw_log_debug("new state %p state:%d", o, st); - o->state = st; - - if (o->state_callback) - o->state_callback(o, o->state_userdata); - - if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) - operation_unlink(o); - - pa_operation_unref(o); -} - - -SPA_EXPORT -void pa_operation_cancel(pa_operation *o) -{ - pa_assert(o); - pa_assert(o->refcount >= 1); - pw_log_debug("%p", o); - operation_set_state(o, PA_OPERATION_CANCELED); -} - -void pa_operation_done(pa_operation *o) { - pa_assert(o); - pa_assert(o->refcount >= 1); - operation_set_state(o, PA_OPERATION_DONE); -} - - -SPA_EXPORT -pa_operation_state_t pa_operation_get_state(PA_CONST pa_operation *o) -{ - pa_assert(o); - pa_assert(o->refcount >= 1); - return o->state; -} - -SPA_EXPORT -void pa_operation_set_state_callback(pa_operation *o, pa_operation_notify_cb_t cb, void *userdata) -{ - pa_assert(o); - pa_assert(o->refcount >= 1); - - if (o->state == PA_OPERATION_DONE || o->state == PA_OPERATION_CANCELED) - return; - - o->state_callback = cb; - o->state_userdata = userdata; -} diff --git a/pipewire-pulseaudio/src/pipewire-pulseaudio.c b/pipewire-pulseaudio/src/pipewire-pulseaudio.c deleted file mode 100644 index 3b3405984..000000000 --- a/pipewire-pulseaudio/src/pipewire-pulseaudio.c +++ /dev/null @@ -1,30 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -static void reg(void) __attribute__ ((constructor)); -static void reg(void) -{ - pw_init(NULL, NULL); -} diff --git a/pipewire-pulseaudio/src/proplist.c b/pipewire-pulseaudio/src/proplist.c deleted file mode 100644 index 79010c30a..000000000 --- a/pipewire-pulseaudio/src/proplist.c +++ /dev/null @@ -1,405 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include -#include - -#include - -#include "internal.h" -#include "strbuf.h" - -struct pa_proplist { - struct pw_properties *props; -}; - -int pa_proplist_update_dict(pa_proplist *p, struct spa_dict *dict) -{ - const struct spa_dict_item *item; - spa_dict_for_each(item, dict) - pa_proplist_sets(p, item->key, item->value); - return 0; -} - -pa_proplist* pa_proplist_new_dict(struct spa_dict *dict) -{ - pa_proplist *p; - - p = pa_proplist_new(); - if (p == NULL) - return NULL; - - pa_proplist_update_dict(p, dict); - - return p; -} -pa_proplist* pa_proplist_new_props(struct pw_properties *props) -{ - return pa_proplist_new_dict(&props->dict); -} - -SPA_EXPORT -pa_proplist* pa_proplist_new(void) -{ - pa_proplist *p; - - p = calloc(1, sizeof(struct pa_proplist)); - if (p == NULL) - return NULL; - - p->props = pw_properties_new(NULL, NULL); - - return p; -} - -SPA_EXPORT -void pa_proplist_free(pa_proplist* p) -{ - pw_properties_free(p->props); - free(p); -} - -SPA_EXPORT -int pa_proplist_key_valid(const char *key) -{ - const char *p; - for (p = key; *p; p++) - if ((unsigned char) *p >= 128) - return 0; - - if (strlen(key) < 1) - return 0; - - return 1; -} - -SPA_EXPORT -int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) -{ - pa_assert(p); - pa_assert(key); - pa_assert(value); - - if (!pa_proplist_key_valid(key)) - return -1; - - pw_properties_set(p->props, key, value); - return 0; -} - -SPA_EXPORT -int pa_proplist_setp(pa_proplist *p, const char *pair) -{ - const char *t; - char *c; - int idx; - - pa_assert(p); - pa_assert(pair); - - if (!(t = strchr(pair, '='))) - return -1; - - idx = pair - t; - c = strdup(pair); - c[idx] = 0; - pa_proplist_sets(p, c, &c[idx]+1); - free(c); - - return 0; -} - -SPA_EXPORT -int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) -{ - va_list varargs; - - va_start(varargs, format); - pw_properties_setva(p->props, key, format, varargs); - va_end(varargs); - - return 0; -} - -SPA_EXPORT -int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) -{ - pa_assert(p); - pa_assert(key); - pa_assert(data || nbytes == 0); - - if (!pa_proplist_key_valid(key)) - return -1; - - pw_properties_set(p->props, key, data); - return 0; -} - -SPA_EXPORT -const char *pa_proplist_gets(PA_CONST pa_proplist *p, const char *key) -{ - return pw_properties_get(p->props, key); -} - -SPA_EXPORT -int pa_proplist_get(PA_CONST pa_proplist *p, const char *key, const void **data, size_t *nbytes) -{ - const char *val; - - spa_assert(p); - spa_assert(key); - - val = pw_properties_get(p->props, key); - - *data = val; - *nbytes = val ? strlen(val) : 0; - return 0; -} - -SPA_EXPORT -void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, const pa_proplist *other) -{ - uint32_t i; - - spa_assert(p); - spa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE); - spa_assert(other); - - if (mode == PA_UPDATE_REPLACE) { - pa_proplist_update_dict(p, &other->props->dict); - return; - } - - if (mode == PA_UPDATE_SET) - pa_proplist_clear(p); - - for (i = 0; i < other->props->dict.n_items; i++) { - const struct spa_dict_item *oi; - - oi = &other->props->dict.items[i]; - if (pw_properties_get(p->props, oi->key) == NULL) - pw_properties_set(p->props, oi->key, oi->value); - } -} - -SPA_EXPORT -int pa_proplist_unset(pa_proplist *p, const char *key) -{ - spa_assert(p); - spa_assert(key); - - if (!pa_proplist_key_valid(key)) - return -1; - - return pw_properties_set(p->props, key, NULL); -} - -SPA_EXPORT -int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) -{ - const char * const * k; - int n = 0; - - spa_assert(p); - spa_assert(keys); - - for (k = keys; *k; k++) - if (!pa_proplist_key_valid(*k)) - return -1; - - for (k = keys; *k; k++) - if (pa_proplist_unset(p, *k) >= 0) - n++; - return n; -} - -SPA_EXPORT -const char *pa_proplist_iterate(PA_CONST pa_proplist *p, void **state) -{ - spa_assert(p); - spa_assert(state); - return pw_properties_iterate(p->props, state); -} - -SPA_EXPORT -char *pa_proplist_to_string(PA_CONST pa_proplist *p) -{ - spa_assert(p); - return pa_proplist_to_string_sep(p, ","); -} - -SPA_EXPORT -char *pa_proplist_to_string_sep(PA_CONST pa_proplist *p, const char *sep) -{ - const char *key; - void *state = NULL; - pa_strbuf *buf; - - spa_assert(p); - spa_assert(sep); - - buf = pa_strbuf_new(); - - while ((key = pa_proplist_iterate(p, &state))) { - const char *v; - const char *t; - - if (!pa_strbuf_isempty(buf)) - pa_strbuf_puts(buf, sep); - - if ((v = pa_proplist_gets(p, key)) == NULL) - continue; - - pa_strbuf_printf(buf, "%s = \"", key); - - for (t = v;;) { - size_t h; - - h = strcspn(t, "\""); - - if (h > 0) - pa_strbuf_putsn(buf, t, h); - - t += h; - - if (*t == 0) - break; - - pa_assert(*t == '"'); - pa_strbuf_puts(buf, "\\\""); - - t++; - } - pa_strbuf_puts(buf, "\""); - } - return pa_strbuf_to_string_free(buf); -} - -SPA_EXPORT -pa_proplist *pa_proplist_from_string(const char *str) -{ - spa_assert(str); - pw_log_warn("Not Implemented"); - return NULL; -} - -SPA_EXPORT -int pa_proplist_contains(PA_CONST pa_proplist *p, const char *key) -{ - spa_assert(p); - spa_assert(key); - - if (!pa_proplist_key_valid(key)) - return -1; - - if (pw_properties_get(p->props, key) == NULL) - return 0; - - return 1; -} - -SPA_EXPORT -void pa_proplist_clear(pa_proplist *p) -{ - spa_assert(p); - pw_properties_clear(p->props); -} - -SPA_EXPORT -pa_proplist* pa_proplist_copy(const pa_proplist *p) -{ - pa_proplist *c; - - spa_assert(p); - - c = calloc(1, sizeof(struct pa_proplist)); - if (c == NULL) - return NULL; - - c->props = pw_properties_copy(p->props); - return c; -} - -SPA_EXPORT -unsigned pa_proplist_size(PA_CONST pa_proplist *p) -{ - spa_assert(p); - return p->props->dict.n_items; -} - -SPA_EXPORT -int pa_proplist_isempty(PA_CONST pa_proplist *p) -{ - spa_assert(p); - return p->props->dict.n_items == 0 ? 1 : 0; -} - -SPA_EXPORT -int pa_proplist_equal(PA_CONST pa_proplist *a, PA_CONST pa_proplist *b) -{ - uint32_t i; - - spa_assert(a); - spa_assert(b); - - if (a == b) - return 1; - - if (pa_proplist_size(a) != pa_proplist_size(b)) - return 0; - - for (i = 0; i < a->props->dict.n_items; i++) { - const struct spa_dict_item *ai, *bi; - - ai = &a->props->dict.items[i]; - bi = spa_dict_lookup_item(&b->props->dict, ai->key); - - if (bi == NULL || bi->value == NULL || ai->value == NULL) - return 0; - if (strcmp(ai->value, bi->value) != 0) - return 0; - } - return 1; -} - - -int pw_properties_update_proplist(struct pw_properties *props, - PA_CONST pa_proplist *p) -{ - void *state = NULL; - const char *key, *val; - int changed = 0; - - while (true) { - key = pa_proplist_iterate(p, &state); - if (key == NULL) - break; - - val = pa_proplist_gets(p, key); - if (val == NULL) - continue; - - changed += pw_properties_set(props, key, val); - } - return changed; -} diff --git a/pipewire-pulseaudio/src/pw-pulse.in b/pipewire-pulseaudio/src/pw-pulse.in deleted file mode 100755 index a8c470bba..000000000 --- a/pipewire-pulseaudio/src/pw-pulse.in +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh - -# This file is part of PipeWire. -# -# Copyright © 2020 Wim Taymans -# -# 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 (including the next -# paragraph) 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. -# -while getopts 'hr:v' param ; do - case $param in - r) - PIPEWIRE_REMOTE="$OPTARG" - export PIPEWIRE_REMOTE - ;; - v) - if [ x"$PIPEWIRE_DEBUG" = x ]; then - PIPEWIRE_DEBUG=3 - else - PIPEWIRE_DEBUG=$(( $PIPEWIRE_DEBUG + 1 )) - fi - export PIPEWIRE_DEBUG - ;; - *) - echo "$0 - run PulseAudio applications on PipeWire" - echo " " - echo "$0 [options] application [arguments]" - echo " " - echo "options:" - echo " -h show brief help" - echo " -r remote daemon name" - echo " -v verbose debug info" - exit 0 - ;; - esac -done - -shift $(( $OPTIND - 1 )) - -LD_LIBRARY_PATH='@LIBPULSE_PATH@'"${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"}" -export LD_LIBRARY_PATH - -exec "$@" diff --git a/pipewire-pulseaudio/src/rtclock.c b/pipewire-pulseaudio/src/rtclock.c deleted file mode 100644 index 0851083f9..000000000 --- a/pipewire-pulseaudio/src/rtclock.c +++ /dev/null @@ -1,106 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include - -#include -#include -#include "internal.h" - -SPA_EXPORT -pa_usec_t pa_rtclock_now(void) -{ - struct timespec ts; - pa_usec_t res; - - clock_gettime(CLOCK_MONOTONIC, &ts); - res = (ts.tv_sec * SPA_USEC_PER_SEC) + (ts.tv_nsec / SPA_NSEC_PER_USEC); - return res; -} - -static struct timeval *pa_rtclock_get(struct timeval *tv) -{ - struct timespec ts; - - pa_assert(tv); - - clock_gettime(CLOCK_MONOTONIC, &ts); - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC; - return tv; -} - -struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) -{ - struct timeval wc_now, rt_now; - - pa_assert(tv); - - pa_gettimeofday(&wc_now); - pa_rtclock_get(&rt_now); - - if (pa_timeval_cmp(&wc_now, tv) < 0) - pa_timeval_add(&rt_now, pa_timeval_diff(tv, &wc_now)); - else - pa_timeval_sub(&rt_now, pa_timeval_diff(&wc_now, tv)); - - *tv = rt_now; - - return tv; -} - -struct timeval* pa_rtclock_to_wallclock(struct timeval *tv) -{ - struct timeval wc_now, rt_now; - - pa_assert(tv); - - pa_gettimeofday(&wc_now); - pa_rtclock_get(&rt_now); - - if (pa_timeval_cmp(&rt_now, tv) < 0) - pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now)); - else - pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv)); - - *tv = wc_now; - - return tv; -} - -struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, bool rtclock) -{ - pa_assert(tv); - - if (v == PA_USEC_INVALID) - return NULL; - - pa_timeval_store(tv, v); - - if (rtclock) - tv->tv_usec |= PA_TIMEVAL_RTCLOCK; - else - pa_rtclock_to_wallclock(tv); - - return tv; -} diff --git a/pipewire-pulseaudio/src/sample-util.h b/pipewire-pulseaudio/src/sample-util.h deleted file mode 100644 index 45528ef6d..000000000 --- a/pipewire-pulseaudio/src/sample-util.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef foosampleutilhfoo -#define foosampleutilhfoo - -/*** - 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, see . -***/ - -#include -#include - -#include -#include -#include -#include - -size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; - -bool pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; - -void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n); -void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n); - -void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const void *src, size_t sstr, unsigned n); - -static inline int32_t pa_mult_s16_volume(int16_t v, int32_t cv) { -#ifdef HAVE_FAST_64BIT_OPERATIONS - /* Multiply with 64 bit integers on 64 bit platforms */ - return (v * (int64_t) cv) >> 16; -#else - /* Multiplying the 32 bit volume factor with the - * 16 bit sample might result in an 48 bit value. We - * want to do without 64 bit integers and hence do - * the multiplication independently for the HI and - * LO part of the volume. */ - - int32_t hi = cv >> 16; - int32_t lo = cv & 0xFFFF; - return ((v * lo) >> 16) + (v * hi); -#endif -} - -pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec); -size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec); - -typedef void (*pa_do_volume_func_t) (void *samples, const void *volumes, unsigned channels, unsigned length); - -pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f); -void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func); - -size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to); - -#define PA_CHANNEL_POSITION_MASK_LEFT \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT)) \ - -#define PA_CHANNEL_POSITION_MASK_RIGHT \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT)) - -#define PA_CHANNEL_POSITION_MASK_CENTER \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER)) - -#define PA_CHANNEL_POSITION_MASK_FRONT \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER)) - -#define PA_CHANNEL_POSITION_MASK_REAR \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER)) - -#define PA_CHANNEL_POSITION_MASK_LFE \ - PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_LFE) - -#define PA_CHANNEL_POSITION_MASK_HFE \ - (PA_CHANNEL_POSITION_MASK_REAR | PA_CHANNEL_POSITION_MASK_FRONT \ - | PA_CHANNEL_POSITION_MASK_LEFT | PA_CHANNEL_POSITION_MASK_RIGHT \ - | PA_CHANNEL_POSITION_MASK_CENTER) - -#define PA_CHANNEL_POSITION_MASK_SIDE_OR_TOP_CENTER \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER)) - -#define PA_CHANNEL_POSITION_MASK_TOP \ - (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT) \ - | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER)) - -#define PA_CHANNEL_POSITION_MASK_ALL \ - ((pa_channel_position_mask_t) (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_MAX)-1)) - -#endif diff --git a/pipewire-pulseaudio/src/sample.c b/pipewire-pulseaudio/src/sample.c deleted file mode 100644 index 07e903219..000000000 --- a/pipewire-pulseaudio/src/sample.c +++ /dev/null @@ -1,337 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB - Copyright 2018 Wim Taymans - - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include -#include - -#define pa_init_i18n() -#define _(String) (String) - -static const size_t size_table[] = { - [PA_SAMPLE_U8] = 1, - [PA_SAMPLE_ULAW] = 1, - [PA_SAMPLE_ALAW] = 1, - [PA_SAMPLE_S16LE] = 2, - [PA_SAMPLE_S16BE] = 2, - [PA_SAMPLE_FLOAT32LE] = 4, - [PA_SAMPLE_FLOAT32BE] = 4, - [PA_SAMPLE_S32LE] = 4, - [PA_SAMPLE_S32BE] = 4, - [PA_SAMPLE_S24LE] = 3, - [PA_SAMPLE_S24BE] = 3, - [PA_SAMPLE_S24_32LE] = 4, - [PA_SAMPLE_S24_32BE] = 4 -}; - -SPA_EXPORT -size_t pa_sample_size_of_format(pa_sample_format_t f) -{ - spa_assert(pa_sample_format_valid(f)); - - return size_table[f]; -} - -SPA_EXPORT -size_t pa_sample_size(const pa_sample_spec * spec) -{ - spa_assert(spec); - spa_assert(pa_sample_spec_valid(spec)); - - return size_table[spec->format]; -} - -SPA_EXPORT -size_t pa_frame_size(const pa_sample_spec * spec) -{ - spa_assert(spec); - spa_assert(pa_sample_spec_valid(spec)); - - return size_table[spec->format] * spec->channels; -} - -SPA_EXPORT -size_t pa_bytes_per_second(const pa_sample_spec * spec) -{ - spa_assert(spec); - spa_assert(pa_sample_spec_valid(spec)); - - return spec->rate * size_table[spec->format] * spec->channels; -} - -SPA_EXPORT -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec * spec) -{ - spa_assert(spec); - spa_assert(pa_sample_spec_valid(spec)); - - return (((pa_usec_t) - (length / (size_table[spec->format] * spec->channels)) - * PA_USEC_PER_SEC) / spec->rate); -} - -SPA_EXPORT -size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec * spec) -{ - spa_assert(spec); - spa_assert(pa_sample_spec_valid(spec)); - - return (size_t) (((t * spec->rate) / PA_USEC_PER_SEC)) * - (size_table[spec->format] * spec->channels); -} - -SPA_EXPORT -pa_sample_spec *pa_sample_spec_init(pa_sample_spec * spec) -{ - spa_assert(spec); - - spec->format = PA_SAMPLE_INVALID; - spec->rate = 0; - spec->channels = 0; - - return spec; -} - -SPA_EXPORT -int pa_sample_format_valid(unsigned format) -{ - return format < PA_SAMPLE_MAX; -} - -SPA_EXPORT -int pa_sample_rate_valid(uint32_t rate) -{ - /* The extra 1% is due to module-loopback: it temporarily sets - * a higher-than-nominal rate to get rid of excessive buffer - * latency */ - return rate > 0 && rate <= PA_RATE_MAX * 101 / 100; -} - -SPA_EXPORT -int pa_channels_valid(uint8_t channels) -{ - return channels > 0 && channels <= PA_CHANNELS_MAX; -} - -SPA_EXPORT -int pa_sample_spec_valid(const pa_sample_spec * spec) -{ - spa_assert(spec); - - if (SPA_UNLIKELY(!pa_sample_rate_valid(spec->rate) || - !pa_channels_valid(spec->channels) || - !pa_sample_format_valid(spec->format))) - return 0; - - return 1; -} - -SPA_EXPORT -int pa_sample_spec_equal(const pa_sample_spec * a, const pa_sample_spec * b) -{ - spa_assert(a); - spa_assert(b); - - spa_return_val_if_fail(pa_sample_spec_valid(a), 0); - - if (SPA_UNLIKELY(a == b)) - return 1; - - spa_return_val_if_fail(pa_sample_spec_valid(b), 0); - - return - (a->format == b->format) && - (a->rate == b->rate) && (a->channels == b->channels); -} - -SPA_EXPORT -const char *pa_sample_format_to_string(pa_sample_format_t f) -{ - static const char *const table[] = { - [PA_SAMPLE_U8] = "u8", - [PA_SAMPLE_ALAW] = "aLaw", - [PA_SAMPLE_ULAW] = "uLaw", - [PA_SAMPLE_S16LE] = "s16le", - [PA_SAMPLE_S16BE] = "s16be", - [PA_SAMPLE_FLOAT32LE] = "float32le", - [PA_SAMPLE_FLOAT32BE] = "float32be", - [PA_SAMPLE_S32LE] = "s32le", - [PA_SAMPLE_S32BE] = "s32be", - [PA_SAMPLE_S24LE] = "s24le", - [PA_SAMPLE_S24BE] = "s24be", - [PA_SAMPLE_S24_32LE] = "s24-32le", - [PA_SAMPLE_S24_32BE] = "s24-32be", - }; - - if (!pa_sample_format_valid(f)) - return NULL; - - return table[f]; -} - -SPA_EXPORT -char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec * spec) -{ - spa_assert(s); - spa_assert(l > 0); - spa_assert(spec); - - pa_init_i18n(); - - if (!pa_sample_spec_valid(spec)) - snprintf(s, l, _("(invalid)")); - else - snprintf(s, l, _("%s %uch %uHz"), - pa_sample_format_to_string(spec->format), - spec->channels, spec->rate); - - return s; -} - -SPA_EXPORT -char *pa_bytes_snprint(char *s, size_t l, unsigned v) -{ - spa_assert(s); - spa_assert(l > 0); - - pa_init_i18n(); - - if (v >= ((unsigned)1024) * 1024 * 1024) - snprintf(s, l, _("%0.1f GiB"), - ((double)v) / 1024 / 1024 / 1024); - else if (v >= ((unsigned)1024) * 1024) - snprintf(s, l, _("%0.1f MiB"), ((double)v) / 1024 / 1024); - else if (v >= (unsigned)1024) - snprintf(s, l, _("%0.1f KiB"), ((double)v) / 1024); - else - snprintf(s, l, _("%u B"), (unsigned)v); - - return s; -} - -SPA_EXPORT -pa_sample_format_t pa_parse_sample_format(const char *format) -{ - spa_assert(format); - - if (strcasecmp(format, "s16le") == 0) - return PA_SAMPLE_S16LE; - else if (strcasecmp(format, "s16be") == 0) - return PA_SAMPLE_S16BE; - else if (strcasecmp(format, "s16ne") == 0 - || strcasecmp(format, "s16") == 0 - || strcasecmp(format, "16") == 0) - return PA_SAMPLE_S16NE; - else if (strcasecmp(format, "s16re") == 0) - return PA_SAMPLE_S16RE; - else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) - return PA_SAMPLE_U8; - else if (strcasecmp(format, "float32") == 0 - || strcasecmp(format, "float32ne") == 0 - || strcasecmp(format, "float") == 0) - return PA_SAMPLE_FLOAT32NE; - else if (strcasecmp(format, "float32re") == 0) - return PA_SAMPLE_FLOAT32RE; - else if (strcasecmp(format, "float32le") == 0) - return PA_SAMPLE_FLOAT32LE; - else if (strcasecmp(format, "float32be") == 0) - return PA_SAMPLE_FLOAT32BE; - else if (strcasecmp(format, "ulaw") == 0 - || strcasecmp(format, "mulaw") == 0) - return PA_SAMPLE_ULAW; - else if (strcasecmp(format, "alaw") == 0) - return PA_SAMPLE_ALAW; - else if (strcasecmp(format, "s32le") == 0) - return PA_SAMPLE_S32LE; - else if (strcasecmp(format, "s32be") == 0) - return PA_SAMPLE_S32BE; - else if (strcasecmp(format, "s32ne") == 0 - || strcasecmp(format, "s32") == 0 - || strcasecmp(format, "32") == 0) - return PA_SAMPLE_S32NE; - else if (strcasecmp(format, "s32re") == 0) - return PA_SAMPLE_S24RE; - else if (strcasecmp(format, "s24le") == 0) - return PA_SAMPLE_S24LE; - else if (strcasecmp(format, "s24be") == 0) - return PA_SAMPLE_S24BE; - else if (strcasecmp(format, "s24ne") == 0 - || strcasecmp(format, "s24") == 0 - || strcasecmp(format, "24") == 0) - return PA_SAMPLE_S24NE; - else if (strcasecmp(format, "s24re") == 0) - return PA_SAMPLE_S24RE; - else if (strcasecmp(format, "s24-32le") == 0) - return PA_SAMPLE_S24_32LE; - else if (strcasecmp(format, "s24-32be") == 0) - return PA_SAMPLE_S24_32BE; - else if (strcasecmp(format, "s24-32ne") == 0 - || strcasecmp(format, "s24-32") == 0) - return PA_SAMPLE_S24_32NE; - else if (strcasecmp(format, "s24-32re") == 0) - return PA_SAMPLE_S24_32RE; - - return PA_SAMPLE_INVALID; -} - -SPA_EXPORT -int pa_sample_format_is_le(pa_sample_format_t f) -{ - spa_assert(pa_sample_format_valid(f)); - - switch (f) { - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S24LE: - case PA_SAMPLE_S32LE: - case PA_SAMPLE_S24_32LE: - case PA_SAMPLE_FLOAT32LE: - return 1; - - case PA_SAMPLE_S16BE: - case PA_SAMPLE_S24BE: - case PA_SAMPLE_S32BE: - case PA_SAMPLE_S24_32BE: - case PA_SAMPLE_FLOAT32BE: - return 0; - - default: - return -1; - } -} - -SPA_EXPORT -int pa_sample_format_is_be(pa_sample_format_t f) -{ - int r; - - if ((r = pa_sample_format_is_le(f)) < 0) - return r; - - return !r; -} diff --git a/pipewire-pulseaudio/src/scache.c b/pipewire-pulseaudio/src/scache.c deleted file mode 100644 index 0feeb78bc..000000000 --- a/pipewire-pulseaudio/src/scache.c +++ /dev/null @@ -1,62 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include "internal.h" - -SPA_EXPORT -int pa_stream_connect_upload(pa_stream *s, size_t length) -{ - pw_log_warn("Not Implemented"); - return 0; -} - -SPA_EXPORT -int pa_stream_finish_upload(pa_stream *s) -{ - pw_log_warn("Not Implemented"); - return 0; -} - -SPA_EXPORT -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) -{ - pw_log_warn("Not Implemented: name:%s", name); - return NULL; -} - -SPA_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) -{ - pw_log_warn("Not Implemented: name:%s dev:%s", name, dev); - return NULL; -} - -SPA_EXPORT -pa_operation* pa_context_play_sample_with_proplist(pa_context *c, const char *name, - const char *dev, pa_volume_t volume, PA_CONST pa_proplist *proplist, - pa_context_play_sample_cb_t cb, void *userdata) -{ - pw_log_warn("Not Implemented: name:%s dev:%s", name, dev); - return NULL; -} diff --git a/pipewire-pulseaudio/src/simple.c b/pipewire-pulseaudio/src/simple.c deleted file mode 100644 index b3137922f..000000000 --- a/pipewire-pulseaudio/src/simple.c +++ /dev/null @@ -1,520 +0,0 @@ -/*** - 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, see . -***/ - -/*Modefied for pipewire by Jan Koester 2020*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include - -#include "internal.h" - -SPA_EXPORT -struct pa_simple { - pa_threaded_mainloop *mainloop; - pa_context *context; - pa_stream *stream; - pa_stream_direction_t direction; - - const void *read_data; - size_t read_index, read_length; - - int operation_success; -}; - -typedef struct pa_simple pa_simple; - -#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) \ - do { \ - if (!(expression)) { \ - if (rerror) \ - *(rerror) = error; \ - return (ret); \ - } \ - } while(false); - -#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) \ - do { \ - if (!(expression)) { \ - if (rerror) \ - *(rerror) = pa_context_errno((p)->context); \ - goto label; \ - } \ - } while(false); - -#define CHECK_DEAD_GOTO(p, rerror, label) \ - do { \ - if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \ - !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \ - if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ - ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ - if (rerror) \ - *(rerror) = pa_context_errno((p)->context); \ - } else \ - if (rerror) \ - *(rerror) = PA_ERR_BADSTATE; \ - goto label; \ - } \ - } while(false); - -static void context_state_cb(pa_context *c, void *userdata) { - pa_simple *p = userdata; - pa_assert(c); - pa_assert(p); - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_READY: - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal(p->mainloop, 0); - break; - - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - } -} - -static void stream_state_cb(pa_stream *s, void * userdata) { - pa_simple *p = userdata; - pa_assert(s); - pa_assert(p); - - switch (pa_stream_get_state(s)) { - - case PA_STREAM_READY: - case PA_STREAM_FAILED: - case PA_STREAM_TERMINATED: - pa_threaded_mainloop_signal(p->mainloop, 0); - break; - - case PA_STREAM_UNCONNECTED: - case PA_STREAM_CREATING: - break; - } -} - -static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { - pa_simple *p = userdata; - pa_assert(p); - - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -static void stream_latency_update_cb(pa_stream *s, void *userdata) { - pa_simple *p = userdata; - - pa_assert(p); - - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -SPA_EXPORT -void pa_simple_free(pa_simple *s) { - pa_assert(s); - - if (s->mainloop) - pa_threaded_mainloop_stop(s->mainloop); - - if (s->stream) - pa_stream_unref(s->stream); - - if (s->context) { - pa_context_disconnect(s->context); - pa_context_unref(s->context); - } - - if (s->mainloop) - pa_threaded_mainloop_free(s->mainloop); - - pa_xfree(s); -} - -SPA_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 *rerror) { - - pa_simple *p; - int error = PA_ERR_INTERNAL, r; - - CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) - - p = pa_xnew0(pa_simple, 1); - p->direction = dir; - - if (!(p->mainloop = pa_threaded_mainloop_new())) - goto fail; - - if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) - goto fail; - - pa_context_set_state_callback(p->context, context_state_cb, p); - - if (pa_context_connect(p->context, server, 0, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } - - pa_threaded_mainloop_lock(p->mainloop); - - if (pa_threaded_mainloop_start(p->mainloop) < 0) - goto unlock_and_fail; - - for (;;) { - pa_context_state_t state; - - state = pa_context_get_state(p->context); - - if (state == PA_CONTEXT_READY) - break; - - if (!PA_CONTEXT_IS_GOOD(state)) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - /* Wait until the context is ready */ - pa_threaded_mainloop_wait(p->mainloop); - } - - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - pa_stream_set_state_callback(p->stream, stream_state_cb, p); - pa_stream_set_read_callback(p->stream, stream_request_cb, p); - pa_stream_set_write_callback(p->stream, stream_request_cb, p); - pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); - - if (dir == PA_STREAM_PLAYBACK) - r = pa_stream_connect_playback(p->stream, dev, attr, - PA_STREAM_INTERPOLATE_TIMING - |PA_STREAM_ADJUST_LATENCY - |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - else - r = pa_stream_connect_record(p->stream, dev, attr, - PA_STREAM_INTERPOLATE_TIMING - |PA_STREAM_ADJUST_LATENCY - |PA_STREAM_AUTO_TIMING_UPDATE); - - if (r < 0) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - for (;;) { - pa_stream_state_t state; - - state = pa_stream_get_state(p->stream); - - if (state == PA_STREAM_READY) - break; - - if (!PA_STREAM_IS_GOOD(state)) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - /* Wait until the stream is ready */ - pa_threaded_mainloop_wait(p->mainloop); - } - - pa_threaded_mainloop_unlock(p->mainloop); - - return p; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - -fail: - if (rerror) - *rerror = error; - pa_simple_free(p); - return NULL; -} - -SPA_EXPORT -int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - pa_assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); - - pa_threaded_mainloop_lock(p->mainloop); - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - int r; - - while (!(l = pa_stream_writable_size(p->stream))) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - - CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); - - if (l > length) - l = length; - - r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); - CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); - - data = (const uint8_t*) data + l; - length -= l; - } - - pa_threaded_mainloop_unlock(p->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -SPA_EXPORT -int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - pa_assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); - - pa_threaded_mainloop_lock(p->mainloop); - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - - while (!p->read_data) { - int r; - - r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - - if (p->read_length <= 0) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } else if (!p->read_data) { - /* There's a hole in the stream, skip it. We could generate - * silence, but that wouldn't work for compressed streams. */ - r = pa_stream_drop(p->stream); - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - } else - p->read_index = 0; - } - - l = p->read_length < length ? p->read_length : length; - memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); - - data = (uint8_t*) data + l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - int r; - - r = pa_stream_drop(p->stream); - p->read_data = NULL; - p->read_length = 0; - p->read_index = 0; - - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - } - } - - pa_threaded_mainloop_unlock(p->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -static void success_cb(pa_stream *s, int success, void *userdata) { - pa_simple *p = userdata; - - pa_assert(s); - pa_assert(p); - - p->operation_success = success; - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -SPA_EXPORT -int pa_simple_drain(pa_simple *p, int *rerror) { - pa_operation *o = NULL; - - pa_assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - - pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - o = pa_stream_drain(p->stream, success_cb, p); - CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - - p->operation_success = 0; - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - - pa_operation_unref(o); - pa_threaded_mainloop_unlock(p->mainloop); - - return 0; - -unlock_and_fail: - - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } - - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -SPA_EXPORT -int pa_simple_flush(pa_simple *p, int *rerror) { - pa_operation *o = NULL; - - pa_assert(p); - - pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - o = pa_stream_flush(p->stream, success_cb, p); - CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - - p->operation_success = 0; - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - - pa_operation_unref(o); - pa_threaded_mainloop_unlock(p->mainloop); - - return 0; - -unlock_and_fail: - - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } - - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -SPA_EXPORT -pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { - pa_usec_t t; - - pa_assert(p); - - pa_threaded_mainloop_lock(p->mainloop); - - for (;;) { - int negative; - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) { - if (p->direction == PA_STREAM_RECORD) { - pa_usec_t already_read; - - /* pa_simple_read() calls pa_stream_peek() to get the next - * chunk of audio. If the next chunk is larger than what the - * pa_simple_read() caller wanted, the leftover data is stored - * in p->read_data until pa_simple_read() is called again. - * pa_stream_drop() won't be called until the whole chunk has - * been consumed, which means that pa_stream_get_latency() will - * return too large values, because the whole size of the - * partially read chunk is included in the latency. Therefore, - * we need to subtract the already-read amount from the - * latency. */ - already_read = pa_bytes_to_usec(p->read_index, pa_stream_get_sample_spec(p->stream)); - - if (!negative) { - if (t > already_read) - t -= already_read; - else - t = 0; - } - } - - /* We don't have a way to report negative latencies from - * pa_simple_get_latency(). If the latency is negative, let's - * report zero. */ - if (negative) - t = 0; - - break; - } - - CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); - - /* Wait until latency data is available again */ - pa_threaded_mainloop_wait(p->mainloop); - } - - pa_threaded_mainloop_unlock(p->mainloop); - - return t; - -unlock_and_fail: - - pa_threaded_mainloop_unlock(p->mainloop); - return (pa_usec_t) -1; -} diff --git a/pipewire-pulseaudio/src/strbuf.c b/pipewire-pulseaudio/src/strbuf.c deleted file mode 100644 index 9e281d578..000000000 --- a/pipewire-pulseaudio/src/strbuf.c +++ /dev/null @@ -1,193 +0,0 @@ -/*** - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include - -#include "internal.h" -#include "strbuf.h" - -/* A chunk of the linked list that makes up the string */ -struct chunk { - struct chunk *next; - size_t length; -}; - -#define CHUNK_TO_TEXT(c) ((char*) (c) + PA_ALIGN(sizeof(struct chunk))) - -struct pa_strbuf { - size_t length; - struct chunk *head, *tail; -}; - -pa_strbuf *pa_strbuf_new(void) { - pa_strbuf *sb; - - sb = pa_xnew(pa_strbuf, 1); - sb->length = 0; - sb->head = sb->tail = NULL; - - return sb; -} - -void pa_strbuf_free(pa_strbuf *sb) { - pa_assert(sb); - - while (sb->head) { - struct chunk *c = sb->head; - sb->head = sb->head->next; - pa_xfree(c); - } - - pa_xfree(sb); -} - -/* Make a C string from the string buffer. The caller has to free - * string with pa_xfree(). */ -char *pa_strbuf_to_string(pa_strbuf *sb) { - char *t, *e; - struct chunk *c; - - pa_assert(sb); - - e = t = pa_xmalloc(sb->length+1); - - for (c = sb->head; c; c = c->next) { - pa_assert((size_t) (e-t) <= sb->length); - memcpy(e, CHUNK_TO_TEXT(c), c->length); - e += c->length; - } - - /* Trailing NUL */ - *e = 0; - - pa_assert(e == t+sb->length); - - return t; -} - -/* Combination of pa_strbuf_free() and pa_strbuf_to_string() */ -char *pa_strbuf_to_string_free(pa_strbuf *sb) { - char *t; - - pa_assert(sb); - t = pa_strbuf_to_string(sb); - pa_strbuf_free(sb); - - return t; -} - -/* Append a string to the string buffer */ -void pa_strbuf_puts(pa_strbuf *sb, const char *t) { - - pa_assert(sb); - pa_assert(t); - - pa_strbuf_putsn(sb, t, strlen(t)); -} - -/* Append a character to the string buffer */ -void pa_strbuf_putc(pa_strbuf *sb, char c) { - pa_assert(sb); - - pa_strbuf_putsn(sb, &c, 1); -} - -/* Append a new chunk to the linked list */ -static void append(pa_strbuf *sb, struct chunk *c) { - pa_assert(sb); - pa_assert(c); - - if (sb->tail) { - pa_assert(sb->head); - sb->tail->next = c; - } else { - pa_assert(!sb->head); - sb->head = c; - } - - sb->tail = c; - sb->length += c->length; - c->next = NULL; -} - -/* Append up to l bytes of a string to the string buffer */ -void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { - struct chunk *c; - - pa_assert(sb); - pa_assert(t); - - if (!l) - return; - - c = pa_xmalloc(PA_ALIGN(sizeof(struct chunk)) + l); - c->length = l; - memcpy(CHUNK_TO_TEXT(c), t, l); - - append(sb, c); -} - -/* Append a printf() style formatted string to the string buffer. */ -/* The following is based on an example from the GNU libc documentation */ -size_t pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { - size_t size = 100; - struct chunk *c = NULL; - - pa_assert(sb); - pa_assert(format); - - for(;;) { - va_list ap; - int r; - - c = pa_xrealloc(c, PA_ALIGN(sizeof(struct chunk)) + size); - - va_start(ap, format); - r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap); - CHUNK_TO_TEXT(c)[size-1] = 0; - va_end(ap); - - if (r > -1 && (size_t) r < size) { - c->length = (size_t) r; - append(sb, c); - return (size_t) r; - } - - if (r > -1) /* glibc 2.1 */ - size = (size_t) r+1; - else /* glibc 2.0 */ - size *= 2; - } -} - -bool pa_strbuf_isempty(pa_strbuf *sb) { - pa_assert(sb); - - return sb->length <= 0; -} diff --git a/pipewire-pulseaudio/src/strbuf.h b/pipewire-pulseaudio/src/strbuf.h deleted file mode 100644 index f5d9921e6..000000000 --- a/pipewire-pulseaudio/src/strbuf.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef foostrbufhfoo -#define foostrbufhfoo - -/*** - 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, see . -***/ - -#include - -typedef struct pa_strbuf pa_strbuf; - -pa_strbuf *pa_strbuf_new(void); -void pa_strbuf_free(pa_strbuf *sb); -char *pa_strbuf_to_string(pa_strbuf *sb); -char *pa_strbuf_to_string_free(pa_strbuf *sb); - -size_t pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -void pa_strbuf_puts(pa_strbuf *sb, const char *t); -void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); -void pa_strbuf_putc(pa_strbuf *sb, char c); - -bool pa_strbuf_isempty(pa_strbuf *sb); - -#endif diff --git a/pipewire-pulseaudio/src/stream.c b/pipewire-pulseaudio/src/stream.c deleted file mode 100644 index 18fff4687..000000000 --- a/pipewire-pulseaudio/src/stream.c +++ /dev/null @@ -1,1952 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include "core-format.h" -#include "internal.h" - -#define MIN_SAMPLES 24u -#define MIN_BUFFERS 8u -#define MAX_BUFFERS 64u - -#define MAX_BUFFER_SAMPLES (8*1024u) -#define MAX_SIZE (4*1024*1024u) - -static void dump_buffer_attr(pa_stream *s, pa_buffer_attr *attr) -{ - char b[1024]; - pw_log_debug("stream %p: sample: %s", s, pa_sample_spec_snprint(b, sizeof(b), &s->sample_spec)); - pw_log_debug("stream %p: stride: %zu", s, pa_frame_size(&s->sample_spec)); - pw_log_debug("stream %p: maxlength: %u", s, attr->maxlength); - pw_log_debug("stream %p: tlength: %u", s, attr->tlength); - pw_log_debug("stream %p: minreq: %u", s, attr->minreq); - pw_log_debug("stream %p: prebuf: %u", s, attr->prebuf); - pw_log_debug("stream %p: fragsize: %u", s, attr->fragsize); -} - -static void stream_destroy(void *data) -{ - pa_stream *s = data; - s->stream = NULL; -} - -static void stream_state_changed(void *data, enum pw_stream_state old, - enum pw_stream_state state, const char *error) -{ - pa_stream *s = data; - pa_context *c = s->context; - - pw_log_debug("stream %p: state '%s'->'%s' (%d)", s, pw_stream_state_as_string(old), - pw_stream_state_as_string(state), s->state); - - if (s->state == PA_STREAM_TERMINATED || c == NULL) - return; - - switch(state) { - case PW_STREAM_STATE_ERROR: - pa_stream_set_state(s, PA_STREAM_FAILED); - break; - case PW_STREAM_STATE_UNCONNECTED: - if (!s->disconnecting) { - pa_context_set_error(c, PA_ERR_KILLED); - pa_stream_set_state(s, PA_STREAM_FAILED); - } - break; - case PW_STREAM_STATE_CONNECTING: - pa_stream_set_state(s, PA_STREAM_CREATING); - break; - case PW_STREAM_STATE_PAUSED: - s->stream_index = pw_stream_get_node_id(s->stream); - if (!s->suspended) { - s->suspended = true; - if (!c->disconnect && !s->corked && s->state == PA_STREAM_READY && s->suspended_callback) - s->suspended_callback(s, s->suspended_userdata); - } - break; - case PW_STREAM_STATE_STREAMING: - if (s->suspended) { - s->suspended = false; - if (!c->disconnect && !s->corked && s->state == PA_STREAM_READY && s->started_callback) - s->started_callback(s, s->started_userdata); - } - break; - } -} - -static const struct spa_pod *get_buffers_param(pa_stream *s, pa_buffer_attr *attr, struct spa_pod_builder *b) -{ - const struct spa_pod *param; - uint32_t blocks, buffers, size, maxsize, stride; - - blocks = 1; - stride = pa_frame_size(&s->sample_spec); - - maxsize = attr->tlength; - size = attr->minreq; - buffers = SPA_CLAMP(maxsize / size, MIN_BUFFERS, MAX_BUFFERS); - - pw_log_info("stream %p: stride %d maxsize %d size %u buffers %d", s, stride, maxsize, - size, buffers); - - param = spa_pod_builder_add_object(b, - SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, - SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(buffers, MIN_BUFFERS, MAX_BUFFERS), - SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(blocks), - SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - size, size, maxsize), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride), - SPA_PARAM_BUFFERS_align, SPA_POD_Int(16)); - return param; -} - -static void patch_buffer_attr(pa_stream *s, pa_buffer_attr *attr, pa_stream_flags_t *flags) { - const char *e, *str; - char buf[100]; - uint32_t stride, period; - - pa_assert(s); - pa_assert(attr); - - e = getenv("PULSE_LATENCY_MSEC"); - if (e == NULL) { - str = getenv("PIPEWIRE_LATENCY"); - if (str) { - int num, denom; - if (sscanf(str, "%u/%u", &num, &denom) == 2 && denom != 0) { - snprintf(buf, sizeof(buf)-1, "%"PRIu64, num * PA_MSEC_PER_SEC / denom); - e = buf; - } - } - } - - if (e) { - uint32_t ms; - pa_sample_spec ss; - - pa_sample_spec_init(&ss); - - if (pa_sample_spec_valid(&s->sample_spec)) - ss = s->sample_spec; - else if (s->n_formats == 1) - pa_format_info_to_sample_spec(s->req_formats[0], &ss, NULL); - - if ((ms = atoi(e)) == 0) { - pa_log_debug("Failed to parse $PULSE_LATENCY_MSEC: %s", e); - } - else if (!pa_sample_spec_valid(&ss)) { - pa_log_debug("Ignoring $PULSE_LATENCY_MSEC: %s (invalid sample spec)", e); - } - else { - attr->maxlength = (uint32_t) -1; - attr->tlength = pa_usec_to_bytes(ms * PA_USEC_PER_MSEC, &ss); - attr->minreq = (uint32_t) -1; - attr->prebuf = (uint32_t) -1; - attr->fragsize = attr->tlength; - - if (flags) - *flags |= PA_STREAM_ADJUST_LATENCY; - } - } - - if (flags && !SPA_FLAG_IS_SET(*flags, PA_STREAM_ADJUST_LATENCY)) { - if (attr->maxlength == 0) - attr->maxlength = -1; - if (attr->tlength == 0) - attr->tlength = -1; - if (attr->minreq == 0) - attr->minreq = -1; - if (attr->prebuf == 0) - attr->prebuf = -1; - if (attr->fragsize == 0) - attr->fragsize = -1; - period = 100; - } else { - period = 20; - } - - dump_buffer_attr(s, attr); - - stride = pa_frame_size(&s->sample_spec); - if (attr->maxlength == (uint32_t) -1 || attr->maxlength == 0) - attr->maxlength = MAX_SIZE; /* 4MB is the maximum queue length PulseAudio <= 0.9.9 supported. */ - attr->maxlength -= attr->maxlength % stride; - attr->maxlength = SPA_MAX(attr->maxlength, stride); - - if (attr->tlength == (uint32_t) -1) - attr->tlength = (uint32_t) pa_usec_to_bytes(2*PA_USEC_PER_SEC, &s->sample_spec); - attr->tlength = SPA_MIN(attr->tlength, attr->maxlength); - attr->tlength -= attr->tlength % stride; - - if (attr->minreq == (uint32_t) -1) - attr->minreq = pa_usec_to_bytes(period*PA_USEC_PER_MSEC, &s->sample_spec); - attr->minreq = SPA_MIN(attr->minreq, attr->tlength / 4); - attr->minreq = SPA_MAX(attr->minreq, MIN_SAMPLES * stride); - attr->minreq -= attr->minreq % stride; - attr->minreq = SPA_MAX(attr->minreq, stride); - - attr->tlength = SPA_MAX(attr->tlength, attr->minreq * 4); - - if (attr->prebuf == (uint32_t) -1) - attr->prebuf = attr->tlength - attr->minreq; - attr->prebuf = SPA_MIN(attr->prebuf, attr->tlength - attr->minreq); - attr->prebuf -= attr->prebuf % stride; - attr->prebuf = SPA_MAX(attr->prebuf, stride); - - if (attr->fragsize == (uint32_t) -1) - attr->fragsize = pa_usec_to_bytes(period*PA_USEC_PER_MSEC, &s->sample_spec); - attr->fragsize = SPA_MIN(attr->fragsize, attr->tlength / 4); - attr->fragsize -= attr->fragsize % stride; - attr->fragsize = SPA_MAX(attr->fragsize, stride); - - dump_buffer_attr(s, attr); -} - -static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *param) -{ - pa_stream *s = data; - const struct spa_pod *params[4]; - uint32_t n_params = 0, stride, latency; - uint8_t buffer[4096]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - struct spa_dict_item items[1]; - char str[64]; - int res; - - if (param == NULL || id != SPA_PARAM_Format) - return; - - if ((res = pa_format_parse_param(param, &s->sample_spec, &s->channel_map)) < 0) { - pw_stream_set_error(s->stream, res, "unhandled format"); - return; - } - - if (s->format) - pa_format_info_free(s->format); - s->format = pa_format_info_from_sample_spec(&s->sample_spec, &s->channel_map); - if (s->format == NULL) { - pw_stream_set_error(s->stream, -errno, "unhandled format"); - return; - } - - patch_buffer_attr(s, &s->buffer_attr, &s->flags); - - pa_stream_set_state(s, PA_STREAM_READY); - - if (s->corked) - pw_stream_set_active(s->stream, false); - - stride = pa_frame_size(&s->sample_spec); - - if (s->direction == PA_STREAM_RECORD) { - latency = s->buffer_attr.fragsize / stride; - } else { - latency = s->buffer_attr.minreq * 2 / stride; - } - snprintf(str, sizeof(str), "%u/%u", latency, s->sample_spec.rate); - items[0] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_LATENCY, str); - pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 1)); - - params[n_params++] = get_buffers_param(s, &s->buffer_attr, &b); - pw_stream_update_params(s->stream, params, n_params); -} - -static void stream_control_info(void *data, uint32_t id, const struct pw_stream_control *control) -{ - pa_stream *s = data; - - pw_log_debug("stream %p: control %d", s, id); - switch (id) { - case SPA_PROP_mute: - if (control->n_values > 0) - s->mute = control->values[0] >= 0.5f; - break; - case SPA_PROP_channelVolumes: - s->n_channel_volumes = SPA_MAX(SPA_AUDIO_MAX_CHANNELS, control->n_values); - memcpy(s->channel_volumes, control->values, s->n_channel_volumes * sizeof(float)); - break; - default: - break; - } -} - -static void stream_add_buffer(void *data, struct pw_buffer *buffer) -{ - pa_stream *s = data; - uint32_t maxsize = buffer->buffer->datas[0].maxsize; - buffer->size = 0; - s->maxsize += maxsize; - s->maxblock = SPA_MIN(maxsize, s->maxblock); -} - -static void stream_remove_buffer(void *data, struct pw_buffer *buffer) -{ - pa_stream *s = data; - struct pa_mem *m = buffer->user_data; - s->maxsize -= buffer->buffer->datas[0].maxsize; - s->maxblock = INT_MAX; - if (m != NULL) { - spa_list_append(&s->free, &m->link); - m->user_data = NULL; - buffer->user_data = NULL; - pw_log_trace("remove %p", m); - } -} - -static void update_timing_info(pa_stream *s) -{ - struct pw_time pwt; - pa_timing_info *ti = &s->timing_info; - size_t stride = pa_frame_size(&s->sample_spec); - int64_t delay, pos; - - pw_stream_get_time(s->stream, &pwt); - s->timing_info_valid = false; - - pa_timeval_store(&ti->timestamp, pwt.now / SPA_NSEC_PER_USEC); - ti->synchronized_clocks = true; - ti->transport_usec = 0; - ti->playing = 1; - ti->write_index_corrupt = false; - ti->read_index_corrupt = false; - - if (pwt.rate.denom > 0) { - uint64_t ticks = pwt.ticks; - if (!s->have_time) - s->ticks_base = ticks; - if (ticks > s->ticks_base) - pos = ((ticks - s->ticks_base) * s->sample_spec.rate / pwt.rate.denom) * stride; - else - pos = 0; - delay = pwt.delay * SPA_USEC_PER_SEC / pwt.rate.denom; - s->have_time = true; - } else { - pos = delay = 0; - s->have_time = false; - } - if (s->direction == PA_STREAM_PLAYBACK) { - ti->sink_usec = delay; - ti->configured_sink_usec = delay; - ti->read_index = pos; - } else { - ti->source_usec = delay; - ti->configured_source_usec = delay; - ti->write_index = pos; - } - s->queued_bytes = pwt.queued; - s->timing_info_valid = true; - - pw_log_trace("stream %p: %"PRIu64" rate:%d/%d ticks:%"PRIu64" pos:%"PRIu64" delay:%"PRIi64 " read:%"PRIu64 - " write:%"PRIu64" queued:%"PRIi64, - s, pwt.queued, s->sample_spec.rate, pwt.rate.denom, pwt.ticks, pos, pwt.delay, - ti->read_index, ti->write_index, ti->read_index - ti->write_index); -} - -static void queue_output(pa_stream *s) -{ - struct pa_mem *m, *t, *old; - struct pw_buffer *buf; - - spa_list_for_each_safe(m, t, &s->ready, link) { - buf = pw_stream_dequeue_buffer(s->stream); - if (buf == NULL) - break; - - if ((old = buf->user_data) != NULL) { - pw_log_trace("queue %p", old); - spa_list_append(&s->free, &old->link); - old->user_data = NULL; - } - - pw_log_trace("queue %p", m); - spa_list_remove(&m->link); - s->ready_bytes -= m->size; - s->queued_bytes += m->size; - - buf->buffer->datas[0].maxsize = m->maxsize; - buf->buffer->datas[0].data = m->data; - buf->buffer->datas[0].chunk->offset = m->offset; - buf->buffer->datas[0].chunk->size = m->size; - buf->user_data = m; - buf->size = m->size; - m->user_data = buf; - - pw_stream_queue_buffer(s->stream, buf); - } -} - -struct pa_mem *alloc_mem(pa_stream *s, size_t len) -{ - struct pa_mem *m; - if (spa_list_is_empty(&s->free)) { - if (len > s->maxblock) - len = s->maxblock; - m = calloc(1, sizeof(struct pa_mem) + len); - if (m == NULL) - return NULL; - m->data = SPA_MEMBER(m, sizeof(struct pa_mem), void); - m->maxsize = len; - pw_log_trace("alloc %p", m); - } else { - m = spa_list_first(&s->free, struct pa_mem, link); - spa_list_remove(&m->link); - pw_log_trace("reuse %p", m); - } - return m; -} - -static void pull_input(pa_stream *s) -{ - struct pw_buffer *buf; - struct pa_mem *m; - - while ((buf = pw_stream_dequeue_buffer(s->stream)) != NULL) { - if ((m = alloc_mem(s, 0)) == NULL) { - pw_log_error("stream %p: Can't alloc mem: %m", s); - pw_stream_queue_buffer(s->stream, buf); - continue; - } - m->data = buf->buffer->datas[0].data; - m->maxsize = buf->buffer->datas[0].maxsize; - m->offset = buf->buffer->datas[0].chunk->offset; - m->size = buf->buffer->datas[0].chunk->size; - m->user_data = buf; - buf->user_data = m; - - pw_log_trace("input %p, size:%zd ready:%zd", m, m->size, s->ready_bytes); - spa_list_append(&s->ready, &m->link); - s->ready_bytes += m->size; - } -} - - -static inline uint32_t queued_size(const pa_stream *s, uint64_t elapsed) -{ - uint64_t queued; - const pa_timing_info *i = &s->timing_info; - queued = i->write_index - SPA_MIN(i->read_index, i->write_index); - queued -= SPA_MIN(queued, elapsed); - return queued; -} -static inline uint32_t target_queue(const pa_stream *s) -{ - return s->buffer_attr.tlength; -} - -static inline uint32_t wanted_size(const pa_stream *s, uint32_t queued, uint32_t target) -{ - return target - SPA_MIN(queued, target); -} - -static inline uint32_t required_size(const pa_stream *s) -{ - return s->buffer_attr.minreq; -} - -static inline uint32_t writable_size(const pa_stream *s, uint64_t elapsed) -{ - uint32_t queued, target, wanted, required; - - queued = queued_size(s, elapsed); - target = target_queue(s); - wanted = wanted_size(s, queued, target); - required = required_size(s); - - pw_log_trace("stream %p, queued:%u target:%u wanted:%u required:%u", - s, queued, target, wanted, required); - if (SPA_FLAG_IS_SET(s->flags, PA_STREAM_ADJUST_LATENCY)) - if (queued >= wanted) - wanted = 0; - if (wanted < required) - wanted = 0; - - return wanted; -} - -static void stream_process(void *data) -{ - pa_stream *s = data; - - pw_log_trace("stream %p:", s); - update_timing_info(s); - - if (s->direction == PA_STREAM_PLAYBACK) { - uint32_t writable; - - queue_output(s); - - writable = writable_size(s, 0); - - if (s->write_callback && s->state == PA_STREAM_READY && writable > 0) - s->write_callback(s, writable, s->write_userdata); - } - else { - pull_input(s); - - if (s->read_callback && s->ready_bytes > 0 && s->state == PA_STREAM_READY) - s->read_callback(s, s->ready_bytes, s->read_userdata); - } -} - -static void stream_drained(void *data) -{ - pa_stream *s = data; - - pw_log_debug("drained"); - - if (s->drain) { - pa_operation *o = s->drain; - pa_operation_ref(o); - if (o->callback) - o->callback(o, o->userdata); - pa_operation_unref(o); - s->drain = NULL; - } -} - -static const struct pw_stream_events stream_events = -{ - PW_VERSION_STREAM_EVENTS, - .destroy = stream_destroy, - .state_changed = stream_state_changed, - .param_changed = stream_param_changed, - .control_info = stream_control_info, - .add_buffer = stream_add_buffer, - .remove_buffer = stream_remove_buffer, - .process = stream_process, - .drained = stream_drained, -}; - -static pa_stream* stream_new(pa_context *c, const char *name, - const pa_sample_spec *ss, const pa_channel_map *map, - pa_format_info * const * formats, unsigned int n_formats, - pa_proplist *p) -{ - pa_stream *s; - char str[1024]; - unsigned int i; - - spa_assert(c); - spa_assert(c->refcount >= 1); - pa_assert((ss == NULL && map == NULL) || (formats == NULL && n_formats == 0)); - pa_assert(n_formats < PA_MAX_FORMATS); - - PA_CHECK_VALIDITY_RETURN_NULL(c, name || - (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID); - - s = calloc(1, sizeof(pa_stream)); - if (s == NULL) - return NULL; - - s->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); - if (name) - pa_proplist_sets(s->proplist, PA_PROP_MEDIA_NAME, name); - else - name = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME); - - s->refcount = 1; - s->context = c; - spa_list_init(&s->free); - spa_list_init(&s->ready); - - s->direction = PA_STREAM_NODIRECTION; - s->state = PA_STREAM_UNCONNECTED; - s->flags = 0; - s->have_time = false; - - if (ss) - s->sample_spec = *ss; - else - pa_sample_spec_init(&s->sample_spec); - - if (map) - s->channel_map = *map; - else - pa_channel_map_init(&s->channel_map); - - pw_log_debug("stream %p: channel map: %p %s", s, - map, pa_channel_map_snprint(str, sizeof(str), &s->channel_map)); - - s->n_formats = 0; - if (formats) { - s->n_formats = n_formats; - for (i = 0; i < n_formats; i++) { - s->req_formats[i] = pa_format_info_copy(formats[i]); - pw_log_debug("format %d: %s", i, - pa_format_info_snprint(str, sizeof(str), formats[i])); - } - } - s->format = NULL; - - s->direct_on_input = PA_INVALID_INDEX; - - s->stream_index = PA_INVALID_INDEX; - s->maxblock = INT_MAX; - - s->device_index = PA_INVALID_INDEX; - s->device_name = NULL; - - spa_list_append(&c->streams, &s->link); - pa_stream_ref(s); - - return s; -} - -SPA_EXPORT -pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, - const pa_channel_map *map) -{ - return stream_new(c, name, ss, map, NULL, 0, NULL); -} - -SPA_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) -{ - pa_channel_map tmap; - - if (!map) - PA_CHECK_VALIDITY_RETURN_NULL(c, map = pa_channel_map_init_extend(&tmap, - ss->channels, PA_CHANNEL_MAP_DEFAULT), PA_ERR_INVALID); - - return stream_new(c, name, ss, map, NULL, 0, p); -} - -SPA_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) -{ - return stream_new(c, name, NULL, NULL, formats, n_formats, p); -} - -static void stream_unlink(pa_stream *s) -{ - pa_context *c = s->context; - pa_operation *o, *t; - - if (c == NULL) - return; - - pw_log_debug("stream %p: unlink %d", s, s->refcount); - - spa_list_for_each_safe(o, t, &c->operations, link) { - if (o->stream == s) - pa_operation_cancel(o); - } - s->drain = NULL; - - spa_list_remove(&s->link); - if (s->stream) - pw_stream_set_active(s->stream, false); - - s->context = NULL; - pa_stream_unref(s); -} - -static void stream_free(pa_stream *s) -{ - int i; - struct pa_mem *m; - - pw_log_debug("stream %p", s); - - - if (s->stream) { - spa_hook_remove(&s->stream_listener); - pw_stream_destroy(s->stream); - } - if (s->global) - s->global->stream = NULL; - - spa_list_consume(m, &s->free, link) { - pw_log_trace("free %p", m); - spa_list_remove(&m->link); - free(m); - } - if (s->proplist) - pa_proplist_free(s->proplist); - - for (i = 0; i < s->n_formats; i++) - pa_format_info_free(s->req_formats[i]); - - if (s->format) - pa_format_info_free(s->format); - - free(s->device_name); - free(s); -} - -SPA_EXPORT -void pa_stream_unref(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - pw_log_debug("stream %p: ref %d", s, s->refcount); - if (--s->refcount == 0) - stream_free(s); -} - -SPA_EXPORT -pa_stream *pa_stream_ref(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - s->refcount++; - pw_log_debug("stream %p: ref %d", s, s->refcount); - return s; -} - -SPA_EXPORT -pa_stream_state_t pa_stream_get_state(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - return s->state; -} - -SPA_EXPORT -pa_context* pa_stream_get_context(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - return s->context; -} - -SPA_EXPORT -uint32_t pa_stream_get_index(PA_CONST pa_stream *s) -{ - uint32_t idx; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - idx = s->stream_index; - pw_log_debug("stream %p: index %u", s, idx); - return idx; -} - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == st) - return; - - pa_stream_ref(s); - - pw_log_debug("stream %p: state %d -> %d", s, s->state, st); - s->state = st; - - if (s->state_callback) - s->state_callback(s, s->state_userdata); - - if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED)) - stream_unlink(s); - - pa_stream_unref(s); -} - - -SPA_EXPORT -uint32_t pa_stream_get_device_index(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, - PA_ERR_BADSTATE, PA_INVALID_INDEX); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, - PA_ERR_BADSTATE, PA_INVALID_INDEX); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->device_index != PA_INVALID_INDEX, - PA_ERR_BADSTATE, PA_INVALID_INDEX); - - pw_log_trace("stream %p: %d", s, s->device_index); - return s->device_index; -} - -SPA_EXPORT -const char *pa_stream_get_device_name(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->device_name, PA_ERR_BADSTATE); - - pw_log_trace("stream %p: %s %d", s, s->device_name, s->device_index); - return s->device_name; -} - -SPA_EXPORT -int pa_stream_is_suspended(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - return s->suspended && !s->corked; -} - -SPA_EXPORT -int pa_stream_is_corked(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_trace("stream %p: corked %d", s, s->corked); - return s->corked; -} - -static int create_stream(pa_stream_direction_t direction, - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - const pa_cvolume *volume, - pa_stream *sync_stream) -{ - int res; - enum pw_stream_flags fl; - const struct spa_pod *params[PA_MAX_FORMATS+1]; - uint32_t i, n_params = 0; - uint8_t buffer[4096]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - const char *str; - uint32_t devid, n_items; - struct spa_dict_item items[7]; - bool monitor, no_remix; - const char *name; - pa_context *c = s->context; - - spa_assert(s); - spa_assert(s->refcount >= 1); - spa_assert(direction == PA_STREAM_PLAYBACK || direction == PA_STREAM_RECORD); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direct_on_input == PA_INVALID_INDEX || direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED| - PA_STREAM_INTERPOLATE_TIMING| - PA_STREAM_NOT_MONOTONIC| - PA_STREAM_AUTO_TIMING_UPDATE| - PA_STREAM_NO_REMAP_CHANNELS| - PA_STREAM_NO_REMIX_CHANNELS| - PA_STREAM_FIX_FORMAT| - PA_STREAM_FIX_RATE| - PA_STREAM_FIX_CHANNELS| - PA_STREAM_DONT_MOVE| - PA_STREAM_VARIABLE_RATE| - PA_STREAM_PEAK_DETECT| - PA_STREAM_START_MUTED| - PA_STREAM_ADJUST_LATENCY| - PA_STREAM_EARLY_REQUESTS| - PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND| - PA_STREAM_START_UNMUTED| - PA_STREAM_FAIL_ON_SUSPEND| - PA_STREAM_RELATIVE_VOLUME| - PA_STREAM_PASSTHROUGH)), PA_ERR_INVALID); - - PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, (flags & (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS)) != (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS), PA_ERR_INVALID); - - - pw_log_info("stream %p: connect %s %08x", s, dev, flags); - - name = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME); - - s->stream = pw_stream_new(c->core, - name, pw_properties_copy(c->props)); - pw_stream_add_listener(s->stream, &s->stream_listener, &stream_events, s); - - s->direction = direction; - s->timing_info_valid = false; - s->disconnecting = false; - if (volume) { - for (i = 0; i < volume->channels; i++) - s->channel_volumes[i] = pa_sw_volume_to_linear(volume->values[i]); - s->n_channel_volumes = volume->channels; - } else { - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - s->channel_volumes[i] = 1.0; - s->n_channel_volumes = 0; - } - s->mute = false; - s->flags = flags; - - pa_stream_set_state(s, PA_STREAM_CREATING); - - fl = PW_STREAM_FLAG_AUTOCONNECT | - PW_STREAM_FLAG_MAP_BUFFERS; - - s->corked = SPA_FLAG_IS_SET(flags, PA_STREAM_START_CORKED); - - if (flags & PA_STREAM_PASSTHROUGH) - fl |= PW_STREAM_FLAG_EXCLUSIVE; - if (flags & PA_STREAM_DONT_MOVE) - fl |= PW_STREAM_FLAG_DONT_RECONNECT; - monitor = (flags & PA_STREAM_PEAK_DETECT); - no_remix = (flags & PA_STREAM_NO_REMIX_CHANNELS); - - if (attr) - s->buffer_attr = *attr; - - if (pa_sample_spec_valid(&s->sample_spec)) { - params[n_params++] = pa_format_build_param(&b, SPA_PARAM_EnumFormat, - &s->sample_spec, &s->channel_map); - } - else { - pa_sample_spec ss; - pa_channel_map chmap; - int i; - - for (i = 0; i < s->n_formats; i++) { - if ((res = pa_format_info_to_sample_spec(s->req_formats[i], &ss, NULL)) < 0) { - char buf[4096]; - pw_log_warn("can't convert format %d %s", res, - pa_format_info_snprint(buf, sizeof(buf), s->req_formats[i])); - continue; - } - if (pa_format_info_get_channel_map(s->req_formats[i], &chmap) < 0) - pa_channel_map_init_extend(&chmap, ss.channels, PA_CHANNEL_MAP_DEFAULT); - - params[n_params++] = pa_format_build_param(&b, SPA_PARAM_EnumFormat, - &ss, &chmap); - } - } - - if (direction == PA_STREAM_RECORD) - devid = s->direct_on_input; - else - devid = PW_ID_ANY; - - if (dev == NULL && devid == PW_ID_ANY) { - dev = getenv("PIPEWIRE_NODE"); - } - else if (dev != NULL && devid == PW_ID_ANY) { - if ((devid = atoi(dev)) == 0) - devid = PW_ID_ANY; - else if (devid & PA_IDX_FLAG_MONITOR) - devid &= PA_IDX_MASK_MONITOR; - - if (devid == PW_ID_ANY) { - if (pa_endswith(dev, ".monitor")) - dev = strndupa(dev, strlen(dev) - 8); - } - } - - if ((str = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_ROLE)) != NULL) { - if (strcmp(str, "video") == 0) - str = "Movie"; - else if (strcmp(str, "music") == 0) - str = "Music"; - else if (strcmp(str, "game") == 0) - str = "Game"; - else if (strcmp(str, "event") == 0) - str = "Notification"; - else if (strcmp(str, "phone") == 0) - str = "Communication"; - else if (strcmp(str, "animation") == 0) - str = "Movie"; - else if (strcmp(str, "production") == 0) - str = "Production"; - else if (strcmp(str, "a11y") == 0) - str = "Accessibility"; - else if (strcmp(str, "test") == 0) - str = "Test"; - else - str = "Music"; - } - - n_items = 0; - items[n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_TYPE, "Audio"); - items[n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_CATEGORY, - direction == PA_STREAM_PLAYBACK ? - "Playback" : monitor ? "Monitor" : "Capture"); - if (str != NULL) - items[n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_ROLE, str); - if (monitor) - items[n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_STREAM_MONITOR, "true"); - if (no_remix) - items[n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_STREAM_DONT_REMIX, "true"); - if (devid == PW_ID_ANY && dev != NULL) - items[n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, dev); - pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, n_items)); - - res = pw_stream_connect(s->stream, - direction == PA_STREAM_PLAYBACK ? - PW_DIRECTION_OUTPUT : - PW_DIRECTION_INPUT, - devid, - fl, - params, n_params); - - return res; -} - -SPA_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) -{ - return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); -} - -SPA_EXPORT -int pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags) -{ - return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); -} - -static void on_disconnected(pa_operation *o, void *userdata) -{ - pa_stream *s = o->stream; - pw_log_debug("stream %p", s); - pa_stream_set_state(s, PA_STREAM_TERMINATED); - pa_operation_done(o); -} - -SPA_EXPORT -int pa_stream_disconnect(pa_stream *s) -{ - pa_operation *o; - pa_context *c = s->context; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(c, c != NULL, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pw_log_debug("stream %p: disconnect", s); - pa_stream_ref(s); - - s->disconnecting = true; - s->stream_index = PA_INVALID_INDEX; - pw_stream_disconnect(s->stream); - - o = pa_operation_new(c, s, on_disconnected, 0); - pa_operation_sync(o); - pa_operation_unref(o); - pa_stream_unref(s); - - return 0; -} - -SPA_EXPORT -int pa_stream_begin_write( - pa_stream *s, - void **data, - size_t *nbytes) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || - s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID); - - if (s->mem == NULL) - s->mem = alloc_mem(s, *nbytes); - if (s->mem == NULL) { - *data = NULL; - *nbytes = 0; - return -errno; - } - s->mem->offset = s->mem->size = 0; - *data = s->mem->data; - *nbytes = *nbytes != (size_t)-1 ? SPA_MIN(*nbytes, s->mem->maxsize) : s->mem->maxsize; - - pw_log_trace("buffer %p %zd %p", *data, *nbytes, s->mem); - - return 0; -} - -SPA_EXPORT -int pa_stream_cancel_write(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || - s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - if (s->mem == NULL) - return 0; - - pw_log_trace("cancel %p %p %zd", s->mem, s->mem->data, s->mem->size); - - spa_list_prepend(&s->free, &s->mem->link); - s->mem = NULL; - - return 0; -} - -SPA_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) -{ - return pa_stream_write_ext_free(s, data, nbytes, free_cb, (void*) data, offset, seek); -} - -SPA_EXPORT -int pa_stream_write_ext_free(pa_stream *s, - const void *data, - size_t nbytes, - pa_free_cb_t free_cb, - void *free_cb_data, - int64_t offset, - pa_seek_mode_t seek) -{ - const void *src = data; - size_t towrite; - - spa_assert(s); - spa_assert(s->refcount >= 1); - spa_assert(data); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || - s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || - (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, - s->mem == NULL || - ((data >= s->mem->data) && - ((const char*) data + nbytes <= (const char*) s->mem->data + s->mem->maxsize)), - PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, offset % pa_frame_size(&s->sample_spec) == 0, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, nbytes % pa_frame_size(&s->sample_spec) == 0, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, !free_cb || !s->buffer, PA_ERR_INVALID); - - pw_log_trace("stream %p: write %zd bytes", s, nbytes); - - towrite = nbytes; - while (towrite > 0) { - size_t dsize = towrite; - if (s->mem == NULL) { - void *dst; - if (pa_stream_begin_write(s, &dst, &dsize) < 0 || - dst == NULL || dsize == 0) { - pw_log_error("stream %p: out of buffers, wanted %zd bytes", s, nbytes); - break; - } - memcpy(dst, src, dsize); - src = SPA_MEMBER(src, dsize, void); - } else { - s->mem->offset = SPA_PTRDIFF(src, s->mem->data); - } - towrite -= dsize; - s->mem->size = dsize; - if (s->mem->size >= s->mem->maxsize || towrite == 0) { - spa_list_append(&s->ready, &s->mem->link); - s->ready_bytes += s->mem->size; - s->mem = NULL; - queue_output(s); - } - } - if (free_cb) - free_cb(free_cb_data); - - s->timing_info.write_index += nbytes; - s->timing_info.since_underrun += nbytes; - pw_log_trace("stream %p: written %zd bytes", s, nbytes); - - return 0; -} - -SPA_EXPORT -int pa_stream_peek(pa_stream *s, - const void **data, - size_t *nbytes) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - spa_assert(data); - spa_assert(nbytes); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - - if (spa_list_is_empty(&s->ready)) { - errno = EPIPE; - pw_log_error("stream %p: no buffer: %m", s); - *data = NULL; - *nbytes = 0; - return 0; - } - s->mem = spa_list_first(&s->ready, struct pa_mem, link); - pw_log_trace("peek %p", s->mem); - - *data = SPA_MEMBER(s->mem->data, s->mem->offset, void); - *nbytes = s->mem->size; - - pw_log_trace("stream %p: %p %zd", s, *data, *nbytes); - - return 0; -} - -SPA_EXPORT -int pa_stream_drop(pa_stream *s) -{ - size_t nbytes; - struct pw_buffer *buf; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->mem, PA_ERR_BADSTATE); - - nbytes = s->mem->size; - - pw_log_trace("stream %p %zd", s, nbytes); - spa_list_remove(&s->mem->link); - s->ready_bytes -= nbytes; - - s->timing_info.read_index += nbytes; - - buf = s->mem->user_data; - pw_stream_queue_buffer(s->stream, buf); - buf->user_data = NULL; - - pw_log_trace("drop %p", s->mem); - spa_list_append(&s->free, &s->mem->link); - s->mem->user_data = NULL; - s->mem = NULL; - - return 0; -} - -SPA_EXPORT -size_t pa_stream_writable_size(PA_CONST pa_stream *s) -{ - const pa_timing_info *i; - uint64_t now, then, elapsed; - struct timespec ts; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, - PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, - PA_ERR_BADSTATE, (size_t) -1); - - i = &s->timing_info; - - if (s->have_time) { - clock_gettime(CLOCK_MONOTONIC, &ts); - now = SPA_TIMESPEC_TO_USEC(&ts); - then = SPA_TIMEVAL_TO_USEC(&i->timestamp); - elapsed = now > then ? pa_usec_to_bytes(now - then, &s->sample_spec) : 0; - } else { - elapsed = 0; - } - - return writable_size(s, elapsed); -} - -SPA_EXPORT -size_t pa_stream_readable_size(PA_CONST pa_stream *s) -{ - uint64_t readable; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, - PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, - PA_ERR_BADSTATE, (size_t) -1); - - readable = s->ready_bytes; - pw_log_trace("stream %p: readable:%"PRIu64" fragsize:%u", s, readable, s->buffer_attr.fragsize); - - return readable; -} - -struct success_ack { - pa_stream_success_cb_t cb; - void *userdata; -}; - -static void on_success(pa_operation *o, void *userdata) -{ - struct success_ack *d = userdata; - pa_stream *s = o->stream; - if (d->cb) - d->cb(s, 1, d->userdata); - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - - pw_log_debug("stream %p", s); - if (s->corked) { - s->corked = false; - pw_stream_set_active(s->stream, true); - } - pw_stream_flush(s->stream, true); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - if (s->drain) - pa_operation_cancel(s->drain); - s->drain = o; - - return o; -} - -static void on_timing_success(pa_operation *o, void *userdata) -{ - struct success_ack *d = userdata; - pa_stream *s = o->stream; - - update_timing_info(s); - - if (s->latency_update_callback) - s->latency_update_callback(s, s->latency_update_userdata); - - if (d->cb) - d->cb(s, s->timing_info_valid, d->userdata); - - pa_operation_done(o); -} - -SPA_EXPORT -pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_debug("stream %p", s); - o = pa_operation_new(s->context, s, on_timing_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->state_callback = cb; - s->state_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->write_callback = cb; - s->write_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->read_callback = cb; - s->read_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->overflow_callback = cb; - s->overflow_userdata = userdata; -} - -SPA_EXPORT -int64_t pa_stream_get_underflow_index(PA_CONST pa_stream *s) -{ - pw_log_warn("Not Implemented"); - return 0; -} - -SPA_EXPORT -void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->underflow_callback = cb; - s->underflow_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_started_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->started_callback = cb; - s->started_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->latency_update_callback = cb; - s->latency_update_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_moved_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->moved_callback = cb; - s->moved_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_suspended_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->suspended_callback = cb; - s->suspended_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_event_callback(pa_stream *s, pa_stream_event_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->event_callback = cb; - s->event_userdata = userdata; -} - -SPA_EXPORT -void pa_stream_set_buffer_attr_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) - return; - - s->buffer_attr_callback = cb; - s->buffer_attr_userdata = userdata; -} - -SPA_EXPORT -pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_debug("stream %p: cork %d->%d", s, s->corked, b); - s->corked = b; - pw_stream_set_active(s->stream, !b); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - struct pa_mem *m; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_debug("stream %p:", s); - pw_stream_flush(s->stream, false); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - - spa_list_consume(m, &s->ready, link) { - struct pw_buffer *b = m->user_data; - pw_log_trace("flush %p", m); - spa_list_remove(&m->link); - spa_list_append(&s->free, &m->link); - m->user_data = NULL; - if (b) - b->user_data = NULL; - } - s->ready_bytes = 0; - s->queued_bytes = 0; - s->timing_info.write_index = s->timing_info.read_index = 0; - s->have_time = false; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - - pw_log_debug("%p", s); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - - pw_log_debug("%p", s); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - struct spa_dict dict; - struct spa_dict_item items[1]; - - spa_assert(s); - spa_assert(s->refcount >= 1); - spa_assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_NAME, name); - dict = SPA_DICT_INIT(items, 1); - pw_stream_update_properties(s->stream, &dict); - - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - - return o; -} - -SPA_EXPORT -int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) -{ - struct timespec ts; - uint64_t now, then, res; - pa_timing_info *i; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - i = &s->timing_info; - - if (s->direction == PA_STREAM_PLAYBACK) { - res = pa_bytes_to_usec((uint64_t) i->read_index, &s->sample_spec); - res -= SPA_MIN(res, i->sink_usec); - } else { - res = pa_bytes_to_usec((uint64_t) i->write_index, &s->sample_spec); - res += i->source_usec; - } - - clock_gettime(CLOCK_MONOTONIC, &ts); - now = SPA_TIMESPEC_TO_USEC(&ts); - then = SPA_TIMEVAL_TO_USEC(&i->timestamp); - if (s->have_time && now > then) - res += now - then; - - if (r_usec) - *r_usec = res; - - pw_log_trace("stream %p: now:%"PRIu64" diff:%"PRIi64 - " write-index:%"PRIi64" read_index:%"PRIi64" rw-diff:%"PRIi64" res:%"PRIu64, - s, now, now - res, i->write_index, i->read_index, - i->write_index - i->read_index, res); - return 0; -} - -static pa_usec_t time_counter_diff(const pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { - pa_assert(s); - pa_assert(s->refcount >= 1); - - if (negative) - *negative = 0; - - if (a >= b) - return a-b; - else { - if (negative && s->direction == PA_STREAM_RECORD) { - *negative = 1; - return b-a; - } else - return 0; - } -} - -SPA_EXPORT -int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) -{ - pa_usec_t t, c; - int64_t cindex; - - spa_assert(s); - spa_assert(s->refcount >= 1); - spa_assert(r_usec); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pa_stream_get_time(s, &t); - - if (s->direction == PA_STREAM_PLAYBACK) - cindex = s->timing_info.write_index; - else - cindex = s->timing_info.read_index; - - if (cindex < 0) - cindex = 0; - - c = pa_bytes_to_usec((uint64_t) cindex, &s->sample_spec); - - if (s->direction == PA_STREAM_PLAYBACK) - *r_usec = time_counter_diff(s, c, t, negative); - else - *r_usec = time_counter_diff(s, t, c, negative); - - pw_log_trace("stream %p: now:%"PRIu64" stream:%"PRIu64" cindex:%"PRIi64 - " res:%"PRIu64, s, t, c, cindex, *r_usec); - - return 0; -} - -SPA_EXPORT -const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_trace("stream %p: %"PRIi64" %"PRIi64" %"PRIi64, s, - s->timing_info.write_index, s->timing_info.read_index, - (s->timing_info.write_index - s->timing_info.read_index)); - - return &s->timing_info; -} - -SPA_EXPORT -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - return &s->sample_spec; -} - -SPA_EXPORT -const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - return &s->channel_map; -} - -SPA_EXPORT -const pa_format_info* pa_stream_get_format_info(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - - return s->format; -} - -SPA_EXPORT -const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - return &s->buffer_attr; -} - -SPA_EXPORT -pa_operation *pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - spa_assert(attr); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_warn("Not Implemented"); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_EXPORT -pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, pa_sample_rate_valid(rate), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->flags & PA_STREAM_VARIABLE_RATE, PA_ERR_BADSTATE); - - pw_log_warn("Not Implemented"); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_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) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, mode == PA_UPDATE_SET || - mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pa_proplist_update(s->proplist, mode, p); - - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_EXPORT -pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata) -{ - pa_operation *o; - struct success_ack *d; - - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, keys && keys[0], PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - pw_log_warn("Not Implemented"); - o = pa_operation_new(s->context, s, on_success, sizeof(struct success_ack)); - d = o->userdata; - d->cb = cb; - d->userdata = userdata; - pa_operation_sync(o); - return o; -} - -SPA_EXPORT -int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - - pw_log_debug("stream %p: Set monitor stream %u", s, sink_input_idx); - s->direct_on_input = sink_input_idx; - return 0; -} - -SPA_EXPORT -uint32_t pa_stream_get_monitor_stream(PA_CONST pa_stream *s) -{ - spa_assert(s); - spa_assert(s->refcount >= 1); - - pw_log_debug("stream %p: get monitor stream %u", s, s->direct_on_input); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direct_on_input != PA_INVALID_INDEX, - PA_ERR_BADSTATE, PA_INVALID_INDEX); - - return s->direct_on_input; -} diff --git a/pipewire-pulseaudio/src/subscribe.c b/pipewire-pulseaudio/src/subscribe.c deleted file mode 100644 index 4ccdc7c70..000000000 --- a/pipewire-pulseaudio/src/subscribe.c +++ /dev/null @@ -1,43 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -#include "internal.h" - -struct subscribe_data -{ - pa_context_success_cb_t cb; - void *userdata; -}; - -SPA_EXPORT -void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) -{ - pa_assert(c); - pa_assert(c->refcount >= 1); - - if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED) - return; - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; -} diff --git a/pipewire-pulseaudio/src/thread-mainloop.c b/pipewire-pulseaudio/src/thread-mainloop.c deleted file mode 100644 index 70aeb8a26..000000000 --- a/pipewire-pulseaudio/src/thread-mainloop.c +++ /dev/null @@ -1,144 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include -#include - -#include -#include - -#include "internal.h" - -struct pa_threaded_mainloop -{ - pa_mainloop *loop; - struct pw_thread_loop *tloop; -}; - -SPA_EXPORT -pa_threaded_mainloop *pa_threaded_mainloop_new(void) -{ - pa_threaded_mainloop *m; - - m = calloc(1, sizeof(pa_threaded_mainloop)); - if (m == NULL) - return NULL; - - m->loop = pa_mainloop_new(); - if (m->loop == NULL) - goto no_mem; - - m->tloop = pw_thread_loop_new_full(m->loop->loop, "pipewire-pulse", NULL); - if (m->tloop == NULL) - goto no_mem; - - return m; - - no_mem: - if (m->loop) - pa_mainloop_free(m->loop); - free(m); - return NULL; -} - -SPA_EXPORT -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_destroy(m->tloop); - pa_mainloop_free(m->loop); - free(m); -} - -SPA_EXPORT -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) -{ - spa_return_val_if_fail(m != NULL, -EINVAL); - return pw_thread_loop_start(m->tloop); -} - -SPA_EXPORT -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_stop(m->tloop); -} - -SPA_EXPORT -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_lock(m->tloop); -} - -SPA_EXPORT -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_unlock(m->tloop); -} - -SPA_EXPORT -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_wait(m->tloop); -} - -SPA_EXPORT -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_signal(m->tloop, wait_for_accept); -} - -SPA_EXPORT -void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) -{ - spa_return_if_fail(m != NULL); - pw_thread_loop_accept(m->tloop); -} - -SPA_EXPORT -int pa_threaded_mainloop_get_retval(PA_CONST pa_threaded_mainloop *m) -{ - spa_return_val_if_fail(m != NULL, -EINVAL); - return pa_mainloop_get_retval(m->loop); -} - -SPA_EXPORT -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) -{ - spa_return_val_if_fail(m != NULL, NULL); - return pa_mainloop_get_api(m->loop); -} - -SPA_EXPORT -int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m) -{ - spa_return_val_if_fail(m != NULL, -EINVAL); - return pw_thread_loop_in_thread(m->tloop); -} - -SPA_EXPORT -void pa_threaded_mainloop_set_name(pa_threaded_mainloop *m, const char *name) -{ - spa_return_if_fail(m != NULL); - spa_return_if_fail(name != NULL); -} diff --git a/pipewire-pulseaudio/src/timeval.c b/pipewire-pulseaudio/src/timeval.c deleted file mode 100644 index e8ca09a9d..000000000 --- a/pipewire-pulseaudio/src/timeval.c +++ /dev/null @@ -1,220 +0,0 @@ -/*** - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include - -#include "internal.h" - -#define HAVE_GETTIMEOFDAY - -SPA_EXPORT -struct timeval *pa_gettimeofday(struct timeval *tv) { - pa_assert(tv); - -#if defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif -{ - FILETIME ft; - LARGE_INTEGER li; - int64_t t; - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (time_t) (t / PA_USEC_PER_SEC); - tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC); -} -#elif defined(HAVE_GETTIMEOFDAY) - pa_assert_se(gettimeofday(tv, NULL) == 0); -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif - - return tv; -} - -SPA_EXPORT -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - - pa_assert(a); - pa_assert(b); - - /* Check which is the earlier time and swap the two arguments if required. */ - if (PA_UNLIKELY(pa_timeval_cmp(a, b) < 0)) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - (pa_usec_t) b->tv_sec) * PA_USEC_PER_SEC; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += (pa_usec_t) a->tv_usec - (pa_usec_t) b->tv_usec; - else if (a->tv_usec < b->tv_usec) - r -= (pa_usec_t) b->tv_usec - (pa_usec_t) a->tv_usec; - - return r; -} - -SPA_EXPORT -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - pa_assert(a); - pa_assert(b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -SPA_EXPORT -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - pa_assert(tv); - - return pa_timeval_diff(pa_gettimeofday(&now), tv); -} - -SPA_EXPORT -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { - time_t secs; - pa_assert(tv); - - secs = (time_t) (v/PA_USEC_PER_SEC); - - if (PA_UNLIKELY(tv->tv_sec > PA_INT_TYPE_MAX(time_t) - secs)) - goto overflow; - - tv->tv_sec += secs; - v -= (pa_usec_t) secs * PA_USEC_PER_SEC; - tv->tv_usec += (suseconds_t) v; - - /* Normalize */ - while ((pa_usec_t) tv->tv_usec >= PA_USEC_PER_SEC) { - - if (PA_UNLIKELY(tv->tv_sec >= PA_INT_TYPE_MAX(time_t))) - goto overflow; - - tv->tv_sec++; - tv->tv_usec -= (suseconds_t) PA_USEC_PER_SEC; - } - - return tv; - -overflow: - tv->tv_sec = PA_INT_TYPE_MAX(time_t); - tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1); - return tv; -} - -SPA_EXPORT -struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v) { - time_t secs; - pa_assert(tv); - - secs = (time_t) (v/PA_USEC_PER_SEC); - - if (PA_UNLIKELY(tv->tv_sec < secs)) - goto underflow; - - tv->tv_sec -= secs; - v -= (pa_usec_t) secs * PA_USEC_PER_SEC; - - if (tv->tv_usec >= (suseconds_t) v) - tv->tv_usec -= (suseconds_t) v; - else { - - if (PA_UNLIKELY(tv->tv_sec <= 0)) - goto underflow; - - tv->tv_sec --; - tv->tv_usec += (suseconds_t) (PA_USEC_PER_SEC - v); - } - - return tv; - -underflow: - tv->tv_sec = 0; - tv->tv_usec = 0; - return tv; -} - -SPA_EXPORT -struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) { - pa_assert(tv); - - if (PA_UNLIKELY(v == PA_USEC_INVALID)) { - tv->tv_sec = PA_INT_TYPE_MAX(time_t); - tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1); - - return tv; - } - - tv->tv_sec = (time_t) (v / PA_USEC_PER_SEC); - tv->tv_usec = (suseconds_t) (v % PA_USEC_PER_SEC); - - return tv; -} - -SPA_EXPORT -pa_usec_t pa_timeval_load(const struct timeval *tv) { - - if (PA_UNLIKELY(!tv)) - return PA_USEC_INVALID; - - return - (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC + - (pa_usec_t) tv->tv_usec; -} diff --git a/pipewire-pulseaudio/src/utf8.c b/pipewire-pulseaudio/src/utf8.c deleted file mode 100644 index 35e4b6d5f..000000000 --- a/pipewire-pulseaudio/src/utf8.c +++ /dev/null @@ -1,295 +0,0 @@ -/*** - 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, see . -***/ - -/* This file is based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_ICONV -#include -#endif - -#include -#include - -#include "internal.h" - -#define FILTER_CHAR '_' - -static inline bool is_unicode_valid(uint32_t ch) { - - if (ch >= 0x110000) /* End of unicode space */ - return false; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return false; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return false; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return false; - - return true; -} - -static inline bool is_continuation_char(uint8_t ch) { - if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ - return false; - return true; -} - -static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { - *u_ch <<= 6; - *u_ch |= ch & 0x3f; -} - -static char* utf8_validate(const char *str, char *output) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p, *last; - int size; - uint8_t *o; - - pa_assert(str); - - o = (uint8_t*) output; - for (p = (const uint8_t*) str; *p; p++) { - if (*p < 128) { - if (o) - *o = *p; - } else { - last = p; - - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - size = 2; - min = 128; - val = (uint32_t) (*p & 0x1e); - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - size = 3; - min = (1 << 11); - val = (uint32_t) (*p & 0x0f); - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - size = 4; - min = (1 << 16); - val = (uint32_t) (*p & 0x07); - } else - goto error; - - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -TWO_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -ONE_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - - if (!is_unicode_valid(val)) - goto error; - - if (o) { - memcpy(o, last, (size_t) size); - o += size; - } - - continue; - -error: - if (o) { - *o = FILTER_CHAR; - p = last; /* We retry at the next character */ - } else - goto failure; - } - - if (o) - o++; - } - - if (o) { - *o = '\0'; - return output; - } - - return (char*) str; - -failure: - return NULL; -} - -SPA_EXPORT -char* pa_utf8_valid (const char *str) { - return utf8_validate(str, NULL); -} - -SPA_EXPORT -char* pa_utf8_filter (const char *str) { - char *new_str; - - pa_assert(str); - new_str = pa_xmalloc(strlen(str) + 1); - return utf8_validate(str, new_str); -} - -#ifdef HAVE_ICONV - -static char* iconv_simple(const char *str, const char *to, const char *from) { - char *new_str; - size_t len, inlen; - iconv_t cd; - ICONV_CONST char *inbuf; - char *outbuf; - size_t res, inbytes, outbytes; - - pa_assert(str); - pa_assert(to); - pa_assert(from); - - cd = iconv_open(to, from); - if (cd == (iconv_t)-1) - return NULL; - - inlen = len = strlen(str) + 1; - new_str = pa_xmalloc(len); - - for (;;) { - inbuf = (ICONV_CONST char*) str; /* Brain dead prototype for iconv() */ - inbytes = inlen; - outbuf = new_str; - outbytes = len; - - res = iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes); - - if (res != (size_t)-1) - break; - - if (errno != E2BIG) { - pa_xfree(new_str); - new_str = NULL; - break; - } - - pa_assert(inbytes != 0); - - len += inbytes; - new_str = pa_xrealloc(new_str, len); - } - - iconv_close(cd); - - return new_str; -} - -SPA_EXPORT -char* pa_utf8_to_locale (const char *str) { - return iconv_simple(str, "", "UTF-8"); -} - -SPA_EXPORT -char* pa_locale_to_utf8 (const char *str) { - return iconv_simple(str, "UTF-8", ""); -} - -#else - -SPA_EXPORT -char* pa_utf8_to_locale (const char *str) { - pa_assert(str); - - return pa_ascii_filter(str); -} - -SPA_EXPORT -char* pa_locale_to_utf8 (const char *str) { - pa_assert(str); - - if (pa_utf8_valid(str)) - return pa_xstrdup(str); - - return NULL; -} - -#endif - -SPA_EXPORT -char *pa_ascii_valid(const char *str) { - const char *p; - pa_assert(str); - - for (p = str; *p; p++) - if ((unsigned char) *p >= 128) - return NULL; - - return (char*) str; -} - -SPA_EXPORT -char *pa_ascii_filter(const char *str) { - char *r, *s, *d; - pa_assert(str); - - r = pa_xstrdup(str); - - for (s = r, d = r; *s; s++) - if ((unsigned char) *s < 128) - *(d++) = *s; - - *d = 0; - - return r; -} diff --git a/pipewire-pulseaudio/src/util.c b/pipewire-pulseaudio/src/util.c deleted file mode 100644 index 66d9baa33..000000000 --- a/pipewire-pulseaudio/src/util.c +++ /dev/null @@ -1,124 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include -#include -#include - -#include -#include - -#include - -#include "internal.h" - -#define PA_PATH_SEP_CHAR '/' - -SPA_EXPORT -char *pa_get_user_name(char *s, size_t l) -{ - return strncpy(s, pw_get_user_name(), l); -} - - -SPA_EXPORT -char *pa_get_host_name(char *s, size_t l) -{ - return strncpy(s, pw_get_host_name(), l); -} - -SPA_EXPORT -char *pa_get_fqdn(char *s, size_t l) -{ - return strncpy(s, pw_get_host_name(), l); -} - -SPA_EXPORT -char *pa_get_home_dir(char *s, size_t l) -{ - const char *home; - home = getenv("HOME"); - if (home == NULL) - home = getenv("USERPROFILE"); - if (home == NULL) { - struct passwd pwd, *result = NULL; - char buffer[4096]; - if (getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &result) == 0) - home = result ? result->pw_dir : NULL; - } - if (home) { - strncpy(s, home, l); - s[l] = 0; - } - return home ? s : NULL; -} - -SPA_EXPORT -char *pa_get_runtime_dir(void) -{ - const char *runtime; - runtime = getenv("PULSE_RUNTIME_PATH"); - if (runtime == NULL) - runtime = getenv("XDG_RUNTIME_DIR"); - if (runtime == NULL) { - char buffer[4096]; - runtime = pa_get_home_dir(buffer, sizeof(buffer)); - } - return runtime ? strdup(runtime) : NULL; - -} - -SPA_EXPORT -char *pa_get_binary_name(char *s, size_t l) -{ - return strncpy(s, pw_get_prgname(), l); -} - -SPA_EXPORT -char *pa_path_get_filename(const char *p) -{ - char *fn; - - if (!p) - return NULL; - - if ((fn = strrchr(p, PA_PATH_SEP_CHAR))) - return fn+1; - - return (char*) p; -} - -SPA_EXPORT -int pa_msleep(unsigned long t) -{ - struct timespec ts; - - ts.tv_sec = (time_t) (t / SPA_MSEC_PER_SEC); - ts.tv_nsec = (long) ((t % SPA_MSEC_PER_SEC) * SPA_NSEC_PER_MSEC); - - return nanosleep(&ts, NULL); -} - -bool pa_endswith(const char *s, const char *sfx) -{ - size_t l1, l2; - l1 = strlen(s); - l2 = strlen(sfx); - return l1 >= l2 && pa_streq(s + l1 - l2, sfx); -} diff --git a/pipewire-pulseaudio/src/version.c b/pipewire-pulseaudio/src/version.c deleted file mode 100644 index 69e269c2a..000000000 --- a/pipewire-pulseaudio/src/version.c +++ /dev/null @@ -1,34 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include - -#include - -SPA_EXPORT -const char* pa_get_library_version(void) -{ - return pa_get_headers_version(); -} - -SPA_EXPORT -bool pa_is_pipewire(void) -{ - return true; -} diff --git a/pipewire-pulseaudio/src/volume.c b/pipewire-pulseaudio/src/volume.c deleted file mode 100644 index 35527ba75..000000000 --- a/pipewire-pulseaudio/src/volume.c +++ /dev/null @@ -1,1037 +0,0 @@ -/*** - 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, see . -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include - -#include "internal.h" -#include "sample-util.h" - -SPA_EXPORT -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { - int i; - pa_assert(a); - pa_assert(b); - - pa_return_val_if_fail(pa_cvolume_valid(a), 0); - - if (PA_UNLIKELY(a == b)) - return 1; - - pa_return_val_if_fail(pa_cvolume_valid(b), 0); - - if (a->channels != b->channels) - return 0; - - for (i = 0; i < a->channels; i++) - if (a->values[i] != b->values[i]) - return 0; - - return 1; -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_init(pa_cvolume *a) { - unsigned c; - - pa_assert(a); - - a->channels = 0; - - for (c = 0; c < PA_CHANNELS_MAX; c++) - a->values[c] = PA_VOLUME_INVALID; - - return a; -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { - int i; - - pa_assert(a); - pa_assert(pa_channels_valid(channels)); - - a->channels = (uint8_t) channels; - - for (i = 0; i < a->channels; i++) - /* Clamp in case there is stale data that exceeds the current - * PA_VOLUME_MAX */ - a->values[i] = PA_CLAMP_VOLUME(v); - - return a; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { - uint64_t sum = 0; - unsigned c; - - pa_assert(a); - pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); - - for (c = 0; c < a->channels; c++) - sum += a->values[c]; - - sum /= a->channels; - - return (pa_volume_t) sum; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { - uint64_t sum = 0; - unsigned c, n; - - pa_assert(a); - - if (!cm) - return pa_cvolume_avg(a); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); - - for (c = n = 0; c < a->channels; c++) { - - if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) - continue; - - sum += a->values[c]; - n ++; - } - - if (n > 0) - sum /= n; - - return (pa_volume_t) sum; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_max(const pa_cvolume *a) { - pa_volume_t m = PA_VOLUME_MUTED; - unsigned c; - - pa_assert(a); - pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); - - for (c = 0; c < a->channels; c++) - if (a->values[c] > m) - m = a->values[c]; - - return m; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_min(const pa_cvolume *a) { - pa_volume_t m = PA_VOLUME_MAX; - unsigned c; - - pa_assert(a); - pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); - - for (c = 0; c < a->channels; c++) - if (a->values[c] < m) - m = a->values[c]; - - return m; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { - pa_volume_t m = PA_VOLUME_MUTED; - unsigned c; - - pa_assert(a); - - if (!cm) - return pa_cvolume_max(a); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); - - for (c = 0; c < a->channels; c++) { - - if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) - continue; - - if (a->values[c] > m) - m = a->values[c]; - } - - return m; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { - pa_volume_t m = PA_VOLUME_MAX; - unsigned c; - - pa_assert(a); - - if (!cm) - return pa_cvolume_min(a); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); - - for (c = 0; c < a->channels; c++) { - - if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) - continue; - - if (a->values[c] < m) - m = a->values[c]; - } - - return m; -} - -SPA_EXPORT -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { - uint64_t result; - - pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); - - /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ - - result = ((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM; - - if (result > (uint64_t)PA_VOLUME_MAX) - pa_log_warn("pa_sw_volume_multiply: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); - - return (pa_volume_t) PA_CLAMP_VOLUME(result); -} - -SPA_EXPORT -pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { - uint64_t result; - - pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); - - if (b <= PA_VOLUME_MUTED) - return 0; - - result = ((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b; - - if (result > (uint64_t)PA_VOLUME_MAX) - pa_log_warn("pa_sw_volume_divide: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); - - return (pa_volume_t) PA_CLAMP_VOLUME(result); -} - -/* Amplitude, not power */ -static double linear_to_dB(double v) { - return 20.0 * log10(v); -} - -static double dB_to_linear(double v) { - return pow(10.0, v / 20.0); -} - -SPA_EXPORT -pa_volume_t pa_sw_volume_from_dB(double dB) { - if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY) - return PA_VOLUME_MUTED; - - return pa_sw_volume_from_linear(dB_to_linear(dB)); -} - -SPA_EXPORT -double pa_sw_volume_to_dB(pa_volume_t v) { - - pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY); - - if (v <= PA_VOLUME_MUTED) - return PA_DECIBEL_MININFTY; - - return linear_to_dB(pa_sw_volume_to_linear(v)); -} - -SPA_EXPORT -pa_volume_t pa_sw_volume_from_linear(double v) { - - if (v <= 0.0) - return PA_VOLUME_MUTED; - - /* - * We use a cubic mapping here, as suggested and discussed here: - * - * http://www.robotplanet.dk/audio/audio_gui_design/ - * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151 - * - * We make sure that the conversion to linear and back yields the - * same volume value! That's why we need the lround() below! - */ - - return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM)); -} - -SPA_EXPORT -double pa_sw_volume_to_linear(pa_volume_t v) { - double f; - - pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0); - - if (v <= PA_VOLUME_MUTED) - return 0.0; - - if (v == PA_VOLUME_NORM) - return 1.0; - - f = ((double) v / PA_VOLUME_NORM); - - return f*f*f; -} - -SPA_EXPORT -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { - unsigned channel; - bool first = true; - char *e; - - pa_assert(s); - pa_assert(l > 0); - pa_assert(c); - - pa_init_i18n(); - - if (!pa_cvolume_valid(c)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - *(e = s) = 0; - - for (channel = 0; channel < c->channels && l > 1; channel++) { - l -= pa_snprintf(e, l, "%s%u: %3u%%", - first ? "" : " ", - channel, - (unsigned)(((uint64_t)c->values[channel] * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); - - e = strchr(e, 0); - first = false; - } - - return s; -} - -SPA_EXPORT -char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) { - pa_assert(s); - pa_assert(l > 0); - - pa_init_i18n(); - - if (!PA_VOLUME_IS_VALID(v)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - pa_snprintf(s, l, "%3u%%", (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); - return s; -} - -SPA_EXPORT -char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) { - unsigned channel; - bool first = true; - char *e; - - pa_assert(s); - pa_assert(l > 0); - pa_assert(c); - - pa_init_i18n(); - - if (!pa_cvolume_valid(c)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - *(e = s) = 0; - - for (channel = 0; channel < c->channels && l > 1; channel++) { - double f = pa_sw_volume_to_dB(c->values[channel]); - - l -= pa_snprintf(e, l, "%s%u: %0.2f dB", - first ? "" : " ", - channel, - isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); - - e = strchr(e, 0); - first = false; - } - - return s; -} - -SPA_EXPORT -char *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) { - char *current = s; - bool first = true; - - pa_assert(s); - pa_assert(l > 0); - pa_assert(c); - - pa_init_i18n(); - - if (!pa_cvolume_valid(c)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - pa_assert(!map || (map->channels == c->channels)); - pa_assert(!map || pa_channel_map_valid(map)); - - current[0] = 0; - - for (unsigned channel = 0; channel < c->channels && l > 1; channel++) { - char channel_position[32]; - size_t bytes_printed; - char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX]; - - if (map) - pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel])); - else - pa_snprintf(channel_position, sizeof(channel_position), "%u", channel); - - bytes_printed = pa_snprintf(current, l, "%s%s: %s", - first ? "" : ", ", - channel_position, - pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB)); - l -= bytes_printed; - current += bytes_printed; - first = false; - } - - return s; -} - -SPA_EXPORT -char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { - double f; - - pa_assert(s); - pa_assert(l > 0); - - pa_init_i18n(); - - if (!PA_VOLUME_IS_VALID(v)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - f = pa_sw_volume_to_dB(v); - pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); - - return s; -} - -SPA_EXPORT -char *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) { - char dB[PA_SW_VOLUME_SNPRINT_DB_MAX]; - - pa_assert(s); - pa_assert(l > 0); - - pa_init_i18n(); - - if (!PA_VOLUME_IS_VALID(v)) { - pa_snprintf(s, l, _("(invalid)")); - return s; - } - - pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s", - v, - (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM), - print_dB ? " / " : "", - print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : ""); - - return s; -} - -SPA_EXPORT -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { - unsigned c; - pa_assert(a); - - pa_return_val_if_fail(pa_cvolume_valid(a), 0); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); - - for (c = 0; c < a->channels; c++) - if (a->values[c] != v) - return 0; - - return 1; -} - -SPA_EXPORT -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { - unsigned i; - - pa_assert(dest); - pa_assert(a); - pa_assert(b); - - pa_return_val_if_fail(pa_cvolume_valid(a), NULL); - pa_return_val_if_fail(pa_cvolume_valid(b), NULL); - - dest->channels = PA_MIN(a->channels, b->channels); - - for (i = 0; i < dest->channels; i++) - dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]); - - return dest; -} - -SPA_EXPORT -pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { - unsigned i; - - pa_assert(dest); - pa_assert(a); - - pa_return_val_if_fail(pa_cvolume_valid(a), NULL); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); - - for (i = 0; i < a->channels; i++) - dest->values[i] = pa_sw_volume_multiply(a->values[i], b); - - dest->channels = (uint8_t) i; - - return dest; -} - -SPA_EXPORT -pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { - unsigned i; - - pa_assert(dest); - pa_assert(a); - pa_assert(b); - - pa_return_val_if_fail(pa_cvolume_valid(a), NULL); - pa_return_val_if_fail(pa_cvolume_valid(b), NULL); - - dest->channels = PA_MIN(a->channels, b->channels); - - for (i = 0; i < dest->channels; i++) - dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]); - - return dest; -} - -SPA_EXPORT -pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { - unsigned i; - - pa_assert(dest); - pa_assert(a); - - pa_return_val_if_fail(pa_cvolume_valid(a), NULL); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); - - for (i = 0; i < a->channels; i++) - dest->values[i] = pa_sw_volume_divide(a->values[i], b); - - dest->channels = (uint8_t) i; - - return dest; -} - -SPA_EXPORT -int pa_cvolume_valid(const pa_cvolume *v) { - unsigned c; - - pa_assert(v); - - if (!pa_channels_valid(v->channels)) - return 0; - - for (c = 0; c < v->channels; c++) - if (!PA_VOLUME_IS_VALID(v->values[c])) - return 0; - - return 1; -} - -static bool on_left(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT); -} - -static bool on_right(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT); -} - -static bool on_center(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER); -} - -static bool on_hfe(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_HFE); -} - -static bool on_lfe(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LFE); -} - -static bool on_front(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT); -} - -static bool on_rear(pa_channel_position_t p) { - return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR); -} - -SPA_EXPORT -pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) { - int a, b; - pa_cvolume result; - - pa_assert(v); - pa_assert(from); - pa_assert(to); - - pa_return_val_if_fail(pa_channel_map_valid(to), NULL); - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); - - if (pa_channel_map_equal(from, to)) - return v; - - result.channels = to->channels; - - for (b = 0; b < to->channels; b++) { - pa_volume_t k = 0; - int n = 0; - - for (a = 0; a < from->channels; a++) - if (from->map[a] == to->map[b]) { - k += v->values[a]; - n ++; - } - - if (n <= 0) { - for (a = 0; a < from->channels; a++) - if ((on_left(from->map[a]) && on_left(to->map[b])) || - (on_right(from->map[a]) && on_right(to->map[b])) || - (on_center(from->map[a]) && on_center(to->map[b])) || - (on_lfe(from->map[a]) && on_lfe(to->map[b]))) { - - k += v->values[a]; - n ++; - } - } - - if (n <= 0) - k = pa_cvolume_avg(v); - else - k /= n; - - result.values[b] = k; - } - - *v = result; - return v; -} - -SPA_EXPORT -int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { - - pa_assert(v); - pa_assert(ss); - - pa_return_val_if_fail(pa_cvolume_valid(v), 0); - pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); - - return v->channels == ss->channels; -} - -SPA_EXPORT -int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { - pa_assert(v); - pa_assert(cm); - - pa_return_val_if_fail(pa_cvolume_valid(v), 0); - pa_return_val_if_fail(pa_channel_map_valid(cm), 0); - - return v->channels == cm->channels; -} - -/* - * Returns the average volume of l and r, where l and r are two disjoint sets of channels - * (e g left and right, or front and rear). - */ -static void get_avg(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r, - bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) { - int c; - pa_volume_t left = 0, right = 0; - unsigned n_left = 0, n_right = 0; - - pa_assert(v); - pa_assert(map); - pa_assert(map->channels == v->channels); - pa_assert(l); - pa_assert(r); - - for (c = 0; c < map->channels; c++) { - if (on_l(map->map[c])) { - left += v->values[c]; - n_left++; - } else if (on_r(map->map[c])) { - right += v->values[c]; - n_right++; - } - } - - if (n_left <= 0) - *l = PA_VOLUME_NORM; - else - *l = left / n_left; - - if (n_right <= 0) - *r = PA_VOLUME_NORM; - else - *r = right / n_right; -} - -SPA_EXPORT -float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { - pa_volume_t left, right; - - pa_assert(v); - pa_assert(map); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); - - if (!pa_channel_map_can_balance(map)) - return 0.0f; - - get_avg(map, v, &left, &right, on_left, on_right); - - if (left == right) - return 0.0f; - - /* 1.0, 0.0 => -1.0 - 0.0, 1.0 => 1.0 - 0.0, 0.0 => 0.0 - 0.5, 0.5 => 0.0 - 1.0, 0.5 => -0.5 - 1.0, 0.25 => -0.75 - 0.75, 0.25 => -0.66 - 0.5, 0.25 => -0.5 */ - - if (left > right) - return -1.0f + ((float) right / (float) left); - else - return 1.0f - ((float) left / (float) right); -} - -static pa_cvolume* set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance, - bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) { - - pa_volume_t left, nleft, right, nright, m; - unsigned c; - - get_avg(map, v, &left, &right, on_l, on_r); - - m = PA_MAX(left, right); - - if (new_balance <= 0) { - nright = (new_balance + 1.0f) * m; - nleft = m; - } else { - nleft = (1.0f - new_balance) * m; - nright = m; - } - - for (c = 0; c < map->channels; c++) { - if (on_l(map->map[c])) { - if (left == 0) - v->values[c] = nleft; - else - v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left); - } else if (on_r(map->map[c])) { - if (right == 0) - v->values[c] = nright; - else - v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right); - } - } - - return v; -} - - -SPA_EXPORT -pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { - pa_assert(map); - pa_assert(v); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); - pa_return_val_if_fail(new_balance >= -1.0f, NULL); - pa_return_val_if_fail(new_balance <= 1.0f, NULL); - - if (!pa_channel_map_can_balance(map)) - return v; - - return set_balance(v, map, new_balance, on_left, on_right); -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { - unsigned c; - pa_volume_t t = 0; - - pa_assert(v); - - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); - - t = pa_cvolume_max(v); - - if (t <= PA_VOLUME_MUTED) - return pa_cvolume_set(v, v->channels, max); - - for (c = 0; c < v->channels; c++) - v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); - - return v; -} - -SPA_EXPORT -#if PA_CHECK_VERSION(12, 0, 0) -pa_cvolume* 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* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) { -#endif - unsigned c; - pa_volume_t t = 0; - - pa_assert(v); - - pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); - - if (!cm) - return pa_cvolume_scale(v, max); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); - - t = pa_cvolume_max_mask(v, cm, mask); - - if (t <= PA_VOLUME_MUTED) - return pa_cvolume_set(v, v->channels, max); - - for (c = 0; c < v->channels; c++) - v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); - - return v; -} - -SPA_EXPORT -float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { - pa_volume_t rear, front; - - pa_assert(v); - pa_assert(map); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); - - if (!pa_channel_map_can_fade(map)) - return 0.0f; - - get_avg(map, v, &rear, &front, on_rear, on_front); - - if (front == rear) - return 0.0f; - - if (rear > front) - return -1.0f + ((float) front / (float) rear); - else - return 1.0f - ((float) rear / (float) front); -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) { - pa_assert(map); - pa_assert(v); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); - pa_return_val_if_fail(new_fade >= -1.0f, NULL); - pa_return_val_if_fail(new_fade <= 1.0f, NULL); - - if (!pa_channel_map_can_fade(map)) - return v; - - return set_balance(v, map, new_fade, on_rear, on_front); -} - -SPA_EXPORT -float pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) { - pa_volume_t hfe, lfe; - - pa_assert(v); - pa_assert(map); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); - - if (!pa_channel_map_can_lfe_balance(map)) - return 0.0f; - - get_avg(map, v, &hfe, &lfe, on_hfe, on_lfe); - - if (hfe == lfe) - return 0.0f; - - if (hfe > lfe) - return -1.0f + ((float) lfe / (float) hfe); - else - return 1.0f - ((float) hfe / (float) lfe); -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { - pa_assert(map); - pa_assert(v); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); - pa_return_val_if_fail(new_balance >= -1.0f, NULL); - pa_return_val_if_fail(new_balance <= 1.0f, NULL); - - if (!pa_channel_map_can_lfe_balance(map)) - return v; - - return set_balance(v, map, new_balance, on_hfe, on_lfe); -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_set_position( - pa_cvolume *cv, - const pa_channel_map *map, - pa_channel_position_t t, - pa_volume_t v) { - - unsigned c; - bool good = false; - - pa_assert(cv); - pa_assert(map); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL); - pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL); - - for (c = 0; c < map->channels; c++) - if (map->map[c] == t) { - cv->values[c] = v; - good = true; - } - - return good ? cv : NULL; -} - -SPA_EXPORT -pa_volume_t pa_cvolume_get_position( - PA_CONST pa_cvolume *cv, - const pa_channel_map *map, - pa_channel_position_t t) { - - unsigned c; - pa_volume_t v = PA_VOLUME_MUTED; - - pa_assert(cv); - pa_assert(map); - - pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED); - pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED); - - for (c = 0; c < map->channels; c++) - if (map->map[c] == t) - if (cv->values[c] > v) - v = cv->values[c]; - - return v; -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { - unsigned i; - - pa_assert(dest); - pa_assert(a); - pa_assert(b); - - pa_return_val_if_fail(pa_cvolume_valid(a), NULL); - pa_return_val_if_fail(pa_cvolume_valid(b), NULL); - - dest->channels = PA_MIN(a->channels, b->channels); - - for (i = 0; i < dest->channels; i++) - dest->values[i] = PA_MAX(a->values[i], b->values[i]); - - return dest; -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { - pa_volume_t m; - - pa_assert(v); - - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL); - - m = pa_cvolume_max(v); - - if (m >= limit - inc) - m = limit; - else - m += inc; - - return pa_cvolume_scale(v, m); -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { - return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX); -} - -SPA_EXPORT -pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { - pa_volume_t m; - - pa_assert(v); - - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL); - - m = pa_cvolume_max(v); - - if (m <= PA_VOLUME_MUTED + dec) - m = PA_VOLUME_MUTED; - else - m -= dec; - - return pa_cvolume_scale(v, m); -} diff --git a/pipewire-pulseaudio/src/xmalloc.c b/pipewire-pulseaudio/src/xmalloc.c deleted file mode 100644 index 79f4a6790..000000000 --- a/pipewire-pulseaudio/src/xmalloc.c +++ /dev/null @@ -1,123 +0,0 @@ -/* PipeWire - * Copyright (C) 2018 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#include -#include - -#include - -#include - -#define MAX_ALLOC_SIZE (1024*1024*96) /* 96MB */ - -static void oom(void) { - static const char e[] = "Not enough memory\n"; - if (write(STDERR_FILENO, e, sizeof(e)-1) < 0) - perror("write"); -#ifdef SIGQUIT - raise(SIGQUIT); -#endif - _exit(1); -} - -SPA_EXPORT -void* pa_xmalloc(size_t l) -{ - void *p; - spa_assert(l > 0); - spa_assert(l < MAX_ALLOC_SIZE); - - if (!(p = malloc(l))) - oom(); - - return p; -} - -SPA_EXPORT -void *pa_xmalloc0(size_t l) -{ - void *p; - spa_assert(l > 0); - spa_assert(l < MAX_ALLOC_SIZE); - - if (!(p = calloc(1, l))) - oom(); - - return p; -} - -SPA_EXPORT -void *pa_xrealloc(void *ptr, size_t size) -{ - void *p; - spa_assert(size > 0); - spa_assert(size < MAX_ALLOC_SIZE); - - if (!(p = realloc(ptr, size))) - oom(); - return p; -} - -SPA_EXPORT -void pa_xfree(void *p) -{ - int saved_errno; - if (!p) - return; - saved_errno = errno; - free(p); - errno = saved_errno; -} - -SPA_EXPORT -char *pa_xstrdup(const char *s) -{ - if (!s) - return NULL; - return pa_xmemdup(s, strlen(s)+1); -} - -SPA_EXPORT -char *pa_xstrndup(const char *s, size_t l) -{ - char *e, *r; - - if (!s) - return NULL; - - if ((e = memchr(s, 0, l))) - return pa_xmemdup(s, (size_t) (e-s+1)); - - r = pa_xmalloc(l+1); - memcpy(r, s, l); - r[l] = 0; - return r; -} - -SPA_EXPORT -void* pa_xmemdup(const void *p, size_t l) -{ - if (!p) - return NULL; - else { - char *r = pa_xmalloc(l); - memcpy(r, p, l); - return r; - } -} diff --git a/pipewire-pulseaudio/test/meson.build b/pipewire-pulseaudio/test/meson.build deleted file mode 100644 index 6bbcaff3a..000000000 --- a/pipewire-pulseaudio/test/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -executable('test-volume', - 'test-volume.c', - c_args : [ '-D_GNU_SOURCE' ], - install : installed_tests_enabled, - install_dir : join_paths(installed_tests_execdir, 'examples'), - dependencies : [pipewire_dep, mathlib, pulseaudio_dep], -) diff --git a/pipewire-pulseaudio/test/test-volume.c b/pipewire-pulseaudio/test/test-volume.c deleted file mode 100644 index 4fcc934e3..000000000 --- a/pipewire-pulseaudio/test/test-volume.c +++ /dev/null @@ -1,215 +0,0 @@ -/* PipeWire - * - * Copyright © 2020 Wim Taymans - * - * 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 (including the next - * paragraph) 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 -#include - -#include -#include -#include -#include -#include -#include -#include - -struct data { - pa_mainloop *loop; - pa_context *context; - pa_time_event *timer; - - int n_channels; - int cycle; -}; - -static void time_event_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) -{ - struct data *data = userdata; - pa_cvolume volume; - pa_volume_t vol; - - if (data->cycle++ & 1) - vol = PA_VOLUME_NORM / 2; - else - vol = PA_VOLUME_NORM / 3; - - pa_cvolume_set(&volume, data->n_channels, vol); - - fprintf(stderr, "set volume\n"); - pa_context_set_sink_volume_by_name(data->context, - "@DEFAULT_SINK@", &volume, NULL, NULL); -} - -static void start_timer(struct data *data) -{ - struct timeval tv; - pa_mainloop_api *api = pa_mainloop_get_api(data->loop); - - pa_gettimeofday(&tv); - pa_timeval_add(&tv, 1 * PA_USEC_PER_SEC); - - if (data->timer == NULL) { - data->timer = api->time_new(api, &tv, time_event_cb, data); - } else { - api->time_restart(data->timer, &tv); - } -} - -static void context_state_callback(pa_context *c, void *userdata) -{ - struct data *data = userdata; - - fprintf(stderr, "context state: %d\n", pa_context_get_state(c)); - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - case PA_CONTEXT_READY: - pa_context_subscribe(data->context, - PA_SUBSCRIPTION_MASK_SINK| - PA_SUBSCRIPTION_MASK_SOURCE| - PA_SUBSCRIPTION_MASK_CLIENT| - PA_SUBSCRIPTION_MASK_SINK_INPUT| - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| - PA_SUBSCRIPTION_MASK_CARD| - PA_SUBSCRIPTION_MASK_MODULE| - PA_SUBSCRIPTION_MASK_SERVER, - NULL, NULL); - start_timer(data); - break; - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - default: - pa_mainloop_quit(data->loop, -1); - break; - } -} - -static const char *str_etype(pa_subscription_event_type_t event) -{ - switch (event & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { - case PA_SUBSCRIPTION_EVENT_NEW: - return "new"; - case PA_SUBSCRIPTION_EVENT_CHANGE: - return "change"; - case PA_SUBSCRIPTION_EVENT_REMOVE: - return "remove"; - } - return "invalid"; -} - -static const char *str_efac(pa_subscription_event_type_t event) -{ - switch (event & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - return "sink"; - case PA_SUBSCRIPTION_EVENT_SOURCE: - return "source"; - case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - return "sink-input"; - case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: - return "source-output"; - case PA_SUBSCRIPTION_EVENT_MODULE: - return "module"; - case PA_SUBSCRIPTION_EVENT_CLIENT: - return "client"; - case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE: - return "sample-cache"; - case PA_SUBSCRIPTION_EVENT_SERVER: - return "server"; - case PA_SUBSCRIPTION_EVENT_AUTOLOAD: - return "autoload"; - case PA_SUBSCRIPTION_EVENT_CARD: - return "card"; - } - return "invalid"; -} - -static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) -{ - struct data *data = userdata; - char v[1024]; - - if (eol < 0) { - fprintf(stderr, "sink info: error:%s", pa_strerror(pa_context_errno(c))); - return; - } - if (eol) - return; - - fprintf(stderr, "sink info: index:%d\n", i->index); - fprintf(stderr, "\tname:%s\n", i->name); - fprintf(stderr, "\tdescription:%s\n", i->description); - fprintf(stderr, "\tmute:%s\n", i->mute ? "yes" : "no"); - fprintf(stderr, "\tvolume:%s\n", pa_cvolume_snprint_verbose(v, sizeof(v), - &i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME)); - fprintf(stderr, "\tbalance:%0.2f\n", pa_cvolume_get_balance(&i->volume, &i->channel_map)); - fprintf(stderr, "\tbase:%s\n", pa_volume_snprint_verbose(v, sizeof(v), - i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME)); - - data->n_channels = i->volume.channels; - - start_timer(data); -} - -static void context_subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) -{ - struct data *data = userdata; - - fprintf(stderr, "subscribe event %d (%s|%s), idx:%d\n", t, - str_etype(t), str_efac(t), idx); - - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - case PA_SUBSCRIPTION_EVENT_SINK: - pa_context_get_sink_info_by_name(data->context, - "@DEFAULT_SINK@", sink_info_cb, data); - break; - } -} - -int main(int argc, char *argv[]) -{ - struct data data = { 0, }; - pa_mainloop_api *api; - int ret; - - data.loop = pa_mainloop_new(); - data.n_channels = 1; - - api = pa_mainloop_get_api(data.loop); - data.context = pa_context_new(api, "test-volume"); - - pa_context_set_state_callback(data.context, context_state_callback, &data); - - if (pa_context_connect(data.context, NULL, 0, NULL) < 0) { - fprintf(stderr, "pa_context_connect() failed.\n"); - return -1; - } - pa_context_set_subscribe_callback(data.context, context_subscribe_cb, &data); - - pa_mainloop_run(data.loop, &ret); - - return 0; -}