mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Remove pipewire-libpulse
We use the original pulseaudio client library and the replacement server pipewire-pulse.
This commit is contained in:
		
							parent
							
								
									161c05d737
								
							
						
					
					
						commit
						91b0d3bb39
					
				
					 50 changed files with 3 additions and 17526 deletions
				
			
		| 
						 | 
					@ -23,10 +23,6 @@ if get_option('pipewire-jack')
 | 
				
			||||||
  manpages += [[ 'pw-jack', '1' ]]
 | 
					  manpages += [[ 'pw-jack', '1' ]]
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if get_option('pipewire-pulseaudio')
 | 
					 | 
				
			||||||
  manpages += [[ 'pw-pulse', '1' ]]
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
foreach m : manpages
 | 
					foreach m : manpages
 | 
				
			||||||
  file = m.get(0) + '.' + m.get(1)
 | 
					  file = m.get(0) + '.' + m.get(1)
 | 
				
			||||||
  infile = file + '.xml.in'
 | 
					  infile = file + '.xml.in'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,6 @@ This file is part of PipeWire.
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
      <manref name="pipewire" section="1"/>,
 | 
					      <manref name="pipewire" section="1"/>,
 | 
				
			||||||
      <manref name="jackd" section="1"/>,
 | 
					      <manref name="jackd" section="1"/>,
 | 
				
			||||||
      <manref name="pw-pulse" section="1"/>
 | 
					 | 
				
			||||||
    </p>
 | 
					    </p>
 | 
				
			||||||
  </section>
 | 
					  </section>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,70 +0,0 @@
 | 
				
			||||||
<?xml version="1.0"?><!--*-nxml-*-->
 | 
					 | 
				
			||||||
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
 | 
					 | 
				
			||||||
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<!--
 | 
					 | 
				
			||||||
This file is part of PipeWire.
 | 
					 | 
				
			||||||
-->
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<manpage name="pw-pulse" section="1" desc="Use PipeWire instead of PulseAudio">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <synopsis>
 | 
					 | 
				
			||||||
    <cmd>pw-pulse [<arg>options</arg>] <arg>COMMAND</arg> [<arg>FILE</arg>]</cmd>
 | 
					 | 
				
			||||||
  </synopsis>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <description>
 | 
					 | 
				
			||||||
    <p><file>pw-pulse</file> 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.</p>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <p>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 <file>pw-pulse</file> has no practical effect.</p>
 | 
					 | 
				
			||||||
  </description>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <options>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <option>
 | 
					 | 
				
			||||||
      <p><opt>-h</opt></p>
 | 
					 | 
				
			||||||
      <optdesc><p>Show help.</p></optdesc>
 | 
					 | 
				
			||||||
    </option>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <option>
 | 
					 | 
				
			||||||
      <p><opt>-r</opt> <arg>NAME</arg></p>
 | 
					 | 
				
			||||||
      <optdesc><p>The name of the remote instance to connect to. If left
 | 
					 | 
				
			||||||
        unspecified, a connection is made to the default PipeWire
 | 
					 | 
				
			||||||
        instance.</p></optdesc>
 | 
					 | 
				
			||||||
    </option>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <option>
 | 
					 | 
				
			||||||
      <p><opt>-v</opt></p>
 | 
					 | 
				
			||||||
      <optdesc><p>Verbose operation.</p></optdesc>
 | 
					 | 
				
			||||||
    </option>
 | 
					 | 
				
			||||||
  </options>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <section name="Example">
 | 
					 | 
				
			||||||
    <p><cmd>pw-pulse gst123 /usr/share/sounds/freedesktop/stereo/bell.oga</cmd></p>
 | 
					 | 
				
			||||||
  </section>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <section name="Notes">
 | 
					 | 
				
			||||||
    <p>Using PipeWire for audio is currently considered to be
 | 
					 | 
				
			||||||
      experimental.</p>
 | 
					 | 
				
			||||||
  </section>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <section name="Authors">
 | 
					 | 
				
			||||||
    <p>The PipeWire Developers <@PACKAGE_BUGREPORT@>;
 | 
					 | 
				
			||||||
      PipeWire is available from <url href="@PACKAGE_URL@"/></p>
 | 
					 | 
				
			||||||
  </section>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <section name="See also">
 | 
					 | 
				
			||||||
    <p>
 | 
					 | 
				
			||||||
      <manref name="pipewire" section="1"/>,
 | 
					 | 
				
			||||||
      <manref name="pulseaudio" section="1"/>,
 | 
					 | 
				
			||||||
      <manref name="pw-jack" section="1"/>
 | 
					 | 
				
			||||||
    </p>
 | 
					 | 
				
			||||||
  </section>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</manpage>
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								meson.build
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								meson.build
									
										
									
									
									
								
							| 
						 | 
					@ -41,9 +41,9 @@ if host_machine.system() == 'linux'
 | 
				
			||||||
  # glibc ld.so interprets ${LIB} in a library loading path with an
 | 
					  # glibc ld.so interprets ${LIB} in a library loading path with an
 | 
				
			||||||
  # appropriate value for the current architecture, typically something
 | 
					  # appropriate value for the current architecture, typically something
 | 
				
			||||||
  # like lib, lib64 or lib/x86_64-linux-gnu.
 | 
					  # 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
 | 
					  # 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,
 | 
					  # Note that ${LIB} is a special token expanded by the runtime linker,
 | 
				
			||||||
  # not an environment variable, and must be passed through literally.
 | 
					  # not an environment variable, and must be passed through literally.
 | 
				
			||||||
  modules_install_dir_dlopen = join_paths(prefix, '${LIB}', pipewire_name)
 | 
					  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)
 | 
					sdl_dep = dependency('sdl2', required : false)
 | 
				
			||||||
sndfile_dep = dependency('sndfile', version : '>= 1.0.20', 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')
 | 
					  glib_dep = dependency('glib-2.0', version : '>=2.32.0')
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -364,12 +364,6 @@ if get_option('pipewire-jack')
 | 
				
			||||||
  subdir('pipewire-jack/src')
 | 
					  subdir('pipewire-jack/src')
 | 
				
			||||||
endif
 | 
					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')
 | 
					if get_option('pipewire-alsa')
 | 
				
			||||||
  subdir('pipewire-alsa/alsa-plugins')
 | 
					  subdir('pipewire-alsa/alsa-plugins')
 | 
				
			||||||
  subdir('pipewire-alsa/conf')
 | 
					  subdir('pipewire-alsa/conf')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,13 +49,6 @@ option('pipewire-jack',
 | 
				
			||||||
option('libjack-path',
 | 
					option('libjack-path',
 | 
				
			||||||
       description: 'Where to install the libjack.so library',
 | 
					       description: 'Where to install the libjack.so library',
 | 
				
			||||||
       type: 'string')
 | 
					       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',
 | 
					option('spa-plugins',
 | 
				
			||||||
       description: 'Enable spa plugins integration',
 | 
					       description: 'Enable spa plugins integration',
 | 
				
			||||||
       type: 'boolean',
 | 
					       type: 'boolean',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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!
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,948 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2005-2006 Lennart Poettering
 | 
					 | 
				
			||||||
  Copyright 2006 Pierre Ossman <ossman@cendio.se> 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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
#include <pulse/channelmap.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "core-format.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/def.h>
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/format.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,50 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
#include <pulse/direction.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,75 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <unistd.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/def.h>
 | 
					 | 
				
			||||||
#include <pulse/error.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,249 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/ext-device-manager.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,193 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/ext-device-restore.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,198 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/pipewire.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/ext-stream-restore.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,915 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2011 Intel Corporation
 | 
					 | 
				
			||||||
  Copyright 2011 Collabora Multimedia
 | 
					 | 
				
			||||||
  Copyright 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
#include <pulse/format.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,542 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <string.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
#include <spa/utils/hook.h>
 | 
					 | 
				
			||||||
#include <spa/utils/ringbuffer.h>
 | 
					 | 
				
			||||||
#include <spa/param/audio/format-utils.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/mainloop.h>
 | 
					 | 
				
			||||||
#include <pulse/stream.h>
 | 
					 | 
				
			||||||
#include <pulse/format.h>
 | 
					 | 
				
			||||||
#include <pulse/subscribe.h>
 | 
					 | 
				
			||||||
#include <pulse/introspect.h>
 | 
					 | 
				
			||||||
#include <pulse/version.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/pipewire.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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__ */
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,659 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2016 Arun Raghavan <mail@arunraghavan.net>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/array.h>
 | 
					 | 
				
			||||||
#include <pipewire/properties.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,53 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2016 Arun Raghavan <mail@arunraghavan.net>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,122 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/result.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
#include <pipewire/loop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/glib-mainloop.h>
 | 
					 | 
				
			||||||
#include <pulse/mainloop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,116 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/list.h>
 | 
					 | 
				
			||||||
#include <spa/support/loop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
#include <pipewire/loop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/mainloop-signal.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,499 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <errno.h>
 | 
					 | 
				
			||||||
#include <poll.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
#include <pipewire/loop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/mainloop.h>
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
#include <pulse/timeval.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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:
 | 
					 | 
				
			||||||
*;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,166 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/list.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/operation.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,30 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/pipewire.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void reg(void) __attribute__ ((constructor));
 | 
					 | 
				
			||||||
static void reg(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	pw_init(NULL, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,405 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <string.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/debug/mem.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
#include <pipewire/properties.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/proplist.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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>         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 "$@"
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,106 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <time.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/timeval.h>
 | 
					 | 
				
			||||||
#include <pulse/rtclock.h>
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,134 +0,0 @@
 | 
				
			||||||
#ifndef foosampleutilhfoo
 | 
					 | 
				
			||||||
#define foosampleutilhfoo
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2004-2006 Lennart Poettering
 | 
					 | 
				
			||||||
  Copyright 2006 Pierre Ossman <ossman@cendio.se> 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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
#include <limits.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/gccmacro.h>
 | 
					 | 
				
			||||||
#include <pulse/sample.h>
 | 
					 | 
				
			||||||
#include <pulse/volume.h>
 | 
					 | 
				
			||||||
#include <pulse/channelmap.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,337 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2004-2006 Lennart Poettering
 | 
					 | 
				
			||||||
  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
 | 
					 | 
				
			||||||
  Copyright 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/timeval.h>
 | 
					 | 
				
			||||||
#include <pulse/sample.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,62 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/scache.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*Modefied for pipewire by Jan Koester 2020*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/pulseaudio.h>
 | 
					 | 
				
			||||||
#include <pulse/thread-mainloop.h>
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <sys/types.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdarg.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,43 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/log.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/subscribe.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,144 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/log.h>
 | 
					 | 
				
			||||||
#include <pipewire/thread-loop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/mainloop.h>
 | 
					 | 
				
			||||||
#include <pulse/thread-mainloop.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,220 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2004-2006 Lennart Poettering
 | 
					 | 
				
			||||||
  Copyright 2006 Pierre Ossman <ossman@cendio.se> 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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
#include <sys/time.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_WINDOWS_H
 | 
					 | 
				
			||||||
#include <windows.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/timeval.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,295 +0,0 @@
 | 
				
			||||||
/***
 | 
					 | 
				
			||||||
  This file is part of PulseAudio.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Copyright 2006 Lennart Poettering
 | 
					 | 
				
			||||||
  Copyright 2006 Pierre Ossman <ossman@cendio.se> 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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
***/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 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 <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include <config.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_ICONV
 | 
					 | 
				
			||||||
#include <iconv.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/utf8.h>
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,124 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <time.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <pwd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/log.h>
 | 
					 | 
				
			||||||
#include <pipewire/pipewire.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/util.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <spa/utils/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/version.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SPA_EXPORT
 | 
					 | 
				
			||||||
const char* pa_get_library_version(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return pa_get_headers_version();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SPA_EXPORT
 | 
					 | 
				
			||||||
bool pa_is_pipewire(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,123 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2018 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <unistd.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/utils/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/xmalloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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],
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <stdio.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pulse/context.h>
 | 
					 | 
				
			||||||
#include <pulse/error.h>
 | 
					 | 
				
			||||||
#include <pulse/introspect.h>
 | 
					 | 
				
			||||||
#include <pulse/mainloop.h>
 | 
					 | 
				
			||||||
#include <pulse/timeval.h>
 | 
					 | 
				
			||||||
#include <pulse/subscribe.h>
 | 
					 | 
				
			||||||
#include <pulse/volume.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue