Remove pipewire-libpulse

We use the original pulseaudio client library and the replacement
server pipewire-pulse.
This commit is contained in:
Wim Taymans 2020-12-17 15:44:49 +01:00
parent 161c05d737
commit 91b0d3bb39
50 changed files with 3 additions and 17526 deletions

View file

@ -23,10 +23,6 @@ if get_option('pipewire-jack')
manpages += [[ 'pw-jack', '1' ]]
endif
if get_option('pipewire-pulseaudio')
manpages += [[ 'pw-pulse', '1' ]]
endif
foreach m : manpages
file = m.get(0) + '.' + m.get(1)
infile = file + '.xml.in'

View file

@ -63,7 +63,6 @@ This file is part of PipeWire.
<p>
<manref name="pipewire" section="1"/>,
<manref name="jackd" section="1"/>,
<manref name="pw-pulse" section="1"/>
</p>
</section>

View file

@ -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 &lt;@PACKAGE_BUGREPORT@&gt;;
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>

View file

@ -41,9 +41,9 @@ if host_machine.system() == 'linux'
# glibc ld.so interprets ${LIB} in a library loading path with an
# appropriate value for the current architecture, typically something
# like lib, lib64 or lib/x86_64-linux-gnu.
# This allows the same pw-pulse script to work for both 32- and 64-bit
# This allows the same pw-jack script to work for both 32- and 64-bit
# applications on biarch/multiarch distributions, by setting something
# like LD_LIBRARY_PATH='/usr/${LIB}/pipewire-0.3/pulse'.
# like LD_LIBRARY_PATH='/usr/${LIB}/pipewire-0.3/jack'.
# Note that ${LIB} is a special token expanded by the runtime linker,
# not an environment variable, and must be passed through literally.
modules_install_dir_dlopen = join_paths(prefix, '${LIB}', pipewire_name)
@ -327,7 +327,7 @@ dbus_dep = dependency('dbus-1')
sdl_dep = dependency('sdl2', required : false)
sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : false)
if get_option('gstreamer') or get_option('pipewire-pulseaudio')
if get_option('gstreamer')
glib_dep = dependency('glib-2.0', version : '>=2.32.0')
endif
@ -364,12 +364,6 @@ if get_option('pipewire-jack')
subdir('pipewire-jack/src')
endif
if get_option('pipewire-pulseaudio')
pulseaudio_dep = dependency('libpulse', version : '>= 11.1')
subdir('pipewire-pulseaudio/src')
subdir('pipewire-pulseaudio/test')
endif
if get_option('pipewire-alsa')
subdir('pipewire-alsa/alsa-plugins')
subdir('pipewire-alsa/conf')

View file

@ -49,13 +49,6 @@ option('pipewire-jack',
option('libjack-path',
description: 'Where to install the libjack.so library',
type: 'string')
option('pipewire-pulseaudio',
description: 'Enable pipewire-pulseaudio integration',
type: 'boolean',
value: false)
option('libpulse-path',
description: 'Where to install the libpulse.so library',
type: 'string')
option('spa-plugins',
description: 'Enable spa plugins integration',
type: 'boolean',

View file

@ -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!

View file

@ -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.

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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");
}

View file

@ -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]);
}

View file

@ -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)
{
}

View file

@ -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;
}

View file

@ -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)
{
}

View file

@ -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);
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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:
*;
};

View file

@ -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,
)

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 "$@"

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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],
)

View file

@ -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;
}