File libcanberra-0.30+2.obscpio of Package libcanberra
07070100000000000081A4000000000000000000000001509D8F37000001C4000000000000000000000000000000000000001E00000000libcanberra-0.30+2/.gitignore/build-aux
/src/canberra-system-bootup.service
/src/canberra-system-shutdown-reboot.service
/src/canberra-system-shutdown.service
/libcanberra-gtk3.pc
/README
Makefile
Makefile.in
/aclocal.m4
*.cache
/compile
/config.guess
/config.h
/config.h.in
/config.log
/config.rpath
/config.status
/config.sub
/configure
/depcomp
/gtk-doc.make
/install-sh
/libcanberra-gtk.pc
/libcanberra.pc
/libltdl
/libtool
/ltmain.sh
*~
/missing
/stamp-h1
/*.tar.gz
/*.tar.xz
07070100000001000081A4000000000000000000000001509D8F370000679F000000000000000000000000000000000000001800000000libcanberra-0.30+2/LGPL
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control
compilation and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply, and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License
may add an explicit geographical distribution limitation excluding those
countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms
of the ordinary General Public License).
To apply these terms, attach the following notices to the library.
It is safest to attach them to the start of each source file to most
effectively convey the exclusion of warranty; and each file should
have at least the "copyright" line and a pointer to where the full
notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the library,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James
Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
07070100000002000081A4000000000000000000000001509D8F37000007CB000000000000000000000000000000000000001F00000000libcanberra-0.30+2/Makefile.am# This file is part of libcanberra.
#
# Copyright 2008 Lennart Poettering
#
# libcanberra 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.
#
# libcanberra 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 libcanberra. If not, see
# <http://www.gnu.org/licenses/>.
dist_doc_DATA =
if USE_LYNX
dist_doc_DATA += README
endif
EXTRA_DIST = \
autogen.sh \
LGPL \
vala/libcanberra.vapi \
vala/libcanberra-gtk.vapi
SUBDIRS = src gtkdoc doc
MAINTAINERCLEANFILES = README
if USE_LYNX
noinst_DATA = README
endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libcanberra.pc
vapidir = $(datadir)/vala/vapi
vapi_DATA = vala/libcanberra.vapi
if HAVE_GTK_ANY
if HAVE_GTK
pkgconfig_DATA += libcanberra-gtk.pc
endif
if HAVE_GTK3
pkgconfig_DATA += libcanberra-gtk3.pc
endif
vapi_DATA += vala/libcanberra-gtk.vapi
endif
DISTCHECK_CONFIGURE_FLAGS = \
--enable-gtk-doc \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
ACLOCAL_AMFLAGS = -I m4
README:
rm -f README
$(MAKE) -C doc README
ln -s doc/README README
homepage: dist
test -d $$HOME/homepage/private
mkdir -p $$HOME/homepage/private/projects/libcanberra $$HOME/homepage/private/projects/libcanberra/gtkdoc
cp libcanberra-@PACKAGE_VERSION@.tar.xz $$HOME/homepage/private/projects/libcanberra
cp doc/README.html doc/style.css $$HOME/homepage/private/projects/libcanberra
cp -a gtkdoc/html/* $$HOME/homepage/private/projects/libcanberra/gtkdoc
ln -sf README.html $$HOME/homepage/private/projects/libcanberra/index.html
.PHONY: homepage
07070100000003000081A4000000000000000000000001509D8F37000036E1000000000000000000000000000000000000002000000000libcanberra-0.30+2/acinclude.m4dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
dnl
dnl @summary figure out how to build C programs using POSIX threads
dnl
dnl This macro figures out how to build C programs using POSIX threads.
dnl It sets the PTHREAD_LIBS output variable to the threads library and
dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
dnl C compiler flags that are needed. (The user can also force certain
dnl compiler flags/libs to be tested by setting these environment
dnl variables.)
dnl
dnl Also sets PTHREAD_CC to any special C compiler that is needed for
dnl multi-threaded programs (defaults to the value of CC otherwise).
dnl (This is necessary on AIX to use the special cc_r compiler alias.)
dnl
dnl NOTE: You are assumed to not only compile your program with these
dnl flags, but also link it with them as well. e.g. you should link
dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
dnl $LIBS
dnl
dnl If you are only building threads programs, you may wish to use
dnl these variables in your default LIBS, CFLAGS, and CC:
dnl
dnl LIBS="$PTHREAD_LIBS $LIBS"
dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
dnl CC="$PTHREAD_CC"
dnl
dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
dnl
dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
dnl default action will define HAVE_PTHREAD.
dnl
dnl Please let the authors know if this macro fails on any platform, or
dnl if you have any other suggestions or comments. This macro was based
dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
dnl We are also grateful for the helpful feedback of numerous users.
dnl
dnl @category InstalledPackages
dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
dnl @version 2006-05-29
dnl @license GPLWithACException
dnl
dnl Checks for GCC shared/pthread inconsistency based on work by
dnl Marcin Owsiany <marcin@owsiany.pl>
AC_DEFUN([ACX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
acx_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
AC_MSG_RESULT($acx_pthread_ok)
if test x"$acx_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
;;
esac
if test x"$acx_pthread_ok" = xno; then
for flag in $acx_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
if test x"$acx_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[acx_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($acx_pthread_ok)
if test "x$acx_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$acx_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
[attr_name=$attr; break])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
# The next part tries to detect GCC inconsistency with -shared on some
# architectures and systems. The problem is that in certain
# configurations, when -shared is specified, GCC "forgets" to
# internally use various flags which are still necessary.
AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies])
check_inconsistencies=yes
case "${host_cpu}-${host_os}" in
*-darwin*) check_inconsistencies=no ;;
esac
if test x"$GCC" != xyes -o "x$check_inconsistencies" != xyes ; then
AC_MSG_RESULT([no])
else
AC_MSG_RESULT([yes])
# In order not to create several levels of indentation, we test
# the value of "$ok" until we find out the cure or run out of
# ideas.
ok="no"
#
# Prepare the flags
#
save_CFLAGS="$CFLAGS"
save_LIBS="$LIBS"
save_CC="$CC"
# Try with the flags determined by the earlier checks.
#
# -Wl,-z,defs forces link-time symbol resolution, so that the
# linking checks with -shared actually have any value
#
# FIXME: -fPIC is required for -shared on many architectures,
# so we specify it here, but the right way would probably be to
# properly detect whether it is actually required.
CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CC="$PTHREAD_CC"
AC_MSG_CHECKING([whether -pthread is sufficient with -shared])
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
#
# Linux gcc on some architectures such as mips/mipsel forgets
# about -lpthread
#
if test x"$ok" = xno; then
AC_MSG_CHECKING([whether -lpthread fixes that])
LIBS="-lpthread $PTHREAD_LIBS $save_LIBS"
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
else
AC_MSG_RESULT([no])
fi
fi
#
# FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc
#
if test x"$ok" = xno; then
AC_MSG_CHECKING([whether -lc_r fixes that])
LIBS="-lc_r $PTHREAD_LIBS $save_LIBS"
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
else
AC_MSG_RESULT([no])
fi
fi
if test x"$ok" = xno; then
# OK, we have run out of ideas
AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries])
# so it's not safe to assume that we may use pthreads
acx_pthread_ok=no
fi
CFLAGS="$save_CFLAGS"
LIBS="$save_LIBS"
CC="$save_CC"
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
acx_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl ACX_PTHREAD
AC_DEFUN([AC_CHECK_DEFINE],[
AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1_$2])dnl
AC_CACHE_CHECK([for $1 in $2], ac_var,
AC_TRY_COMPILE([#include <$2>],[
#ifdef $1
int ok;
#else
choke me
#endif
],AS_VAR_SET(ac_var, yes),AS_VAR_SET(ac_var, no)))
AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl
AS_VAR_POPDEF([ac_var])dnl
])
AC_DEFUN([ACX_LIBWRAP], [
LIBWRAP_LIBS=
saved_LIBS="$LIBS"
LIBS="$LIBS -lwrap"
AC_MSG_CHECKING([for tcpwrap library and headers])
AC_LINK_IFELSE(
AC_LANG_PROGRAM(
[#include <tcpd.h>
#include <syslog.h>
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;],
[struct request_info *req;
return hosts_access (req);]),
[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?])
LIBWRAP_LIBS="-lwrap"
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)])
LIBS="$saved_LIBS"
])
AC_DEFUN([ACX_LIRC], [
LIRC_CFLAGS=
LIRC_LIBS=
AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1
LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0)
])
07070100000004000081ED000000000000000000000001509D8F37000007BF000000000000000000000000000000000000001E00000000libcanberra-0.30+2/autogen.sh#!/bin/bash
# This file is part of libcanberra.
#
# Copyright 2008 Lennart Poettering
#
# libcanberra 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.
#
# libcanberra 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 libcanberra. If not, see
# <http://www.gnu.org/licenses/>.
if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then
cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \
chmod +x .git/hooks/pre-commit && \
echo "Activated pre-commit hook."
fi
GTKDOCIZE=$(which gtkdocize 2>/dev/null)
if test -z $GTKDOCIZE; then
echo "You don't have gtk-doc installed, and thus won't be able to generate the documentation."
echo 'EXTRA_DIST =' > gtkdoc/gtk-doc.make
else
gtkdocize --docdir gtkdoc/
gtkdocargs=--enable-gtk-doc
fi
autoreconf --force --install --symlink
libdir() {
echo $(cd $1/$(gcc -print-multi-os-directory); pwd)
}
args="\
--sysconfdir=/etc \
--localstatedir=/var \
--libdir=$(libdir /usr/lib) \
--libexecdir=/usr/lib \
$gtkdocargs"
if [ "x$1" == "xc" ]; then
./configure CFLAGS='-g -O0 -Wp,-U_FORTIFY_SOURCE' $args
make clean
else
echo
echo "----------------------------------------------------------------"
echo "Initialized build system. For a common configuration please run:"
echo "----------------------------------------------------------------"
echo
echo "./configure CFLAGS='-g -O0 -Wp,-U_FORTIFY_SOURCE' $args"
echo
fi
07070100000005000081A4000000000000000000000001509D8F37000056C0000000000000000000000000000000000000002000000000libcanberra-0.30+2/configure.ac# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
# This file is part of libcanberra.
#
# Copyright 2008 Lennart Poettering
#
# libcanberra 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.
#
# libcanberra 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 libcanberra. If not, see
# <http://www.gnu.org/licenses/>.
m4_define([ca_major],[0])
m4_define([ca_minor],[30])
m4_define([ca_version],[ca_major.ca_minor])
AC_PREREQ([2.68])
AC_INIT([libcanberra],
[ca_version],
[mzyvopnaoreen (at) 0pointer (dot) de],
[libcanberra],
[http://0pointer.de/lennart/projects/libcanberra/])
AC_CONFIG_SRCDIR([src/common.c])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR(m4)
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([foreign 1.11 -Wall silent-rules tar-pax no-dist-gzip dist-xz])
AM_SILENT_RULES([yes])
AC_SUBST(LIBCANBERRA_VERSION_INFO, [2:5:2])
AC_SUBST(LIBCANBERRA_GTK_VERSION_INFO, [1:9:1])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
if type -p stow > /dev/null && test -d /usr/local/stow ; then
AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***])
ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
fi
#### Checks for programs. ####
AC_PROG_MKDIR_P
AC_PROG_LN_S
AM_PROG_AR
# CC
AC_PROG_CC
AC_PROG_CC_C99
AM_PROG_CC_C_O
AC_PROG_GCC_TRADITIONAL
AC_USE_SYSTEM_EXTENSIONS
# C++
AC_PROG_CXX
CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
-pipe \
-Wall \
-W \
-Wextra \
-Winline \
-Wvla \
-Wundef \
-Wformat=2 \
-Wlogical-op \
-Wsign-compare \
-Wformat-security \
-Wmissing-include-dirs \
-Wformat-nonliteral \
-Wold-style-definition \
-Wpointer-arith \
-Winit-self \
-Wdeclaration-after-statement \
-Wfloat-equal \
-Wmissing-prototypes \
-Wstrict-prototypes \
-Wredundant-decls \
-Wmissing-declarations \
-Wmissing-noreturn \
-Wshadow \
-Wendif-labels \
-Wcast-align \
-Wstrict-aliasing=2 \
-Wwrite-strings \
-Wno-long-long \
-Wno-overlength-strings \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-Wno-unused-result \
-Wunsafe-loop-optimizations \
-Wpacked \
-Werror=overflow \
-Wp,-D_FORTIFY_SOURCE=2 \
-ffast-math \
-fno-common \
-fdiagnostics-show-option \
-fno-strict-aliasing \
-ffunction-sections \
-fdata-sections])
AC_SUBST([WARNINGFLAGS], $with_cflags)
CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\
-Wl,--as-needed \
-Wl,--gc-sections])
AC_SUBST([GCLDFLAGS], $with_ldflags)
#### libtool stuff ####
LT_PREREQ(2.2)
LT_INIT([dlopen win32-dll disable-static])
dnl Unfortunately, even up to libtool 2.2.6a there is no way to know
dnl exactly which version of libltdl is present in the system, so we
dnl just assume that it's a working version as long as we have the
dnl library and the header files.
dnl
dnl As an extra safety device, check for lt_dladvise_init() which is
dnl only implemented in libtool 2.x, and refine as we go if we have
dnl refined requirements.
dnl
dnl Check the header files first since the system may have a
dnl libltdl.so for runtime, but no headers, and we want to bail out as
dnl soon as possible.
dnl
dnl We don't need any special variable for this though, since the user
dnl can give the proper place to find libltdl through the standard
dnl variables like LDFLAGS and CPPFLAGS.
AC_CHECK_HEADER([ltdl.h],
[AC_CHECK_LIB([ltdl], [lt_dladvise_init], [LIBLTDL=-lltdl], [LIBLTDL=])],
[LIBLTDL=])
AS_IF([test "x$LIBLTDL" = "x"],
[AC_MSG_ERROR([Unable to find libltdl.])])
AC_SUBST([LIBLTDL])
#### Determine build environment ####
os_is_win32=0
case "$host_os" in
mingw*)
AC_DEFINE([OS_IS_WIN32], 1, [Build target is Windows.])
os_is_win32=1
;;
esac
AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1")
AM_CONDITIONAL(USE_VERSION_SCRIPT, test "x$supports_anon_versioning" = "xyes" )
###################################
# Basic environment checks #
###################################
#### Checks for header files. ####
# ISO
AC_HEADER_STDC
# XPG4-UNIX
AC_CHECK_HEADERS([sys/poll.h])
# Other
AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([byteswap.h])
#### Typdefs, structures, etc. ####
AC_C_CONST
AC_C_BIGENDIAN
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_CHECK_TYPES(ssize_t, , [AC_DEFINE([ssize_t], [signed long],
[Define ssize_t if it is not done by the standard libs.])])
AC_TYPE_OFF_T
AC_TYPE_UID_T
#### Check for libs ####
# ISO
AC_SEARCH_LIBS([pow], [m])
# POSIX
AC_SEARCH_LIBS([sched_setscheduler], [rt])
# Non-standard
#### Check for functions ####
# ISO
AC_CHECK_FUNCS([lrintf strtof])
# POSIX
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([gettimeofday nanosleep posix_memalign sigaction sleep sysconf pthread_yield])
# SUSv3
AC_CHECK_FUNCS([strerror_r])
# BSD
AC_CHECK_FUNCS([lstat])
# GNU
AC_CHECK_FUNCS([strndup])
#### POSIX threads ####
ACX_PTHREAD
#### Large File-Support (LFS) ####
AC_SYS_LARGEFILE
###################################
# External libraries #
###################################
#### pkg-config ####
PKG_PROG_PKG_CONFIG
#### ALSA support (optional) ####
AC_ARG_ENABLE([alsa],
AS_HELP_STRING([--disable-alsa], [Disable optional ALSA support]),
[
case "${enableval}" in
yes) alsa=yes ;;
no) alsa=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-alsa) ;;
esac
],
[alsa=auto])
if test "x${alsa}" != xno ; then
PKG_CHECK_MODULES(ALSA, [ alsa >= 1.0.0 ],
[
HAVE_ALSA=1
AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?])
],
[
HAVE_ALSA=0
if test "x$alsa" = xyes ; then
AC_MSG_ERROR([*** ALSA not found ***])
fi
])
else
HAVE_ALSA=0
fi
AC_SUBST(ALSA_CFLAGS)
AC_SUBST(ALSA_LIBS)
### OSS support (optional) ###
AC_ARG_ENABLE([oss],
AS_HELP_STRING([--disable-oss], [Disable optional OSS support]),
[
case "${enableval}" in
yes) oss=yes ;;
no) oss=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-oss) ;;
esac
],
[oss=auto])
if test "x${oss}" != xno ; then
AC_CHECK_HEADERS(soundcard.h sys/soundcard.h machine/soundcard.h)
if test "${ac_cv_header_sys_soundcard_h}" = "yes" || \
test "${ac_cv_header_soundcard_h}" = "yes" || \
test "${ac_cv_header_machine_soundcard_h}" = "yes"; then
HAVE_OSS=1
AC_DEFINE([HAVE_OSS], 1, [Have OSS?])
else
HAVE_OSS=0
if test "x$oss" = xyes ; then
AC_MSG_ERROR([*** OSS not found ***])
fi
fi
else
HAVE_OSS=0
fi
### PulseAudio (optional) ####
AC_ARG_ENABLE([pulse],
AS_HELP_STRING([--disable-pulse], [Disable optional PulseAudio support]),
[
case "${enableval}" in
yes) pulse=yes ;;
no) pulse=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-pulse) ;;
esac
],
[pulse=auto])
if test "x${pulse}" != xno ; then
if test -d ../pulseaudio ; then
PULSE_CFLAGS='-I$(top_srcdir)/../pulseaudio/src'
PULSE_LIBS='-L$(top_srcdir)/../pulseaudio/src/.libs -lpulse'
HAVE_PULSE=1
AC_DEFINE([HAVE_PULSE], 1, [Have PulseAudio?])
echo "*** Found pulseaudio in ../pulseaudio, using that version ***"
else
PKG_CHECK_MODULES(PULSE, [ libpulse >= 0.9.11 ],
[
HAVE_PULSE=1
AC_DEFINE([HAVE_PULSE], 1, [Have PulseAudio?])
],
[
HAVE_PULSE=0
if test "x$pulse" = xyes ; then
AC_MSG_ERROR([*** PulseAudio not found ***])
fi
])
fi
else
HAVE_PULSE=0
fi
AC_SUBST(PULSE_CFLAGS)
AC_SUBST(PULSE_LIBS)
#### UDEV support (optional) ####
AC_ARG_ENABLE([udev],
AS_HELP_STRING([--disable-udev], [Disable optional udev support]),
[
case "${enableval}" in
yes) udev=yes ;;
no) udev=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-udev) ;;
esac
],
[udev=auto])
if test "x${udev}" != xno ; then
PKG_CHECK_MODULES(UDEV, [ libudev >= 160 ],
[
HAVE_UDEV=1
AC_DEFINE([HAVE_UDEV], 1, [Have udev?])
],
[
HAVE_UDEV=0
if test "x$udev" = xyes ; then
AC_MSG_ERROR([*** udev not found ***])
fi
])
else
HAVE_UDEV=0
fi
AC_SUBST(UDEV_CFLAGS)
AC_SUBST(UDEV_LIBS)
AM_CONDITIONAL([HAVE_UDEV], [test "x$HAVE_UDEV" = x1])
#### GStreamer support (optional) ####
AC_ARG_ENABLE([gstreamer],
AS_HELP_STRING([--disable-gstreamer], [Disable optional GStreamer support]),
[
case "${enableval}" in
yes) gstreamer=yes ;;
no) gstreamer=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-gstreamer) ;;
esac
],
[gstreamer=auto])
if test "x${gstreamer}" != xno ; then
PKG_CHECK_MODULES(GST, [ gstreamer-1.0 >= 0.10.15 ],
[
HAVE_GSTREAMER=1
AC_DEFINE([HAVE_GSTREAMER], 1, [Have GStreamer?])
],
[
HAVE_GSTREAMER=0
if test "x$gstreamer" = xyes ; then
AC_MSG_ERROR([*** GStreamer not found ***])
fi
])
else
HAVE_GSTREAMER=0
fi
AC_SUBST(GSTREAMER_CFLAGS)
AC_SUBST(GSTREAMER_LIBS)
### Null output (optional) ####
AC_ARG_ENABLE([null],
AS_HELP_STRING([--disable-null], [Disable optional null output]),
[
case "${enableval}" in
yes) null=yes ;;
no) null=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-null) ;;
esac
],
[null=yes])
if test "x${null}" != xno ; then
HAVE_NULL=1
AC_DEFINE([HAVE_NULL], 1, [Have NULL output?])
else
HAVE_NULL=0
fi
### GTK (optional) ####
AC_ARG_ENABLE([gtk],
AS_HELP_STRING([--disable-gtk], [Disable optional GTK+ support]),
[
case "${enableval}" in
yes) gtk=yes ;;
no) gtk=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-gtk) ;;
esac
],
[gtk=auto])
AM_CONDITIONAL([GCONF_SCHEMAS_INSTALL], [false])
if test "x${gtk}" != xno ; then
PKG_CHECK_MODULES(GTK, [ gtk+-2.0 >= 2.20.0 gthread-2.0 glib-2.0 >= 2.32 gdk-2.0 x11 ],
[
HAVE_GTK=1
AC_DEFINE([HAVE_GTK], 1, [Have GTK?])
GTK_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0`
GTK_MODULES_DIR="${libdir}/gtk-2.0/modules"
],
[
HAVE_GTK=0
if test "x$gtk" = xyes ; then
AC_MSG_ERROR([*** GTK not found ***])
fi
])
else
HAVE_GTK=0
fi
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
AC_SUBST(GTK_MODULES_DIR)
AC_SUBST(HAVE_GTK)
AM_CONDITIONAL([HAVE_GTK], [test "x$HAVE_GTK" = x1])
AC_ARG_ENABLE([gtk3],
AS_HELP_STRING([--disable-gtk3], [Disable optional GTK+ 3 support]),
[
case "${enableval}" in
yes) gtk3=yes ;;
no) gtk3=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-gtk3) ;;
esac
],
[gtk3=auto])
if test "x${gtk3}" != xno ; then
PKG_CHECK_MODULES(GTK3, [ gtk+-3.0 gthread-2.0 glib-2.0 >= 2.32 gdk-3.0 x11 ],
[
HAVE_GTK3=1
AC_DEFINE([HAVE_GTK3], 1, [Have GTK3?])
GTK3_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-3.0`
GTK3_MODULES_DIR="${libdir}/gtk-3.0/modules"
],
[
HAVE_GTK3=0
if test "x$gtk3" = xyes ; then
AC_MSG_ERROR([*** GTK3 not found ***])
fi
])
else
HAVE_GTK3=0
fi
AC_SUBST(GTK3_CFLAGS)
AC_SUBST(GTK3_LIBS)
AC_SUBST(GTK3_MODULES_DIR)
AC_SUBST(HAVE_GTK3)
AM_CONDITIONAL([HAVE_GTK3], [test "x$HAVE_GTK3" = x1])
AM_CONDITIONAL([HAVE_GTK_ANY], [test "x$HAVE_GTK" = x1 -o "x$HAVE_GTK3" = x1])
#### TDB cache support (optional) ####
AC_ARG_ENABLE([tdb],
AS_HELP_STRING([--disable-tdb], [Disable optional tdb support]),
[
case "${enableval}" in
yes) tdb=yes ;;
no) tdb=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-tdb) ;;
esac
],
[tdb=auto])
if test "x${tdb}" != xno ; then
PKG_CHECK_MODULES(TDB, [ tdb >= 1.1 ],
[
HAVE_TDB=1
AC_DEFINE([HAVE_TDB], 1, [Have TDB?])
],
[
HAVE_TDB=0
if test "x$tdb" = xyes ; then
AC_MSG_ERROR([*** TDB not found ***])
fi
])
else
HAVE_TDB=0
fi
AC_SUBST(TDB_CFLAGS)
AC_SUBST(TDB_LIBS)
AC_SUBST(HAVE_TDB)
AM_CONDITIONAL([HAVE_TDB], [test "x$HAVE_TDB" = x1])
### Global cache support ###
# For now, we only support tdb based caching, hence we'll shortcut this here
HAVE_CACHE=$HAVE_TDB
AC_SUBST(HAVE_CACHE)
AM_CONDITIONAL([HAVE_CACHE], [test "x$HAVE_CACHE" = x1])
if test "x${HAVE_CACHE}" = x1 ; then
AC_DEFINE([HAVE_CACHE], 1, [Do cacheing?])
fi
#
# systemd
#
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[],
[with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
if test "x$with_systemdsystemunitdir" != xno; then
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
### LYNX documentation generation ###
AC_ARG_ENABLE([lynx],
AS_HELP_STRING([--disable-lynx], [Turn off lynx usage for documentation generation]),
[
case "${enableval}" in
yes) lynx=yes ;;
no) lynx=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;;
esac
],
[lynx=yes])
if test x$lynx = xyes ; then
AC_CHECK_PROG(have_lynx, lynx, yes, no)
if test "x$have_lynx" = xno ; then
AC_MSG_WARN([*** lynx not found, plain text README will not be built ***])
fi
fi
AM_CONDITIONAL([USE_LYNX], [test "x$have_lynx" = xyes])
### Vorbis (mandatory) ###
PKG_CHECK_MODULES(VORBIS, [ vorbisfile ])
### Chose builtin driver ###
AC_ARG_WITH([builtin],
[AS_HELP_STRING([--with-builtin], [Choose builtin driver])],
[],
[with_builtin=dso])
HAVE_DSO=0
BUILTIN_DSO=0
BUILTIN_PULSE=0
BUILTIN_ALSA=0
BUILTIN_OSS=0
BUILTIN_GSTREAMER=0
BUILTIN_NULL=0
case "x$with_builtin" in
xpulse)
if test "x$HAVE_PULSE" != x1 ; then
AC_MSG_ERROR([*** PulseAudio selected for builtin driver, but not enabled. ***])
fi
BUILTIN_PULSE=1
HAVE_ALSA=0
HAVE_OSS=0
HAVE_GSTREAMER=0
HAVE_NULL=0
;;
xalsa)
if test "x$HAVE_ALSA" != x1 ; then
AC_MSG_ERROR([*** ALSA selected for builtin driver, but not enabled. ***])
fi
BUILTIN_ALSA=1
HAVE_OSS=0
HAVE_PULSE=0
HAVE_GSTREAMER=0
HAVE_NULL=0
;;
xgstreamer)
if test "x$HAVE_GSTREAMER" != x1 ; then
AC_MSG_ERROR([*** GStremaer selected for builtin driver, but not enabled. ***])
fi
BUILTIN_GSTREAMER=1
HAVE_ALSA=0
HAVE_OSS=0
HAVE_PULSE=0
HAVE_NULL=0
;;
xoss)
if test "x$HAVE_OSS" != x1 ; then
AC_MSG_ERROR([*** OSS selected for builtin driver, but not enabled. ***])
fi
BUILTIN_OSS=1
HAVE_ALSA=0
HAVE_PULSE=0
HAVE_GSTREAMER=0
HAVE_NULL=0
;;
xnull)
if test "x$HAVE_NULL" != x1 ; then
AC_MSG_ERROR([*** Null output selected for builtin driver, but not enabled. ***])
fi
BUILTIN_NULL=1
HAVE_PULSE=0
HAVE_ALSA=0
HAVE_OSS=0
HAVE_GSTREAMER=0
;;
xdso)
BUILTIN_DSO=1
HAVE_DSO=1
AC_DEFINE([HAVE_DSO], 1, [Have DSO?])
;;
*)
AC_MSG_ERROR([*** Unknown driver $with_builtin selected for builtin ***])
esac
if test "x$HAVE_PULSE" != x1 -a "x$HAVE_ALSA" != x1 -a "x$HAVE_OSS" != x1 -a "x$HAVE_GSTREAMER" != x1 -a "x$HAVE_NULL" != x1 ; then
AC_MSG_ERROR([*** No backend enabled. ***])
fi
AC_SUBST(HAVE_DSO)
AC_SUBST(HAVE_PULSE)
AC_SUBST(HAVE_ALSA)
AC_SUBST(HAVE_OSS)
AC_SUBST(HAVE_GSTREAMER)
AC_SUBST(HAVE_NULL)
AC_SUBST(BUILTIN_DSO)
AC_SUBST(BUILTIN_PULSE)
AC_SUBST(BUILTIN_ALSA)
AC_SUBST(BUILTIN_OSS)
AC_SUBST(BUILTIN_GSTREAMER)
AC_SUBST(BUILTIN_NULL)
AM_CONDITIONAL([HAVE_PULSE], [test "x$HAVE_PULSE" = x1])
AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1])
AM_CONDITIONAL([HAVE_GSTREAMER], [test "x$HAVE_GSTREAMER" = x1])
AM_CONDITIONAL([HAVE_NULL], [test "x$HAVE_NULL" = x1])
AM_CONDITIONAL([BUILTIN_DSO], [test "x$BUILTIN_DSO" = x1])
AM_CONDITIONAL([BUILTIN_PULSE], [test "x$BUILTIN_PULSE" = x1])
AM_CONDITIONAL([BUILTIN_ALSA], [test "x$BUILTIN_ALSA" = x1])
AM_CONDITIONAL([BUILTIN_OSS], [test "x$BUILTIN_OSS" = x1])
AM_CONDITIONAL([BUILTIN_GSTREAMER], [test "x$BUILTIN_GSTREAMER" = x1])
AM_CONDITIONAL([BUILTIN_NULL], [test "x$BUILTIN_NULL" = x1])
AC_SUBST([CA_MAJOR],[ca_major])
AC_SUBST([CA_MINOR],[ca_minor])
GTK_DOC_CHECK(1.9)
###################################
# Output #
###################################
AC_CONFIG_FILES([
Makefile
src/Makefile
libcanberra.pc
libcanberra-gtk.pc
libcanberra-gtk3.pc
src/canberra.h
gtkdoc/Makefile
doc/Makefile
doc/README.html
])
AC_OUTPUT
# ==========================================================================
ENABLE_BUILTIN_DSO=no
if test "x$BUILTIN_DSO" = "x1" ; then
ENABLE_BUILTIN_DSO=yes
fi
ENABLE_PULSE=no
if test "x$HAVE_PULSE" = "x1" ; then
ENABLE_PULSE=yes
fi
ENABLE_BUILTIN_PULSE=no
if test "x$BUILTIN_PULSE" = "x1" ; then
ENABLE_BUILTIN_PULSE=yes
fi
ENABLE_ALSA=no
if test "x$HAVE_ALSA" = "x1" ; then
ENABLE_ALSA=yes
fi
ENABLE_BUILTIN_ALSA=no
if test "x$BUILTIN_ALSA" = "x1" ; then
ENABLE_BUILTIN_ALSA=yes
fi
ENABLE_OSS=no
if test "x$HAVE_OSS" = "x1" ; then
ENABLE_OSS=yes
fi
ENABLE_BUILTIN_OSS=no
if test "x$BUILTIN_OSS" = "x1" ; then
ENABLE_BUILTIN_OSS=yes
fi
ENABLE_GSTREAMER=no
if test "x$HAVE_GSTREAMER" = "x1" ; then
ENABLE_GSTREAMER=yes
fi
ENABLE_BUILTIN_GSTREAMER=no
if test "x$BUILTIN_GSTREAMER" = "x1" ; then
ENABLE_BUILTIN_GSTREAMER=yes
fi
ENABLE_NULL=no
if test "x$HAVE_NULL" = "x1" ; then
ENABLE_NULL=yes
fi
ENABLE_BUILTIN_NULL=no
if test "x$BUILTIN_NULL" = "x1" ; then
ENABLE_BUILTIN_NULL=yes
fi
ENABLE_GTK=no
if test "x$HAVE_GTK" = "x1" ; then
ENABLE_GTK=yes
fi
ENABLE_GTK3=no
if test "x$HAVE_GTK3" = "x1" ; then
ENABLE_GTK3=yes
fi
ENABLE_TDB=no
if test "x$HAVE_TDB" = "x1" ; then
ENABLE_TDB=yes
fi
ENABLE_CACHE=no
if test "x$HAVE_CACHE" = "x1" ; then
ENABLE_CACHE=yes
fi
ENABLE_UDEV=no
if test "x$HAVE_UDEV" = "x1" ; then
ENABLE_UDEV=yes
fi
echo "
---{ $PACKAGE_NAME $VERSION }---
prefix: ${prefix}
sysconfdir: ${sysconfdir}
localstatedir: ${localstatedir}
Compiler: ${CC}
CFLAGS: ${CFLAGS}
C++-Compiler: ${CXX}
CXXFLAGS: ${CXXFLAGS}
Builtin DSO: ${ENABLE_BUILTIN_DSO}
Enable PulseAudio: ${ENABLE_PULSE}
Builtin PulseAudio: ${ENABLE_BUILTIN_PULSE}
Enable ALSA: ${ENABLE_ALSA}
Builtin ALSA: ${ENABLE_BUILTIN_ALSA}
Enable OSS: ${ENABLE_OSS}
Builtin OSS: ${ENABLE_BUILTIN_OSS}
Enable GStreamer: ${ENABLE_GSTREAMER}
Builtin GStreamer: ${ENABLE_BUILTIN_GSTREAMER}
Enable Null Output: ${ENABLE_NULL}
Builtin Null Output: ${ENABLE_BUILTIN_NULL}
Enable tdb: ${ENABLE_TDB}
Enable lookup cache: ${ENABLE_CACHE}
Enable GTK+: ${ENABLE_GTK}
GTK Modules Directory: ${GTK_MODULES_DIR}
Enable GTK3+: ${ENABLE_GTK3}
GTK3 Modules Directory: ${GTK3_MODULES_DIR}
Enable udev: ${ENABLE_UDEV}
systemd Unit Directory: ${with_systemdsystemunitdir}
"
if test "x$HAVE_OSS" = "x1" -a "x$HAVE_ALSA" = "x1" ; then
echo "
WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
You enabled the OSS driver although the ALSA driver is
available. Please note that if ALSA is available the OSS driver is a
very bad choice, since it currently doesn't support resampling or
converting sample types to the necessities of the hardware if the
hardware does not directly support the format/rate of the sound file
to play.
Packagers of Linux distributions! Please think twice if you package
the OSS driver! It is probably best to not to pacakge it at all -- at
least until the OSS driver learned sample type conversion and the most
basic resampling. Otherwise you might end up getting bug reports from
users misunderstanding the OSS vs. ALSA situation.
WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
"
fi
07070100000006000041ED000000000000000000000002509D8F3700000000000000000000000000000000000000000000001700000000libcanberra-0.30+2/doc07070100000007000081A4000000000000000000000001509D8F3700000015000000000000000000000000000000000000002200000000libcanberra-0.30+2/doc/.gitignore/README
/README.html
07070100000008000081A4000000000000000000000001509D8F3700000444000000000000000000000000000000000000002300000000libcanberra-0.30+2/doc/Makefile.am# This file is part of libcanberra.
#
# Copyright 2008 Lennart Poettering
#
# libcanberra 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.
#
# libcanberra 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 libcanberra. If not, see
# <http://www.gnu.org/licenses/>.
noinst_DATA = README.html
EXTRA_DIST = $(noinst_DATA) style.css README.html.in
MAINTAINERCLEANFILES = README.html
CLEANFILES =
if USE_LYNX
README: README.html
$(AM_V_GEN)lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@
noinst_DATA += README
CLEANFILES += README
endif
tidy: README.html
tidy -qe < README.html ; true
.PHONY: tidy
07070100000009000081A4000000000000000000000001509D8F3700002DD1000000000000000000000000000000000000002600000000libcanberra-0.30+2/doc/README.html.in<?xml version="1.0" encoding="utf-8"?> <!-- -*-html-helper-*- -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>libcanberra @PACKAGE_VERSION@</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<h1><a name="top">libcanberra @PACKAGE_VERSION@</a></h1>
<p><i>Copyright 2008-2012 Lennart Poettering <@PACKAGE_BUGREPORT@></i></p>
<ul class="toc">
<li><a href="#license">License</a></li>
<li><a href="#news">News</a></li>
<li><a href="#overview">Overview</a></li>
<li><a href="#status">Current Status</a></li>
<li><a href="#documentation">Documentation</a></li>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#acks">Acknowledgements</a></li>
<li><a href="#download">Download</a></li>
</ul>
<h2><a name="license">License</a></h2>
<p>This program 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.</p>
<p>This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.</p>
<h2><a name="news">News</a></h2>
<div class="news-date">Tue 25 Sep
2012: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.30.tar.xz">Version
0.30</a> released; Port to GStreamer 1.0.</p>
<div class="news-date">Tue 15 May
2012: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.29.tar.xz">Version
0.29</a> released; A couple of bugfixes, drop GConf usage.</p>
<div class="news-date">Thu 24 Feb
2011: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.28.tar.gz">Version
0.28</a> released; Hook properly into GNOME 3.0 sessions; this drops
support for GNOME 2.0 sessions, but not applications.</p>
<div class="news-date">Fri 18 Feb
2011: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.27.tar.gz">Version
0.27</a> released; Gtk+ 3.x fixes; add new tool to implement boot-up
sounds when used with systemd; other fixes</p>
<div class="news-date">Mon 4 Oct
2010: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.26.tar.gz">Version
0.26</a> released; Gtk+ 3.x fixes.</p>
<div class="news-date">Sun 13 Jun
2010: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.25.tar.gz">Version
0.25</a> released; Optionally build with Gtk+ 3.x in addition to Gtk+ 2.x.</p>
<div class="news-date">Mon 19 Apr
2010: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.24.tar.gz">Version
0.24</a> released; GTK code is now fine with GSEAL. Minor fixes in the
PulseAudio backend, other fixes.</p>
<div class="news-date">Sat 20 Feb
2010: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.23.tar.gz">Version
0.23</a> released; various minor fixes in the pulse and gstreamer
backends as well in the Vala API. Support for the recently
standardized Vorbis 6.1/7.1 multichannel modes.</p>
<div class="news-date">Tue 20 Oct
2009: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.22.tar.gz">Version
0.22</a> released; small fix to make sure we don't dereference a null
pointer. </p>
<div class="news-date">Fri 16 Oct 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.21.tar.gz">Version 0.21</a> released;
suppress casting warning</p>
<div class="news-date">Thu 15 Oct 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.20.tar.gz">Version 0.20</a> released;
minor casting fix</p>
<div class="news-date">Wed 14 Oct 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.19.tar.gz">Version 0.19</a> released;
some important fixes for the Gtk support</p>
<div class="news-date">Sun 20 Sep 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.18.tar.gz">Version 0.18</a> released;
numerous updates for the Gtk support</p>
<div class="news-date">Fri 12 Sep 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.17.tar.gz">Version 0.17</a> released;
add vala vapi file; numerous updates to Gtk support</p>
<div class="news-date">Thu 27 Aug 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.16.tar.gz">Version 0.16</a> released;
add new <tt>ca_context_playing()</tt> call</p>
<div class="news-date">Wed 5 Aug 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.15.tar.gz">Version 0.15</a> released;
bug fixes</p>
<div class="news-date">Thu 2 Jul 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.14.tar.gz">Version 0.14</a> released;
bug fixes</p>
<div class="news-date">Tue 23 Jun 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.13.tar.gz">Version 0.13</a> released;
multichannel support; gtk multihead support; bug fixes</p>
<div class="news-date">Mon 13 Apr 2009: </div> <p class="news-text"><a
href="@PACKAGE_URL@libcanberra-0.12.tar.gz">Version 0.12</a> released;
changes include: various fixes and updates for the PulseAudio backend;
detect forks and return an error for all functions in that case</p>
<div class="news-date">Wed 21 Jan
2009: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.11.tar.gz">Version
0.11</a> released; changes include: major GStreamer backend fixes; update to libtool 2.2; a few other fixes</p>
<div class="news-date">Mon 6 Oct
2008: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.10.tar.gz">Version
0.10</a> released; changes include: install Gtk+ module using GConf; a few other fixes</p>
<div class="news-date">Tue 9 Sep
2008: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.9.tar.gz">Version
0.9</a> released; changes include: GStreamer fixes, include (optional)
libtdb based lookup cache.</p>
<div class="news-date">Thu 28 Aug
2008: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.8.tar.gz">Version
0.8</a> released; changes include: new OSS and GStreamer backend;
portability fixes for FreeBSD/Solaris; the multi backend works now</p>
<div class="news-date">Thu 14 Aug
2008: </div> <p class="news-text"><a href="@PACKAGE_URL@libcanberra-0.7.tar.gz">Version
0.7</a> released; changes include: documentation updates; various bug
fixes; add this web site/README; allow playback of event sounds with
only a sound file path specified; other changes</p>
<h2><a name="overview">Overview</a></h2>
<p><tt>libcanberra</tt> is an implementation of
the <a href="http://freedesktop.org/wiki/Specifications/sound-theme-spec">XDG
Sound Theme and Name Specifications</a>, for generating event sounds
on free desktops, such
as <a href="http://www.gnome.org/">GNOME</a>. It comes with several
backends
(<a href="http://alsa-project.org/">ALSA</a>, <a href="http://pulseaudio.org/">PulseAudio</a>,
OSS, <a href="http://gstreamer.org/">GStreamer</a>, null) and is
designed to be portable. It consists of the following parts:</p>
<ol>
<li><tt>libcanberra</tt>: the main library</li>
<li><tt>libcanberra-gtk</tt>: some glue code to make it easier to use <tt>libcanberra</tt> from Gtk+ applications</li>
<li><tt>libcanberra-gtk-module</tt>: a Gtk+ module that uses <tt>libcanberra-gtk</tt> to trigger input feedback event sounds</li>
</ol>
<p>For more information see <a href="http://0pointer.de/blog/projects/sixfold-announcement.html">the original announcement.</a></p>
<h2><a name="status">Current Status</a></h2>
<p><tt>libcanberra</tt> is mostly feature complete. For now however it
includes backends only for ALSA, PulseAudio, OSS and GStreamer.</p>
<p><tt>libcanberra</tt> has been
declared <a href="http://mail.gnome.org/archives/devel-announce-list/2008-August/msg00001.html">a
blessed GNOME dependency</a>.</p>
<p>The OSS driver is incomplete: only sound files that are in a format
natively understood by the sound card are supported. If the sample
type, channel map or sampling rate of the sound file are not supported
by the sound card no automatic conversion will take place and the file
will not be played. Also note that the OSS backend is most likely
incompatible with OSS4, due to subtle incompatibilities between OSS4
and the OSS 3.x.</p>
<p>It is recommended to always take the "shortest" path from
libcanberra to the audio device. I.e. don't use the GStreamer plugin
if libcanberra supports the final output target natively. Besides
being more resource-friendly and less error-prone, some advanced
functionality might get lost with each layer you add to your
stack. For example: while you could use libcanberra's Gstreamer
backend to output to a PulseAudio server this will not be able to make
use of sample cacheing or will be able to attach additional meta data
to the sounds played, which might be necessary for effects like
positional event sounds.</p>
<h2><a name="documentation">Documentation</a></h2>
<p>You may browse the <a href="http://www.gtk.org/gtk-doc/">gtkdoc</a>
generated <a href="http://0pointer.de/lennart/projects/libcanberra/gtkdoc/">programing
documentation</a> of the API.</p>
<h2><a name="requirements">Requirements</a></h2>
<p>Currently, <tt>libcanberra</tt> is tested on Linux only.</p>
<p><tt>libcanberra</tt> was developed and tested on Fedora Rawhide
from August 2008, it should work on most other Linux
distributions (and maybe Unix versions) since it uses GNU autoconf and
GNU libtool for source code configuration and shared library
management.</p>
<p><tt>libcanberra</tt> has no dependencies besides the OGG Vorbis
development headers and whatever the selected backends require. Gtk+
support is optional. An optional lookup cache can be used if Samba's
tdb trivial database is available.</p>
<h2><a name="installation">Installation</a></h2>
<p>As this package is made with the GNU autotools you should run
<tt>./configure</tt> inside the distribution directory for configuring
the source tree. After that you should run <tt>make</tt> for
compilation and <tt>make install</tt> (as root) for installation of
<tt>libcanberra</tt>.</p>
<h2><a name="acks">Acknowledgements</a></h2>
<p>Marc-André Lureau and Brian Cameron for the GStreamer backend.</p>
<p>Joe Marcus Clarke for the OSS backend.</p>
<p>Diego Elio Pettenò for various build system fixes.</p>
<h2><a name="download">Download</a></h2>
<p>The newest release is always available from <a href="@PACKAGE_URL@">@PACKAGE_URL@</a></p>
<p>The current release is <a href="@PACKAGE_URL@libcanberra-@PACKAGE_VERSION@.tar.xz">@PACKAGE_VERSION@</a></p>
<p>Get <tt>libcanberra</tt>'s development sources from the <a href="http://git-scm.com/">GIT</a> <a href="git://git.0pointer.de/libcanberra">repository</a> (<a href="http://git.0pointer.de/?p=libcanberra.git">gitweb</a>): </p>
<pre>git clone git://git.0pointer.de/libcanberra</pre>
<p>If you want to report bugs, have questions or want to be notified about new releases, please join the <a href="https://tango.0pointer.de/mailman/listinfo/libcanberra-discuss/"><tt>libcanberra-discuss</tt></a> mailing list.</p>
<p>If you want to be notified about new git commits, please join the <a href="https://tango.0pointer.de/mailman/listinfo/libcanberra-commits/"><tt>libcanberra-commits</tt></a> mailing list.</p>
<p><tt>libcanberra</tt>'s bugs are tracked at <a href="http://bugs.freedesktop.org/buglist.cgi?bug_status=__open__&product=libcanberra">bugs.freedesktop.org</a>.</p>
<hr/>
<address class="grey">Lennart Poettering <@PACKAGE_BUGREPORT@>, September 2012</address>
</body>
</html>
0707010000000A000081A4000000000000000000000001509D8F37000003D3000000000000000000000000000000000000002100000000libcanberra-0.30+2/doc/style.css/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
body { color: black; background-color: white; }
a:link, a:visited { color: #900000; }
div.news-date { font-size: 80%; font-style: italic; }
pre { background-color: #f0f0f0; padding: 0.4cm; }
.grey { color: #8f8f8f; font-size: 80%; }
0707010000000B000041ED000000000000000000000002509D8F3700000000000000000000000000000000000000000000001A00000000libcanberra-0.30+2/gtkdoc0707010000000C000081A4000000000000000000000001509D8F370000013C000000000000000000000000000000000000002500000000libcanberra-0.30+2/gtkdoc/.gitignore/libcanberra-unused.txt
*.bak
/html
/xml
*.stamp
/libcanberra-decl-list.txt
/libcanberra-decl.txt
/libcanberra-overrides.txt
/libcanberra-undeclared.txt
/libcanberra-undocumented.txt
/libcanberra.args
/libcanberra.hierarchy
/libcanberra.interfaces
/libcanberra.prerequisites
/libcanberra.signals
/gtk-doc.make
/tmpl
0707010000000D000081A4000000000000000000000001509D8F3700000B58000000000000000000000000000000000000002600000000libcanberra-0.30+2/gtkdoc/Makefile.am## Process this file with automake to produce Makefile.in
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
# This is a blank Makefile.am for using gtk-doc.
# Copy this to your project's API docs directory and modify the variables to
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
# of using the various options.
# The name of the module, e.g. 'glib'.
DOC_MODULE=libcanberra
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# The directory containing the source code. Relative to $(srcdir).
# gtk-doc will search all .c & .h files beneath here for inline comments
# documenting the functions and macros.
# e.g. DOC_SOURCE_DIR=../../../gtk
DOC_SOURCE_DIR=../src
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
SCAN_OPTIONS=
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
MKDB_OPTIONS=--sgml-mode --output-format=xml
# Extra options to supply to gtkdoc-mktmpl
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
MKTMPL_OPTIONS=
# Extra options to supply to gtkdoc-fixref. Not normally needed.
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
FIXXREF_OPTIONS=
# Used for dependencies. The docs will be rebuilt if any of these change.
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB=
CFILE_GLOB=
# Header files to ignore when scanning.
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
IGNORE_HFILES=
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
content_files=
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
# signals and properties.
# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
INCLUDES=
GTKDOC_LIBS=
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtkdoc/gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST +=
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
#DISTCLEANFILES +=
# Comment this out if you want your docs-status tested during 'make check'
#TESTS = $(GTKDOC_CHECK)
0707010000000E000081A4000000000000000000000001509D8F37000002E2000000000000000000000000000000000000003000000000libcanberra-0.30+2/gtkdoc/libcanberra-docs.sgml<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
<bookinfo>
<title>libcanberra Reference Manual</title>
<releaseinfo>
The latest version of this documentation can be found on-line at
<ulink role="online-location" url="http://0pointer.de/lennart/projects/libcanberra/gtkdoc/index.html">http://0pointer.de/lennart/projects/libcanberra/gtkdoc/index.html</ulink>.
</releaseinfo>
</bookinfo>
<chapter>
<title>libcanberra</title>
<xi:include href="xml/canberra.xml"/>
<xi:include href="xml/canberra-gtk.xml"/>
</chapter>
</book>
0707010000000F000081A4000000000000000000000001509D8F3700000665000000000000000000000000000000000000003300000000libcanberra-0.30+2/gtkdoc/libcanberra-sections.txt<SECTION>
<FILE>canberra-gtk</FILE>
ca_gtk_context_get
ca_gtk_proplist_set_for_widget
ca_gtk_play_for_widget
ca_gtk_proplist_set_for_event
ca_gtk_play_for_event
ca_gtk_widget_disable_sounds
</SECTION>
<SECTION>
<FILE>canberra</FILE>
CA_PROP_MEDIA_NAME
CA_PROP_MEDIA_TITLE
CA_PROP_MEDIA_ARTIST
CA_PROP_MEDIA_LANGUAGE
CA_PROP_MEDIA_FILENAME
CA_PROP_MEDIA_ICON
CA_PROP_MEDIA_ICON_NAME
CA_PROP_MEDIA_ROLE
CA_PROP_EVENT_ID
CA_PROP_EVENT_DESCRIPTION
CA_PROP_EVENT_MOUSE_X
CA_PROP_EVENT_MOUSE_Y
CA_PROP_EVENT_MOUSE_HPOS
CA_PROP_EVENT_MOUSE_VPOS
CA_PROP_EVENT_MOUSE_BUTTON
CA_PROP_WINDOW_NAME
CA_PROP_WINDOW_ID
CA_PROP_WINDOW_ICON
CA_PROP_WINDOW_ICON_NAME
CA_PROP_WINDOW_X11_DISPLAY
CA_PROP_WINDOW_X11_SCREEN
CA_PROP_WINDOW_X11_MONITOR
CA_PROP_WINDOW_X11_XID
CA_PROP_APPLICATION_NAME
CA_PROP_APPLICATION_ID
CA_PROP_APPLICATION_VERSION
CA_PROP_APPLICATION_ICON
CA_PROP_APPLICATION_ICON_NAME
CA_PROP_APPLICATION_LANGUAGE
CA_PROP_APPLICATION_PROCESS_ID
CA_PROP_APPLICATION_PROCESS_BINARY
CA_PROP_APPLICATION_PROCESS_USER
CA_PROP_APPLICATION_PROCESS_HOST
CA_PROP_CANBERRA_CACHE_CONTROL
CA_PROP_CANBERRA_VOLUME
CA_PROP_CANBERRA_XDG_THEME_NAME
CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE
<SUBSECTION>
ca_context
ca_finish_callback_t
ca_context_create
ca_context_destroy
ca_context_open
ca_context_set_driver
ca_context_change_device
ca_context_change_props
ca_context_change_props_full
ca_context_play
ca_context_play_full
ca_context_cancel
ca_context_cache
ca_context_cache_full
ca_context_playing
<SUBSECTION>
ca_strerror
<SUBSECTION>
ca_proplist
ca_proplist_create
ca_proplist_destroy
ca_proplist_sets
ca_proplist_setf
ca_proplist_set
</SECTION>
07070100000010000081A4000000000000000000000001509D8F3700000000000000000000000000000000000000000000002C00000000libcanberra-0.30+2/gtkdoc/libcanberra.types07070100000011000081A4000000000000000000000001509D8F3700000123000000000000000000000000000000000000002900000000libcanberra-0.30+2/libcanberra-gtk.pc.inprefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
includedir=@includedir@
Name: libcanberra-gtk
Description: Gtk Event Sound API
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lcanberra-gtk -lX11 @PTHREAD_LIBS@
Cflags: -D_REENTRANT -I${includedir}
Requires: libcanberra gdk-2.0 gtk+-2.0
07070100000012000081A4000000000000000000000001509D8F3700000126000000000000000000000000000000000000002A00000000libcanberra-0.30+2/libcanberra-gtk3.pc.inprefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
includedir=@includedir@
Name: libcanberra-gtk3
Description: Gtk3 Event Sound API
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lcanberra-gtk3 -lX11 @PTHREAD_LIBS@
Cflags: -D_REENTRANT -I${includedir}
Requires: libcanberra gdk-3.0 gtk+-3.0
07070100000013000081A4000000000000000000000001509D8F37000000F4000000000000000000000000000000000000002500000000libcanberra-0.30+2/libcanberra.pc.inprefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
includedir=@includedir@
Name: libcanberra
Description: Event Sound API
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lcanberra @PTHREAD_LIBS@
Cflags: -D_REENTRANT -I${includedir}
Requires:
07070100000014000041ED000000000000000000000002509D8F3700000000000000000000000000000000000000000000001600000000libcanberra-0.30+2/m407070100000015000081A4000000000000000000000001509D8F3700000062000000000000000000000000000000000000002100000000libcanberra-0.30+2/m4/.gitignore/argz.m4
/gtk-doc.m4
/libtool.m4
/ltdl.m4
/ltoptions.m4
/ltsugar.m4
/ltversion.m4
/lt~obsolete.m4
07070100000016000081A4000000000000000000000001509D8F370000266E000000000000000000000000000000000000002400000000libcanberra-0.30+2/m4/attributes.m4dnl Macros to check the presence of generic (non-typed) symbols.
dnl Copyright (c) 2006-2008 Diego Pettenò <flameeyes@gmail.com>
dnl Copyright (c) 2006-2008 xine project
dnl Copyright (c) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2, or (at your option)
dnl any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
dnl 02110-1301, USA.
dnl
dnl As a special exception, the copyright owners of the
dnl macro gives unlimited permission to copy, distribute and modify the
dnl configure scripts that are the output of Autoconf when processing the
dnl Macro. You need not follow the terms of the GNU General Public
dnl License when using or distributing such scripts, even though portions
dnl of the text of the Macro appear in them. The GNU General Public
dnl License (GPL) does govern all other use of the material that
dnl constitutes the Autoconf Macro.
dnl
dnl This special exception to the GPL applies to versions of the
dnl Autoconf Macro released by this project. When you make and
dnl distribute a modified version of the Autoconf Macro, you may extend
dnl this special exception to the GPL to apply to your modified version as
dnl well.
dnl Check if FLAG in ENV-VAR is supported by compiler and append it
dnl to WHERE-TO-APPEND variable
dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG])
AC_DEFUN([CC_CHECK_FLAG_APPEND], [
AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2],
AS_TR_SH([cc_cv_$2_$3]),
[eval "AS_TR_SH([cc_save_$2])='${$2}'"
eval "AS_TR_SH([$2])='$3'"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a = 0; int main(void) { return a; } ])],
[eval "AS_TR_SH([cc_cv_$2_$3])='yes'"],
[eval "AS_TR_SH([cc_cv_$2_$3])='no'"])
eval "AS_TR_SH([$2])='$cc_save_$2'"])
AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes],
[eval "$1='${$1} $3'"])
])
dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2])
AC_DEFUN([CC_CHECK_FLAGS_APPEND], [
for flag in $3; do
CC_CHECK_FLAG_APPEND($1, $2, $flag)
done
])
dnl Check if the flag is supported by linker (cacheable)
dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
AC_DEFUN([CC_CHECK_LDFLAGS], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_ldflags_$1]),
[ac_save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $1"
AC_LINK_IFELSE([int main() { return 1; }],
[eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_ldflags_$1])="])
LDFLAGS="$ac_save_LDFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
[$2], [$3])
])
dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
dnl the current linker to avoid undefined references in a shared object.
AC_DEFUN([CC_NOUNDEFINED], [
dnl We check $host for which systems to enable this for.
AC_REQUIRE([AC_CANONICAL_HOST])
case $host in
dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
dnl are requested, as different implementations are present; to avoid problems
dnl use -Wl,-z,defs only for those platform not behaving this way.
*-freebsd* | *-openbsd*) ;;
*)
dnl First of all check for the --no-undefined variant of GNU ld. This allows
dnl for a much more readable commandline, so that people can understand what
dnl it does without going to look for what the heck -z defs does.
for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
break
done
;;
esac
AC_SUBST([LDFLAGS_NOUNDEFINED])
])
dnl Check for a -Werror flag or equivalent. -Werror is the GCC
dnl and ICC flag that tells the compiler to treat all the warnings
dnl as fatal. We usually need this option to make sure that some
dnl constructs (like attributes) are not simply ignored.
dnl
dnl Other compilers don't support -Werror per se, but they support
dnl an equivalent flag:
dnl - Sun Studio compiler supports -errwarn=%all
AC_DEFUN([CC_CHECK_WERROR], [
AC_CACHE_CHECK(
[for $CC way to treat warnings as errors],
[cc_cv_werror],
[CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
[CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
])
])
AC_DEFUN([CC_CHECK_ATTRIBUTE], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
AS_TR_SH([cc_cv_attribute_$1]),
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
[eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
[AC_DEFINE(
AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
[Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
)
$4],
[$5])
])
AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
CC_CHECK_ATTRIBUTE(
[constructor],,
[void __attribute__((constructor)) ctor() { int a; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
CC_CHECK_ATTRIBUTE(
[format], [format(printf, n, n)],
[void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
CC_CHECK_ATTRIBUTE(
[format_arg], [format_arg(printf)],
[char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
CC_CHECK_ATTRIBUTE(
[visibility_$1], [visibility("$1")],
[void __attribute__((visibility("$1"))) $1_function() { }],
[$2], [$3])
])
AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
CC_CHECK_ATTRIBUTE(
[nonnull], [nonnull()],
[void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
CC_CHECK_ATTRIBUTE(
[unused], ,
[void some_function(void *foo, __attribute__((unused)) void *bar);],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
CC_CHECK_ATTRIBUTE(
[sentinel], ,
[void some_function(void *foo, ...) __attribute__((sentinel));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
CC_CHECK_ATTRIBUTE(
[deprecated], ,
[void some_function(void *foo, ...) __attribute__((deprecated));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
CC_CHECK_ATTRIBUTE(
[alias], [weak, alias],
[void other_function(void *foo) { }
void some_function(void *foo) __attribute__((weak, alias("other_function")));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
CC_CHECK_ATTRIBUTE(
[malloc], ,
[void * __attribute__((malloc)) my_alloc(int n);],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_PACKED], [
CC_CHECK_ATTRIBUTE(
[packed], ,
[struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_CONST], [
CC_CHECK_ATTRIBUTE(
[const], ,
[int __attribute__((const)) twopow(int n) { return 1 << n; } ],
[$1], [$2])
])
AC_DEFUN([CC_FLAG_VISIBILITY], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
[cc_cv_flag_visibility],
[cc_flag_visibility_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
cc_cv_flag_visibility='yes',
cc_cv_flag_visibility='no')
CFLAGS="$cc_flag_visibility_save_CFLAGS"])
AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
[AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
[Define this if the compiler supports the -fvisibility flag])
$1],
[$2])
])
AC_DEFUN([CC_FUNC_EXPECT], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if compiler has __builtin_expect function],
[cc_cv_func_expect],
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[int some_function() {
int a = 3;
return (int)__builtin_expect(a, 3);
}])],
[cc_cv_func_expect=yes],
[cc_cv_func_expect=no])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([test "x$cc_cv_func_expect" = "xyes"],
[AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
[Define this if the compiler supports __builtin_expect() function])
$1],
[$2])
])
AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
[cc_cv_attribute_aligned],
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
for cc_attribute_align_try in 64 32 16 8 4 2; do
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
int main() {
static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
return c;
}])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
done
CFLAGS="$ac_save_CFLAGS"
])
if test "x$cc_cv_attribute_aligned" != "x"; then
AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
[Define the highest alignment supported])
fi
])
07070100000017000041ED000000000000000000000002509D8F3700000000000000000000000000000000000000000000001700000000libcanberra-0.30+2/src07070100000018000081A4000000000000000000000001509D8F37000000B6000000000000000000000000000000000000002200000000libcanberra-0.30+2/src/.gitignore/canberra-boot
/libcanberra-login-sound.desktop
/libcanberra-ready-sound.desktop
/libcanberra-logout-sound.sh
/canberra-gtk-play
.libs
*.o
*.lo
.deps
*.la
/test-canberra
/canberra.h
07070100000019000081A4000000000000000000000001509D8F37000027F3000000000000000000000000000000000000002300000000libcanberra-0.30+2/src/Makefile.am# This file is part of libcanberra.
#
# Copyright 2008 Lennart Poettering
#
# libcanberra 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.
#
# libcanberra 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 libcanberra. If not, see
# <http://www.gnu.org/licenses/>.
gtkmoduledir = @GTK_MODULES_DIR@
gtk3moduledir = @GTK3_MODULES_DIR@
plugindir = $(libdir)/libcanberra-@PACKAGE_VERSION@
gnomeshutdowndir = $(datadir)/gnome/shutdown
gnomeautostartdir = $(datadir)/gnome/autostart
gdmautostartdir = $(datadir)/gdm/autostart/LoginWindow
gsdgtkmodulesdir = $(libdir)/gnome-settings-daemon-3.0/gtk-modules
AM_CFLAGS = $(WARNINGFLAGS) $(PTHREAD_CFLAGS) -DCA_PLUGIN_PATH=\"$(plugindir)\"
#AM_CFLAGS = $(WARNINGFLAGS) $(PTHREAD_CFLAGS) -DCA_PLUGIN_PATH=\"/home/lennart/projects/libcanberra/src/.libs\"
AM_CXXFLAGS = $(WARNINGFLAGS) $(PTHREAD_CFLAGS)
AM_LDADD = $(PTHREAD_LIBS)
AM_LDFLAGS = $(GCLDFLAGS)
EXTRA_DIST = \
map-file
lib_LTLIBRARIES = \
libcanberra.la
include_HEADERS = \
canberra.h
noinst_PROGRAMS = \
test-canberra
libcanberra_la_SOURCES = \
canberra.h \
common.c common.h \
mutex-posix.c mutex.h \
proplist.c proplist.h \
driver.h \
read-sound-file.c read-sound-file.h \
read-vorbis.c read-vorbis.h \
read-wav.c read-wav.h \
sound-theme-spec.c sound-theme-spec.h \
llist.h \
macro.h macro.c \
malloc.c malloc.h \
fork-detect.c fork-detect.h
libcanberra_la_CFLAGS = \
$(AM_CFLAGS) \
$(VORBIS_CFLAGS)
libcanberra_la_LIBADD = \
$(VORBIS_LIBS)
libcanberra_la_LDFLAGS = \
-export-dynamic \
-version-info $(LIBCANBERRA_VERSION_INFO)
if USE_VERSION_SCRIPT
libcanberra_la_LDFLAGS += -Wl,-version-script=$(srcdir)/map-file
endif
if HAVE_CACHE
libcanberra_la_SOURCES += \
cache.c cache.h
libcanberra_la_CFLAGS += \
$(TDB_CLFAGS) \
-DCA_MACHINE_ID=\"$(localstatedir)/lib/dbus/machine-id\"
libcanberra_la_LIBADD += \
$(TDB_LIBS)
endif
plugin_LTLIBRARIES =
if BUILTIN_DSO
libcanberra_la_SOURCES += \
dso.c \
driver-order.c driver-order.h
libcanberra_la_LIBADD += \
$(LIBLTDL)
plugin_LTLIBRARIES += \
libcanberra-multi.la
libcanberra_multi_la_SOURCES = \
multi.c
libcanberra_multi_la_CFLAGS = \
-Ddriver_open=multi_driver_open \
-Ddriver_destroy=multi_driver_destroy \
-Ddriver_change_device=multi_driver_change_device \
-Ddriver_change_props=multi_driver_change_props \
-Ddriver_play=multi_driver_play \
-Ddriver_cancel=multi_driver_cancel \
-Ddriver_cache=multi_driver_cache
libcanberra_multi_la_LIBADD = \
libcanberra.la
libcanberra_multi_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
if HAVE_PULSE
if BUILTIN_PULSE
libcanberra_la_SOURCES += \
pulse.c
libcanberra_la_CFLAGS += \
$(PULSE_CFLAGS)
libcanberra_la_LIBADD += \
$(PULSE_LIBS)
else
plugin_LTLIBRARIES += \
libcanberra-pulse.la
libcanberra_pulse_la_SOURCES = \
pulse.c
libcanberra_pulse_la_CFLAGS = \
$(PULSE_CFLAGS) \
-Ddriver_open=pulse_driver_open \
-Ddriver_destroy=pulse_driver_destroy \
-Ddriver_change_device=pulse_driver_change_device \
-Ddriver_change_props=pulse_driver_change_props \
-Ddriver_play=pulse_driver_play \
-Ddriver_cancel=pulse_driver_cancel \
-Ddriver_cache=pulse_driver_cache
libcanberra_pulse_la_LIBADD = \
$(PULSE_LIBS) \
libcanberra.la
libcanberra_pulse_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
endif
if HAVE_ALSA
if BUILTIN_ALSA
libcanberra_la_SOURCES += \
alsa.c
libcanberra_la_CFLAGS += \
$(ALSA_CFLAGS)
libcanberra_la_LIBADD += \
$(ALSA_LIBS)
else
plugin_LTLIBRARIES += \
libcanberra-alsa.la
libcanberra_alsa_la_SOURCES = \
alsa.c
libcanberra_alsa_la_CFLAGS = \
$(ALSA_CFLAGS) \
-Ddriver_open=alsa_driver_open \
-Ddriver_destroy=alsa_driver_destroy \
-Ddriver_change_device=alsa_driver_change_device \
-Ddriver_change_props=alsa_driver_change_props \
-Ddriver_play=alsa_driver_play \
-Ddriver_cancel=alsa_driver_cancel \
-Ddriver_cache=alsa_driver_cache
libcanberra_alsa_la_LIBADD = \
$(ALSA_LIBS) \
libcanberra.la
libcanberra_alsa_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
endif
if HAVE_OSS
if BUILTIN_OSS
libcanberra_la_SOURCES += \
oss.c
else
plugin_LTLIBRARIES += \
libcanberra-oss.la
libcanberra_oss_la_SOURCES = \
oss.c
libcanberra_oss_la_CFLAGS = \
-Ddriver_open=oss_driver_open \
-Ddriver_destroy=oss_driver_destroy \
-Ddriver_change_device=oss_driver_change_device \
-Ddriver_change_props=oss_driver_change_props \
-Ddriver_play=oss_driver_play \
-Ddriver_cancel=oss_driver_cancel \
-Ddriver_cache=oss_driver_cache
libcanberra_oss_la_LIBADD = \
libcanberra.la
libcanberra_oss_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
endif
if HAVE_GSTREAMER
if BUILTIN_GSTREAMER
libcanberra_la_SOURCES += \
gstreamer.c
libcanberra_la_CFLAGS += \
$(GST_CFLAGS)
libcanberra_la_LIBADD += \
$(GST_LIBS)
else
plugin_LTLIBRARIES += \
libcanberra-gstreamer.la
libcanberra_gstreamer_la_SOURCES = \
gstreamer.c
libcanberra_gstreamer_la_CFLAGS = \
$(GST_CFLAGS) \
-Ddriver_open=gstreamer_driver_open \
-Ddriver_destroy=gstreamer_driver_destroy \
-Ddriver_change_device=gstreamer_driver_change_device \
-Ddriver_change_props=gstreamer_driver_change_props \
-Ddriver_play=gstreamer_driver_play \
-Ddriver_cancel=gstreamer_driver_cancel \
-Ddriver_cache=gstreamer_driver_cache
libcanberra_gstreamer_la_LIBADD = \
$(GST_LIBS) \
libcanberra.la
libcanberra_gstreamer_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
endif
if HAVE_NULL
if BUILTIN_NULL
libcanberra_la_SOURCES += \
null.c
else
plugin_LTLIBRARIES += \
libcanberra-null.la
libcanberra_null_la_SOURCES = \
null.c
libcanberra_null_la_CFLAGS = \
-Ddriver_open=null_driver_open \
-Ddriver_destroy=null_driver_destroy \
-Ddriver_change_device=null_driver_change_device \
-Ddriver_change_props=null_driver_change_props \
-Ddriver_play=null_driver_play \
-Ddriver_cancel=null_driver_cancel \
-Ddriver_cache=null_driver_cache
libcanberra_null_la_LIBADD = \
libcanberra.la
libcanberra_null_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
endif
bin_PROGRAMS =
CLEANFILES =
if HAVE_UDEV
if HAVE_ALSA
bin_PROGRAMS += \
canberra-boot
canberra_boot_SOURCES = \
canberra-boot.c
canberra_boot_LDADD = \
$(UDEV_LIBS) \
libcanberra.la
canberra_boot_CFLAGS = \
$(UDEV_CFLAGS)
if HAVE_SYSTEMD
systemdsystemunit_DATA = \
canberra-system-bootup.service \
canberra-system-shutdown.service \
canberra-system-shutdown-reboot.service
EXTRA_DIST += \
canberra-system-bootup.service.in \
canberra-system-shutdown.service.in \
canberra-system-shutdown-reboot.service.in
%.service: %.service.in
$(AM_V_GEN)sed -e 's,@bindir\@,$(bindir),g' $< > $@
CLEANFILES += \
$(systemdsystemunit_DATA)
endif
endif
endif
if HAVE_GTK_ANY
bin_PROGRAMS += \
canberra-gtk-play
include_HEADERS += \
canberra-gtk.h
endif
if HAVE_GTK3
lib_LTLIBRARIES += \
libcanberra-gtk3.la
gtk3module_LTLIBRARIES = \
libcanberra-gtk3-module.la
libcanberra_gtk3_la_SOURCES = \
canberra-gtk.h \
canberra-gtk.c
libcanberra_gtk3_la_CFLAGS = \
$(GTK3_CFLAGS)
libcanberra_gtk3_la_LIBADD = \
$(GTK3_LIBS) \
libcanberra.la
libcanberra_gtk3_la_LDFLAGS = \
-export-dynamic -version-info $(LIBCANBERRA_GTK_VERSION_INFO)
libcanberra_gtk3_module_la_SOURCES = \
canberra-gtk-module.c
libcanberra_gtk3_module_la_CFLAGS = \
$(GTK3_CFLAGS)
libcanberra_gtk3_module_la_LIBADD = \
$(GTK3_LIBS) \
libcanberra.la \
libcanberra-gtk3.la
libcanberra_gtk3_module_la_LDFLAGS = \
-avoid-version -module -export-dynamic
install-exec-hook:
$(MKDIR_P) -m 755 $(DESTDIR)$(gtk3moduledir)
( cd $(DESTDIR)$(gtk3moduledir) && \
rm -f libcanberra-gtk-module.so && \
$(LN_S) libcanberra-gtk3-module.so libcanberra-gtk-module.so )
endif
if HAVE_GTK
lib_LTLIBRARIES += \
libcanberra-gtk.la
gtkmodule_LTLIBRARIES = \
libcanberra-gtk-module.la
libcanberra_gtk_la_SOURCES = \
canberra-gtk.h \
canberra-gtk.c
libcanberra_gtk_la_CFLAGS = \
$(GTK_CFLAGS)
libcanberra_gtk_la_LIBADD = \
$(GTK_LIBS) \
libcanberra.la
libcanberra_gtk_la_LDFLAGS = \
-export-dynamic -version-info $(LIBCANBERRA_GTK_VERSION_INFO)
libcanberra_gtk_module_la_SOURCES = \
canberra-gtk-module.c
libcanberra_gtk_module_la_CFLAGS = \
$(GTK_CFLAGS)
libcanberra_gtk_module_la_LIBADD = \
$(GTK_LIBS) \
libcanberra.la \
libcanberra-gtk.la
libcanberra_gtk_module_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
if HAVE_GTK3
canberra_gtk_play_LDADD = \
$(GTK3_LIBS) \
libcanberra.la \
libcanberra-gtk3.la
canberra_gtk_play_CFLAGS = \
$(GTK3_CFLAGS)
else
if HAVE_GTK
canberra_gtk_play_LDADD = \
$(GTK_LIBS) \
libcanberra.la \
libcanberra-gtk.la
canberra_gtk_play_CFLAGS = \
$(GTK_CFLAGS)
endif
endif
if HAVE_GTK_ANY
dist_gsdgtkmodules_DATA = \
canberra-gtk-module.desktop
canberra_gtk_play_SOURCES = \
canberra-gtk-play.c
EXTRA_DIST += \
libcanberra-login-sound.desktop.in \
libcanberra-ready-sound.desktop.in \
libcanberra-logout-sound.sh.in
gnomeautostart_DATA = \
libcanberra-login-sound.desktop
gdmautostart_DATA = \
libcanberra-ready-sound.desktop
gnomeshutdown_SCRIPTS = \
libcanberra-logout-sound.sh
CLEANFILES += \
libcanberra-login-sound.desktop \
libcanberra-ready-sound.desktop \
libcanberra-logout-sound.sh
libcanberra-logout-sound.sh: libcanberra-logout-sound.sh.in Makefile
$(AM_V_GEN)sed -e 's,@bindir\@,$(bindir),g' < $< > $@ && \
chmod +x $@
libcanberra-login-sound.desktop: libcanberra-login-sound.desktop.in Makefile
$(AM_V_GEN)sed -e 's,@bindir\@,$(bindir),g' < $< > $@
libcanberra-ready-sound.desktop: libcanberra-ready-sound.desktop.in Makefile
$(AM_V_GEN)sed -e 's,@bindir\@,$(bindir),g' < $< > $@
endif
test_canberra_SOURCES = \
test-canberra.c
test_canberra_LDADD = \
$(AM_LDADD) \
libcanberra.la
0707010000001A000081A4000000000000000000000001509D8F3700003ED9000000000000000000000000000000000000001E00000000libcanberra-0.30+2/src/alsa.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <alsa/asoundlib.h>
#include "canberra.h"
#include "common.h"
#include "driver.h"
#include "llist.h"
#include "read-sound-file.h"
#include "sound-theme-spec.h"
#include "malloc.h"
struct private;
struct outstanding {
CA_LLIST_FIELDS(struct outstanding);
ca_bool_t dead;
uint32_t id;
ca_finish_callback_t callback;
void *userdata;
ca_sound_file *file;
snd_pcm_t *pcm;
int pipe_fd[2];
ca_context *context;
};
struct private {
ca_theme_data *theme;
ca_mutex *outstanding_mutex;
ca_bool_t signal_semaphore;
sem_t semaphore;
ca_bool_t semaphore_allocated;
CA_LLIST_HEAD(struct outstanding, outstanding);
};
#define PRIVATE(c) ((struct private *) ((c)->private))
static void outstanding_free(struct outstanding *o) {
ca_assert(o);
if (o->pipe_fd[1] >= 0)
close(o->pipe_fd[1]);
if (o->pipe_fd[0] >= 0)
close(o->pipe_fd[0]);
if (o->file)
ca_sound_file_close(o->file);
if (o->pcm)
snd_pcm_close(o->pcm);
ca_free(o);
}
int driver_open(ca_context *c) {
struct private *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "alsa"), CA_ERROR_NODRIVER);
ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE);
if (!(c->private = p = ca_new0(struct private, 1)))
return CA_ERROR_OOM;
if (!(p->outstanding_mutex = ca_mutex_new())) {
driver_destroy(c);
return CA_ERROR_OOM;
}
if (sem_init(&p->semaphore, 0, 0) < 0) {
driver_destroy(c);
return CA_ERROR_OOM;
}
p->semaphore_allocated = TRUE;
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
if (p->outstanding_mutex) {
ca_mutex_lock(p->outstanding_mutex);
/* Tell all player threads to terminate */
for (out = p->outstanding; out; out = out->next) {
if (out->dead)
continue;
out->dead = TRUE;
if (out->callback)
out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata);
/* This will cause the thread to wakeup and terminate */
if (out->pipe_fd[1] >= 0) {
close(out->pipe_fd[1]);
out->pipe_fd[1] = -1;
}
}
if (p->semaphore_allocated) {
/* Now wait until all players are destroyed */
p->signal_semaphore = TRUE;
while (p->outstanding) {
ca_mutex_unlock(p->outstanding_mutex);
sem_wait(&p->semaphore);
ca_mutex_lock(p->outstanding_mutex);
}
}
ca_mutex_unlock(p->outstanding_mutex);
ca_mutex_free(p->outstanding_mutex);
}
if (p->theme)
ca_theme_data_free(p->theme);
if (p->semaphore_allocated)
sem_destroy(&p->semaphore);
ca_free(p);
c->private = NULL;
snd_config_update_free_global();
return CA_SUCCESS;
}
int driver_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
return CA_SUCCESS;
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(changed, CA_ERROR_INVALID);
ca_return_val_if_fail(merged, CA_ERROR_INVALID);
return CA_SUCCESS;
}
int driver_cache(ca_context *c, ca_proplist *proplist) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
return CA_ERROR_NOTSUPPORTED;
}
static int translate_error(int error) {
switch (error) {
case -ENODEV:
case -ENOENT:
return CA_ERROR_NOTFOUND;
case -EACCES:
case -EPERM:
return CA_ERROR_ACCESS;
case -ENOMEM:
return CA_ERROR_OOM;
case -EBUSY:
return CA_ERROR_NOTAVAILABLE;
case -EINVAL:
return CA_ERROR_INVALID;
case -ENOSYS:
return CA_ERROR_NOTSUPPORTED;
default:
if (ca_debug())
fprintf(stderr, "Got unhandled error from ALSA: %s\n", snd_strerror(error));
return CA_ERROR_IO;
}
}
static const snd_pcm_format_t sample_type_table[] = {
#ifdef WORDS_BIGENDIAN
[CA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_BE,
[CA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_LE,
#else
[CA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_LE,
[CA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_BE,
#endif
[CA_SAMPLE_U8] = SND_PCM_FORMAT_U8
};
static int open_alsa(ca_context *c, struct outstanding *out) {
int ret;
snd_pcm_hw_params_t *hwparams;
unsigned rate;
snd_pcm_hw_params_alloca(&hwparams);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
ca_return_val_if_fail(out, CA_ERROR_INVALID);
/* In ALSA we need to open different devices for doing
* multichannel audio. This cnnot be done in a backend-independant
* wa, hence we limit ourselves to mono/stereo only. */
ca_return_val_if_fail(ca_sound_file_get_nchannels(out->file) <= 2, CA_ERROR_NOTSUPPORTED);
if ((ret = snd_pcm_open(&out->pcm, c->device ? c->device : "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
goto finish;
if ((ret = snd_pcm_hw_params_any(out->pcm, hwparams)) < 0)
goto finish;
if ((ret = snd_pcm_hw_params_set_access(out->pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
goto finish;
if ((ret = snd_pcm_hw_params_set_format(out->pcm, hwparams, sample_type_table[ca_sound_file_get_sample_type(out->file)])) < 0)
goto finish;
rate = ca_sound_file_get_rate(out->file);
if ((ret = snd_pcm_hw_params_set_rate_near(out->pcm, hwparams, &rate, 0)) < 0)
goto finish;
if ((ret = snd_pcm_hw_params_set_channels(out->pcm, hwparams, ca_sound_file_get_nchannels(out->file))) < 0)
goto finish;
if ((ret = snd_pcm_hw_params(out->pcm, hwparams)) < 0)
goto finish;
if ((ret = snd_pcm_prepare(out->pcm)) < 0)
goto finish;
return CA_SUCCESS;
finish:
return translate_error(ret);
}
#define BUFSIZE (16*1024)
static void* thread_func(void *userdata) {
struct outstanding *out = userdata;
int ret;
void *data, *d = NULL;
size_t fs, data_size;
size_t nbytes = 0;
struct pollfd *pfd = NULL;
nfds_t n_pfd;
struct private *p;
p = PRIVATE(out->context);
pthread_detach(pthread_self());
fs = ca_sound_file_frame_size(out->file);
data_size = (BUFSIZE/fs)*fs;
if (!(data = ca_malloc(data_size))) {
ret = CA_ERROR_OOM;
goto finish;
}
if ((ret = snd_pcm_poll_descriptors_count(out->pcm)) < 0) {
ret = translate_error(ret);
goto finish;
}
n_pfd = (nfds_t) ret + 1;
if (!(pfd = ca_new(struct pollfd, n_pfd))) {
ret = CA_ERROR_OOM;
goto finish;
}
if ((ret = snd_pcm_poll_descriptors(out->pcm, pfd+1, (unsigned) n_pfd-1)) < 0) {
ret = translate_error(ret);
goto finish;
}
pfd[0].fd = out->pipe_fd[0];
pfd[0].events = POLLIN;
pfd[0].revents = 0;
for (;;) {
unsigned short revents;
snd_pcm_sframes_t sframes;
if (out->dead)
break;
if (poll(pfd, n_pfd, -1) < 0) {
ret = CA_ERROR_SYSTEM;
goto finish;
}
/* We have been asked to shut down */
if (pfd[0].revents)
break;
if ((ret = snd_pcm_poll_descriptors_revents(out->pcm, pfd+1, (unsigned) n_pfd-1, &revents)) < 0) {
ret = translate_error(ret);
goto finish;
}
if (revents != POLLOUT) {
switch (snd_pcm_state(out->pcm)) {
case SND_PCM_STATE_XRUN:
if ((ret = snd_pcm_recover(out->pcm, -EPIPE, 1)) != 0) {
ret = translate_error(ret);
goto finish;
}
break;
case SND_PCM_STATE_SUSPENDED:
if ((ret = snd_pcm_recover(out->pcm, -ESTRPIPE, 1)) != 0) {
ret = translate_error(ret);
goto finish;
}
break;
default:
snd_pcm_drop(out->pcm);
if ((ret = snd_pcm_prepare(out->pcm)) < 0) {
ret = translate_error(ret);
goto finish;
}
break;
}
continue;
}
if (nbytes <= 0) {
nbytes = data_size;
if ((ret = ca_sound_file_read_arbitrary(out->file, data, &nbytes)) < 0)
goto finish;
d = data;
}
if (nbytes <= 0) {
snd_pcm_drain(out->pcm);
break;
}
if ((sframes = snd_pcm_writei(out->pcm, d, nbytes/fs)) < 0) {
if ((ret = snd_pcm_recover(out->pcm, (int) sframes, 1)) < 0) {
ret = translate_error(ret);
goto finish;
}
continue;
}
nbytes -= (size_t) sframes*fs;
d = (uint8_t*) d + (size_t) sframes*fs;
}
ret = CA_SUCCESS;
finish:
ca_free(data);
ca_free(pfd);
if (!out->dead)
if (out->callback)
out->callback(out->context, out->id, ret, out->userdata);
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
if (!p->outstanding && p->signal_semaphore)
sem_post(&p->semaphore);
outstanding_free(out);
ca_mutex_unlock(p->outstanding_mutex);
return NULL;
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
struct private *p;
struct outstanding *out = NULL;
int ret;
pthread_t thread;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
if (!(out = ca_new0(struct outstanding, 1))) {
ret = CA_ERROR_OOM;
goto finish;
}
out->context = c;
out->id = id;
out->callback = cb;
out->userdata = userdata;
out->pipe_fd[0] = out->pipe_fd[1] = -1;
if (pipe(out->pipe_fd) < 0) {
ret = CA_ERROR_SYSTEM;
goto finish;
}
if ((ret = ca_lookup_sound(&out->file, NULL, &p->theme, c->props, proplist)) < 0)
goto finish;
if ((ret = open_alsa(c, out)) < 0)
goto finish;
/* OK, we're ready to go, so let's add this to our list */
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (pthread_create(&thread, NULL, thread_func, out) < 0) {
ret = CA_ERROR_OOM;
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
goto finish;
}
ret = CA_SUCCESS;
finish:
/* We keep the outstanding struct around if we need clean up later to */
if (ret != CA_SUCCESS)
outstanding_free(out);
return ret;
}
int driver_cancel(ca_context *c, uint32_t id) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = out->next) {
if (out->id != id)
continue;
if (out->dead)
continue;
out->dead = TRUE;
if (out->callback)
out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
/* This will cause the thread to wakeup and terminate */
if (out->pipe_fd[1] >= 0) {
close(out->pipe_fd[1]);
out->pipe_fd[1] = -1;
}
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
}
int driver_playing(ca_context *c, uint32_t id, int *playing) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
p = PRIVATE(c);
*playing = 0;
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = out->next) {
if (out->dead ||
out->id != id)
continue;
*playing = 1;
break;
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
}
0707010000001B000081A4000000000000000000000001509D8F37000038DA000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/cache.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <tdb.h>
#include "malloc.h"
#include "macro.h"
#include "mutex.h"
#include "canberra.h"
#include "sound-theme-spec.h"
#include "cache.h"
#define FILENAME "event-sound-cache.tdb"
#define UPDATE_INTERVAL 10
/* This part is not portable due to pthread_once usage, should be abstracted
* when we port this to platforms that do not have POSIX threading */
static ca_mutex *mutex = NULL;
static struct tdb_context *database = NULL;
static void allocate_mutex_once(void) {
mutex = ca_mutex_new();
}
static int allocate_mutex(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
if (pthread_once(&once, allocate_mutex_once) != 0)
return CA_ERROR_OOM;
if (!mutex)
return CA_ERROR_OOM;
return 0;
}
static int get_cache_home(char **e) {
const char *env, *subdir;
char *r;
ca_return_val_if_fail(e, CA_ERROR_INVALID);
if ((env = getenv("XDG_CACHE_HOME")) && *env == '/')
subdir = "";
else if ((env = getenv("HOME")) && *env == '/')
subdir = "/.cache";
else {
*e = NULL;
return CA_SUCCESS;
}
if (!(r = ca_new(char, strlen(env) + strlen(subdir) + 1)))
return CA_ERROR_OOM;
sprintf(r, "%s%s", env, subdir);
*e = r;
return CA_SUCCESS;
}
static int sensible_gethostbyname(char *n, size_t l) {
if (gethostname(n, l) < 0)
return -1;
n[l-1] = 0;
if (strlen(n) >= l-1) {
errno = ENAMETOOLONG;
return -1;
}
if (!n[0]) {
errno = ENOENT;
return -1;
}
return 0;
}
static int get_machine_id(char **id) {
FILE *f;
size_t l;
ca_return_val_if_fail(id, CA_ERROR_INVALID);
/* First we try the D-Bus machine id */
if ((f = fopen(CA_MACHINE_ID, "r"))) {
char ln[34] = "", *r;
r = fgets(ln, sizeof(ln)-1, f);
fclose(f);
if (r) {
ln[strcspn(ln, " \n\r\t")] = 0;
if (!(*id = ca_strdup(ln)))
return CA_ERROR_OOM;
return CA_SUCCESS;
}
}
/* Then we try the host name */
l = 100;
for (;;) {
if (!(*id = ca_new(char, l)))
return CA_ERROR_OOM;
if (sensible_gethostbyname(*id, l) >= 0)
return CA_SUCCESS;
ca_free(*id);
if (errno != EINVAL && errno != ENAMETOOLONG)
break;
l *= 2;
}
/* Then we use the POSIX host id */
*id = ca_sprintf_malloc("%08lx", (unsigned long) gethostid());
return CA_SUCCESS;
}
static int db_open(void) {
int ret;
char *c, *id, *pn;
if ((ret = allocate_mutex()) < 0)
return ret;
ca_mutex_lock(mutex);
if (database) {
ret = CA_SUCCESS;
goto finish;
}
if ((ret = get_cache_home(&c)) < 0)
goto finish;
if (!c) {
ret = CA_ERROR_NOTFOUND;
goto finish;
}
/* Try to create, just in case it doesn't exist yet. We don't do
* this recursively however. */
mkdir(c, 0755);
if ((ret = get_machine_id(&id)) < 0) {
ca_free(c);
goto finish;
}
/* This data is machine specific, hence we include some kind of
* stable machine id here in the name. Also, we don't want to care
* abouth endianess/packing issues, hence we include the compiler
* target in the name, too. */
pn = ca_sprintf_malloc("%s/" FILENAME ".%s." CANONICAL_HOST, c, id);
ca_free(c);
ca_free(id);
if (!pn) {
ret = CA_ERROR_OOM;
goto finish;
}
/* We pass TDB_NOMMAP here as long as rhbz 460851 is not fixed in
* tdb. */
database = tdb_open(pn, 0, TDB_NOMMAP, O_RDWR|O_CREAT|O_NOCTTY
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
, 0644);
ca_free(pn);
if (!database) {
ret = CA_ERROR_CORRUPT;
goto finish;
}
ret = CA_SUCCESS;
finish:
ca_mutex_unlock(mutex);
return ret;
}
#ifdef CA_GCC_DESTRUCTOR
static void db_close(void) CA_GCC_DESTRUCTOR;
static void db_close(void) {
/* Only here to make this valgrind clean */
if (!getenv("VALGRIND"))
return;
if (mutex) {
ca_mutex_free(mutex);
mutex = NULL;
}
if (database) {
tdb_close(database);
database = NULL;
}
}
#endif
static int db_lookup(const void *key, size_t klen, void **data, size_t *dlen) {
int ret;
TDB_DATA k, d;
ca_return_val_if_fail(key, CA_ERROR_INVALID);
ca_return_val_if_fail(klen > 0, CA_ERROR_INVALID);
ca_return_val_if_fail(data, CA_ERROR_INVALID);
ca_return_val_if_fail(dlen, CA_ERROR_INVALID);
if ((ret = db_open()) < 0)
return ret;
k.dptr = (void*) key;
k.dsize = klen;
ca_mutex_lock(mutex);
ca_assert(database);
d = tdb_fetch(database, k);
if (!d.dptr) {
ret = CA_ERROR_NOTFOUND;
goto finish;
}
*data = d.dptr;
*dlen = d.dsize;
finish:
ca_mutex_unlock(mutex);
return ret;
}
static int db_store(const void *key, size_t klen, const void *data, size_t dlen) {
int ret;
TDB_DATA k, d;
ca_return_val_if_fail(key, CA_ERROR_INVALID);
ca_return_val_if_fail(klen > 0, CA_ERROR_INVALID);
ca_return_val_if_fail(data || dlen == 0, CA_ERROR_INVALID);
if ((ret = db_open()) < 0)
return ret;
k.dptr = (void*) key;
k.dsize = klen;
d.dptr = (void*) data;
d.dsize = dlen;
ca_mutex_lock(mutex);
ca_assert(database);
if (tdb_store(database, k, d, TDB_REPLACE) < 0) {
ret = CA_ERROR_CORRUPT;
goto finish;
}
ret = CA_SUCCESS;
finish:
ca_mutex_unlock(mutex);
return ret;
}
static int db_remove(const void *key, size_t klen) {
int ret;
TDB_DATA k;
ca_return_val_if_fail(key, CA_ERROR_INVALID);
ca_return_val_if_fail(klen > 0, CA_ERROR_INVALID);
if ((ret = db_open()) < 0)
return ret;
k.dptr = (void*) key;
k.dsize = klen;
ca_mutex_lock(mutex);
ca_assert(database);
if (tdb_delete(database, k) < 0) {
ret = CA_ERROR_CORRUPT;
goto finish;
}
ret = CA_SUCCESS;
finish:
ca_mutex_unlock(mutex);
return ret;
}
static char *build_key(
const char *theme,
const char *name,
const char *locale,
const char *profile,
size_t *klen) {
char *key, *k;
size_t tl, nl, ll, pl;
tl = strlen(theme);
nl = strlen(name);
ll = strlen(locale);
pl = strlen(profile);
*klen = tl+1+nl+1+ll+1+pl+1;
if (!(key = ca_new(char, *klen)))
return NULL;
k = key;
strcpy(k, theme);
k += tl+1;
strcpy(k, name);
k += nl+1;
strcpy(k, locale);
k += ll+1;
strcpy(k, profile);
return key;
}
static int get_last_change(time_t *t) {
int ret;
char *e, *k;
struct stat st;
static time_t last_check = 0, last_change = 0;
time_t now;
const char *g;
ca_return_val_if_fail(t, CA_ERROR_INVALID);
if ((ret = allocate_mutex()) < 0)
return ret;
ca_mutex_lock(mutex);
ca_assert_se(time(&now) != (time_t) -1);
if (now < last_check + UPDATE_INTERVAL) {
*t = last_change;
ret = CA_SUCCESS;
goto finish;
}
if ((ret = ca_get_data_home(&e)) < 0)
goto finish;
*t = 0;
if (e) {
if (!(k = ca_new(char, strlen(e) + sizeof("/sounds")))) {
ca_free(e);
ret = CA_ERROR_OOM;
goto finish;
}
sprintf(k, "%s/sounds", e);
ca_free(e);
if (stat(k, &st) >= 0)
*t = st.st_mtime;
ca_free(k);
}
g = ca_get_data_dirs();
for (;;) {
size_t j = strcspn(g, ":");
if (g[0] == '/' && j > 0) {
if (!(k = ca_new(char, j + sizeof("/sounds")))) {
ret = CA_ERROR_OOM;
goto finish;
}
memcpy(k, g, j);
strcpy(k+j, "/sounds");
if (stat(k, &st) >= 0)
if (st.st_mtime >= *t)
*t = st.st_mtime;
ca_free(k);
}
if (g[j] == 0)
break;
g += j+1;
}
last_change = *t;
last_check = now;
ret = 0;
finish:
ca_mutex_unlock(mutex);
return ret;
}
int ca_cache_lookup_sound(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme,
const char *name,
const char *locale,
const char *profile) {
char *key = NULL;
void *data = NULL;
size_t klen, dlen;
int ret;
uint32_t timestamp;
time_t last_change, now;
ca_bool_t remove_entry = FALSE;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(theme, CA_ERROR_INVALID);
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
ca_return_val_if_fail(locale, CA_ERROR_INVALID);
ca_return_val_if_fail(profile, CA_ERROR_INVALID);
if (sound_path)
*sound_path = NULL;
if (!(key = build_key(theme, name, locale, profile, &klen)))
return CA_ERROR_OOM;
ret = db_lookup(key, klen, &data, &dlen);
if (ret < 0)
goto finish;
ca_assert(data);
if (dlen < sizeof(uint32_t) ||
(dlen > sizeof(uint32_t) && ((char*) data)[dlen-1] != 0)) {
/* Corrupt entry */
ret = CA_ERROR_NOTFOUND;
remove_entry = TRUE;
goto finish;
}
memcpy(×tamp, data, sizeof(timestamp));
if ((ret = get_last_change(&last_change)) < 0)
goto finish;
ca_assert_se(time(&now) != (time_t) -1);
/* Hmm, is the entry older than the last change to our sound theme
* dirs? Also, check for clock skews */
if ((time_t) timestamp < last_change || ((time_t) timestamp > now)) {
remove_entry = TRUE;
ret = CA_ERROR_NOTFOUND;
goto finish;
}
if (dlen <= sizeof(uint32_t)) {
/* Negative caching entry. */
*f = NULL;
ret = CA_SUCCESS;
goto finish;
}
if (sound_path) {
if (!(*sound_path = ca_strdup((const char*) data + sizeof(uint32_t)))) {
ret = CA_ERROR_OOM;
goto finish;
}
}
if ((ret = sfopen(f, (const char*) data + sizeof(uint32_t))) < 0)
remove_entry = TRUE;
finish:
if (remove_entry)
db_remove(key, klen);
if (sound_path && ret < 0)
ca_free(*sound_path);
ca_free(key);
ca_free(data);
return ret;
}
int ca_cache_store_sound(
const char *theme,
const char *name,
const char *locale,
const char *profile,
const char *fname) {
char *key;
void *data;
size_t klen, dlen;
int ret;
time_t now;
ca_return_val_if_fail(theme, CA_ERROR_INVALID);
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
ca_return_val_if_fail(locale, CA_ERROR_INVALID);
ca_return_val_if_fail(profile, CA_ERROR_INVALID);
if (!(key = build_key(theme, name, locale, profile, &klen)))
return CA_ERROR_OOM;
dlen = sizeof(uint32_t) + (fname ? strlen(fname) + 1 : 0);
if (!(data = ca_malloc(dlen))) {
ca_free(key);
return CA_ERROR_OOM;
}
ca_assert_se(time(&now) != (time_t) -1);
*(uint32_t*) data = (uint32_t) now;
if (fname)
strcpy((char*) data + sizeof(uint32_t), fname);
ret = db_store(key, klen, data, dlen);
ca_free(key);
ca_free(data);
return ret;
}
0707010000001C000081A4000000000000000000000001509D8F370000055D000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/cache.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberracachehfoo
#define foocanberracachehfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include "read-sound-file.h"
int ca_cache_lookup_sound(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme,
const char *name,
const char *locale,
const char *profile);
int ca_cache_store_sound(
const char *theme,
const char *name,
const char *locale,
const char *profile,
const char *fname);
#endif
0707010000001D000081A4000000000000000000000001509D8F3700001D34000000000000000000000000000000000000002700000000libcanberra-0.30+2/src/canberra-boot.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <canberra.h>
#include <libudev.h>
#include "macro.h"
static char *find_device(void) {
struct udev *udev = NULL;
struct udev_enumerate *udev_enum = NULL;
struct udev_list_entry *i, *first;
int internal_device = -1, pci_device = -1, other_device = -1;
char *s = NULL;
if (!(udev = udev_new())) {
fprintf(stderr, "Failed to allocate udev context.\n");
return NULL;
}
if (!(udev_enum = udev_enumerate_new(udev))) {
fprintf(stderr, "Failed to allocate enumeration object.\n");
goto finish;
}
if (udev_enumerate_add_match_subsystem(udev_enum, "sound") < 0) {
fprintf(stderr, "Failed to install subsystem match.\n");
goto finish;
}
if (udev_enumerate_scan_devices(udev_enum) < 0) {
fprintf(stderr, "Failed to enumerate devices.\n");
goto finish;
}
first = udev_enumerate_get_list_entry(udev_enum);
udev_list_entry_foreach(i, first) {
const char *sysfs, *p;
long l;
char d[64];
char *e = NULL;
struct udev_device *dev;
const char *ff, *class, *bus;
sysfs = udev_list_entry_get_name(i);
if (!(p = strrchr(sysfs, '/')))
continue;
p++;
if (strncmp(p, "card", 4) != 0)
continue;
errno = 0;
l = strtol(p + 4, &e, 10);
if (!e || *e != 0 || errno != 0)
continue;
/* Check whether this sound card has a playback device
* #0 (i.e. something that is not HDMI, SPDIF or
* something other weird.) */
snprintf(d, sizeof(d), "/sys/class/sound/card%i/pcmC%iD0p", (int) l, (int) l);
if (access(d, F_OK) < 0)
continue;
if (!(dev = udev_device_new_from_syspath(udev, sysfs)))
continue;
class = udev_device_get_property_value(dev, "SOUND_CLASS");
ff = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR");
bus = udev_device_get_property_value(dev, "ID_BUS");
/* Ignore modems and other non-audio sound device */
if (class && !ca_streq(class, "sound")) {
udev_device_unref(dev);
continue;
}
/* Prefer "internal" devices */
if (internal_device < 0 && ff && ca_streq(ff, "internal"))
internal_device = (int) l;
/* If no "internal" device is available, prefer PCI devices */
if (pci_device < 0 && bus && ca_streq(bus, "pci"))
pci_device = (int) l;
/* If neither "internal" nor PCI devices are
* available, pick whatever we can find */
if (other_device < 0)
other_device = (int) l;
udev_device_unref(dev);
}
if (internal_device >= 0)
asprintf(&s, "front:%i", internal_device);
else if (pci_device >= 0)
asprintf(&s, "front:%i", pci_device);
else if (other_device >= 0)
asprintf(&s, "front:%i", other_device);
finish:
if (udev_enum)
udev_enumerate_unref(udev_enum);
if (udev)
udev_unref(udev);
return s;
}
static void finish_cb(ca_context *c, uint32_t id, int error_code, void *userdata) {
uint64_t u = 1;
for (;;) {
if (write(CA_PTR_TO_INT(userdata), &u, sizeof(u)) > 0)
break;
if (errno != EINTR) {
fprintf(stderr, "write() failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
}
int main(int argc, char *argv[]) {
ca_context *c = NULL;
ca_proplist *p = NULL;
int ret = EXIT_FAILURE, r;
int fd = -1;
char *device = NULL;
if (argc > 2) {
fprintf(stderr, "This program expects no more than one parameter.\n");
goto finish;
}
if ((fd = eventfd(0, EFD_CLOEXEC)) < 0) {
fprintf(stderr, "Failed to create event file descriptor: %s\n", strerror(errno));
goto finish;
}
if ((r = ca_context_create(&c)) < 0) {
fprintf(stderr, "Failed to create context: %s\n", ca_strerror(r));
goto finish;
}
if ((r = ca_context_set_driver(c, "alsa")) < 0) {
fprintf(stderr, "Failed to set driver: %s\n", ca_strerror(r));
goto finish;
}
if (!(device = find_device())) {
ret = EXIT_SUCCESS;
goto finish;
}
if ((r = ca_context_change_device(c, device)) < 0) {
fprintf(stderr, "Failed to set device: %s\n", ca_strerror(r));
goto finish;
}
if ((r = ca_proplist_create(&p)) < 0) {
fprintf(stderr, "Failed to create property list: %s\n", ca_strerror(r));
goto finish;
}
if ((r = ca_proplist_sets(p, CA_PROP_EVENT_ID, argc >= 2 ? argv[1] : "system-bootup")) < 0 ||
(r = ca_proplist_sets(p, CA_PROP_CANBERRA_CACHE_CONTROL, "never")) < 0) {
fprintf(stderr, "Failed to set event id: %s\n", strerror(r));
goto finish;
}
if ((r = ca_context_play_full(c, 0, p, finish_cb, CA_INT_TO_PTR(fd))) < 0) {
fprintf(stderr, "Failed to play event sound: %s\n", ca_strerror(r));
goto finish;
}
for (;;) {
uint64_t u;
if (read(fd, &u, sizeof(u)) < 0) {
if (errno == EINTR)
break;
fprintf(stderr, "read() failed: %s\n", strerror(errno));
} else
break;
}
ret = EXIT_SUCCESS;
finish:
if (c)
ca_context_destroy(c);
if (p)
ca_proplist_destroy(p);
if (fd >= 0)
close(fd);
free(device);
return ret;
}
0707010000001E000081A4000000000000000000000001509D8F370000A523000000000000000000000000000000000000002D00000000libcanberra-0.30+2/src/canberra-gtk-module.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#include "canberra-gtk.h"
typedef struct {
guint signal_id;
gboolean arg1_is_set;
GObject *object;
GValue arg1;
GdkEvent *event;
} SoundEventData;
/*
We generate these sounds:
dialog-error
dialog-warning
dialog-information
dialog-question
window-new
window-close
window-minimized
window-unminimized
window-maximized
window-unmaximized
notebook-tab-changed
dialog-ok
dialog-cancel
item-selected
link-pressed
link-released
button-pressed
button-released
menu-click
button-toggle-on
button-toggle-off
menu-popup
menu-popdown
menu-replace
tooltip-popup
tooltip-popdown
drag-start
drag-accept
drag-fail
expander-toggle-on
expander-toggle-off
TODO:
scroll-xxx
window-switch
window-resize-xxx
window-move-xxx
*/
static gboolean disabled = FALSE;
static GQueue sound_event_queue = G_QUEUE_INIT;
static guint idle_id = 0;
static guint
signal_id_dialog_response,
signal_id_widget_show,
signal_id_widget_hide,
signal_id_check_menu_item_toggled,
signal_id_menu_item_activate,
signal_id_toggle_button_toggled,
signal_id_button_pressed,
signal_id_button_released,
signal_id_widget_window_state_event,
signal_id_notebook_switch_page,
signal_id_tree_view_cursor_changed,
signal_id_icon_view_selection_changed,
signal_id_widget_drag_begin,
signal_id_widget_drag_failed,
signal_id_widget_drag_drop,
signal_id_expander_activate;
static GQuark
disable_sound_quark,
was_iconized_quark,
is_xembed_quark;
/* Make sure GCC doesn't warn us about a missing prototype for this
* exported function */
void gtk_module_init(gint *argc, gchar ***argv[]);
static const char *translate_message_tye(GtkMessageType mt) {
static const char *const message_type_table[] = {
[GTK_MESSAGE_INFO] = "dialog-information",
[GTK_MESSAGE_WARNING] = "dialog-warning",
[GTK_MESSAGE_QUESTION] = "dialog-question",
[GTK_MESSAGE_ERROR] = "dialog-error",
[GTK_MESSAGE_OTHER] = NULL
};
if (mt >= G_N_ELEMENTS(message_type_table))
return NULL;
return message_type_table[mt];
}
static const char *translate_response(int response) {
static const char *const response_table[] = {
[-GTK_RESPONSE_NONE] = NULL,
[-GTK_RESPONSE_REJECT] = "dialog-cancel",
[-GTK_RESPONSE_DELETE_EVENT] = "dialog-cancel",
[-GTK_RESPONSE_ACCEPT] = "dialog-ok",
[-GTK_RESPONSE_OK] = "dialog-ok",
[-GTK_RESPONSE_CANCEL] = "dialog-cancel",
[-GTK_RESPONSE_CLOSE] = "dialog-ok",
[-GTK_RESPONSE_YES] = "dialog-ok",
[-GTK_RESPONSE_NO] = "dialog-cancel",
[-GTK_RESPONSE_APPLY] = "dialog-ok",
[-GTK_RESPONSE_HELP] = NULL,
};
if (response >= 0)
return NULL;
if ((unsigned) -response >= G_N_ELEMENTS(response_table))
return NULL;
return response_table[-response];
}
static gboolean is_child_of_combo_box(GtkWidget *w) {
while (w) {
if (GTK_IS_COMBO_BOX(w))
return TRUE;
w = gtk_widget_get_parent(w);
}
return FALSE;
}
static GtkDialog* find_parent_dialog(GtkWidget *w) {
while (w) {
if (GTK_IS_DIALOG(w))
return GTK_DIALOG(w);
w = gtk_widget_get_parent(w);
}
return NULL;
}
static void free_sound_event(SoundEventData *d) {
g_object_unref(d->object);
if (d->arg1_is_set)
g_value_unset(&d->arg1);
if (d->event)
gdk_event_free(d->event);
g_slice_free(SoundEventData, d);
}
static gboolean is_menu_hint(GdkWindowTypeHint hint) {
return
hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU ||
hint == GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU ||
hint == GDK_WINDOW_TYPE_HINT_MENU;
}
static SoundEventData* filter_sound_event(SoundEventData *d) {
GList *i, *n;
do {
for (i = sound_event_queue.head; i; i = n) {
SoundEventData *j;
j = i->data;
n = i->next;
if (d->object == j->object) {
/* Let's drop a show event immediately followed by a
* hide event */
if (d->signal_id == signal_id_widget_show &&
j->signal_id == signal_id_widget_hide) {
free_sound_event(d);
free_sound_event(j);
g_queue_delete_link(&sound_event_queue, i);
return NULL;
}
/* Let's drop widget hide events in favour of dialog
* response.
*
* Let's drop widget window state events in favour of
* widget hide/show.
*
* Let's drop double events */
if ((d->signal_id == signal_id_widget_hide &&
j->signal_id == signal_id_dialog_response) ||
(d->signal_id == signal_id_widget_window_state_event &&
j->signal_id == signal_id_widget_hide) ||
(d->signal_id == signal_id_widget_window_state_event &&
j->signal_id == signal_id_widget_show)) {
free_sound_event(d);
d = j;
g_queue_delete_link(&sound_event_queue, i);
break;
}
if ((d->signal_id == signal_id_dialog_response &&
j->signal_id == signal_id_widget_hide) ||
(d->signal_id == signal_id_widget_show &&
j->signal_id == signal_id_widget_window_state_event) ||
(d->signal_id == signal_id_widget_hide &&
j->signal_id == signal_id_widget_window_state_event) ||
(d->signal_id == j->signal_id)) {
free_sound_event(j);
g_queue_delete_link(&sound_event_queue, i);
}
} else if (GTK_IS_WINDOW(d->object) && GTK_IS_WINDOW(j->object)) {
GdkWindowTypeHint dhint, jhint;
dhint = gtk_window_get_type_hint(GTK_WINDOW(d->object));
jhint = gtk_window_get_type_hint(GTK_WINDOW(j->object));
if (is_menu_hint(dhint) && is_menu_hint(jhint)) {
if (d->signal_id == signal_id_widget_hide &&
j->signal_id == signal_id_widget_show) {
free_sound_event(d);
d = j;
g_queue_delete_link(&sound_event_queue, i);
break;
}
if (d->signal_id == signal_id_widget_show &&
j->signal_id == signal_id_widget_hide) {
free_sound_event(j);
g_queue_delete_link(&sound_event_queue, i);
}
}
}
}
/* If we exited the iteration early, let's retry. */
} while (i);
/* FIXME: Filter menu hide on menu show */
return d;
}
static gint window_get_desktop(GdkDisplay *d, GdkWindow *w) {
Atom type_return;
gint format_return;
gulong nitems_return;
gulong bytes_after_return;
guchar *data = NULL;
gint ret = -1;
#ifdef GDK_IS_X11_DISPLAY
if (!GDK_IS_X11_DISPLAY(d))
return 0;
#endif
if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w),
gdk_x11_get_xatom_by_name_for_display(d, "_NET_WM_DESKTOP"),
0, G_MAXLONG, False, XA_CARDINAL, &type_return,
&format_return, &nitems_return, &bytes_after_return,
&data) != Success)
return -1;
if (type_return == XA_CARDINAL && format_return == 32 && data) {
guint32 desktop = *(guint32*) data;
if (desktop != 0xFFFFFFFF)
ret = (gint) desktop;
}
if (type_return != None && data != NULL)
XFree(data);
return ret;
}
static gint display_get_desktop(GdkDisplay *d) {
Atom type_return;
gint format_return;
gulong nitems_return;
gulong bytes_after_return;
guchar *data = NULL;
gint ret = -1;
#ifdef GDK_IS_X11_DISPLAY
if (!GDK_IS_X11_DISPLAY(d))
return 0;
#endif
if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), DefaultRootWindow(GDK_DISPLAY_XDISPLAY(d)),
gdk_x11_get_xatom_by_name_for_display(d, "_NET_CURRENT_DESKTOP"),
0, G_MAXLONG, False, XA_CARDINAL, &type_return,
&format_return, &nitems_return, &bytes_after_return,
&data) != Success)
return -1;
if (type_return == XA_CARDINAL && format_return == 32 && data) {
guint32 desktop = *(guint32*) data;
if (desktop != 0xFFFFFFFF)
ret = (gint) desktop;
}
if (type_return != None && data != NULL)
XFree(data);
return ret;
}
static gboolean window_is_xembed(GdkDisplay *d, GdkWindow *w) {
Atom type_return;
gint format_return;
gulong nitems_return;
gulong bytes_after_return;
guchar *data = NULL;
gboolean ret = FALSE;
Atom xembed;
#ifdef GDK_IS_X11_DISPLAY
if (!GDK_IS_X11_DISPLAY(d))
return FALSE;
#endif
/* Gnome Panel applets are XEMBED windows. We need to make sure we
* ignore them */
xembed = gdk_x11_get_xatom_by_name_for_display(d, "_XEMBED_INFO");
/* be robust against not existing XIDs (LP: #834403) */
gdk_error_trap_push();
if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w),
xembed,
0, 2, False, xembed, &type_return,
&format_return, &nitems_return, &bytes_after_return,
&data) != Success) {
return FALSE;
}
#if GTK_CHECK_VERSION(3,0,0)
gdk_error_trap_pop_ignored();
#else
gdk_flush();
gdk_error_trap_pop();
#endif
if (type_return == xembed && format_return == 32 && data)
ret = TRUE;
if (type_return != None && data != NULL)
XFree(data);
return ret;
}
static void dispatch_sound_event(SoundEventData *d) {
int ret = CA_SUCCESS;
static gboolean menu_is_popped_up = FALSE;
if (g_object_get_qdata(d->object, disable_sound_quark))
return;
/* The GdkWindow of the the widget might have changed while this
* event was queued for us. Make sure to update it from the
* current one if necessary. */
if (d->event && d->event->any.window) {
GdkWindow *window;
g_object_unref(G_OBJECT(d->event->any.window));
if ((window = gtk_widget_get_window(GTK_WIDGET(d->object))))
d->event->any.window = GDK_WINDOW(g_object_ref(G_OBJECT(window)));
else
d->event->any.window = NULL;
}
if (d->signal_id == signal_id_widget_show) {
GdkWindowTypeHint hint;
/* Show/hide signals for non-windows have already been filtered out
* by the emission hook! */
hint = gtk_window_get_type_hint(GTK_WINDOW(d->object));
if (is_menu_hint(hint)) {
if (!menu_is_popped_up) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "menu-popup",
CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "menu-replace",
CA_PROP_EVENT_DESCRIPTION, "Menu replaced",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
menu_is_popped_up = TRUE;
} else if (hint == GDK_WINDOW_TYPE_HINT_TOOLTIP) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "tooltip-popup",
CA_PROP_EVENT_DESCRIPTION, "Tooltip popped up",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else if (hint == GDK_WINDOW_TYPE_HINT_NORMAL ||
hint == GDK_WINDOW_TYPE_HINT_DIALOG) {
gboolean played_sound = FALSE;
gboolean is_xembed;
is_xembed =
gtk_widget_get_realized(GTK_WIDGET(d->object)) &&
window_is_xembed(
gtk_widget_get_display(GTK_WIDGET(d->object)),
gtk_widget_get_window(GTK_WIDGET(d->object)));
g_object_set_qdata(d->object, is_xembed_quark, GINT_TO_POINTER(is_xembed));
if (GTK_IS_MESSAGE_DIALOG(d->object)) {
GtkMessageType mt;
const char *id;
g_object_get(d->object, "message_type", &mt, NULL);
if ((id = translate_message_tye(mt))) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, id,
CA_PROP_EVENT_DESCRIPTION, "Message dialog shown",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
played_sound = TRUE;
}
}
if (!played_sound &&
!is_xembed &&
gtk_window_get_decorated(GTK_WINDOW(d->object))) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-new",
CA_PROP_EVENT_DESCRIPTION, "Window shown",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
}
}
if (GTK_IS_DIALOG(d->object) && d->signal_id == signal_id_dialog_response) {
int response;
const char *id;
response = g_value_get_int(&d->arg1);
if ((id = translate_response(response))) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, id,
CA_PROP_EVENT_DESCRIPTION, "Dialog closed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-close",
CA_PROP_EVENT_DESCRIPTION, "Window closed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
} else if (d->signal_id == signal_id_widget_hide) {
GdkWindowTypeHint hint;
hint = gtk_window_get_type_hint(GTK_WINDOW(d->object));
if (is_menu_hint(hint)) {
if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "menu-popdown",
CA_PROP_EVENT_DESCRIPTION, "Menu popped down",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
menu_is_popped_up = FALSE;
} else if (hint == GDK_WINDOW_TYPE_HINT_TOOLTIP) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "tooltip-popdown",
CA_PROP_EVENT_DESCRIPTION, "Tooltip popped down",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else if ((hint == GDK_WINDOW_TYPE_HINT_NORMAL ||
hint == GDK_WINDOW_TYPE_HINT_DIALOG)) {
gboolean is_xembed;
is_xembed = !!g_object_get_qdata(d->object, is_xembed_quark);
if (!is_xembed &&
gtk_window_get_decorated(GTK_WINDOW(d->object)))
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-close",
CA_PROP_EVENT_DESCRIPTION, "Window closed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
}
if (GTK_IS_WINDOW(d->object) && d->signal_id == signal_id_widget_window_state_event) {
GdkEventWindowState *e;
gint w_desktop = -1, c_desktop = -1;
e = (GdkEventWindowState*) d->event;
/* Unfortunately GDK_WINDOW_STATE_ICONIFIED is used both for
* proper minimizing and when a window becomes invisible
* because the desktop was switched. To handle this we check
* if the window becoming invisible is actually on the current
* desktop, and only if that's the case we assume it is being
* minimized. We then store this information, so that we know
* later on when the window is unminimized again. */
if (gtk_widget_get_realized(GTK_WIDGET(d->object))) {
GdkDisplay *display;
display = gtk_widget_get_display(GTK_WIDGET(d->object));
w_desktop = window_get_desktop(display, gtk_widget_get_window(GTK_WIDGET(d->object)));
c_desktop = display_get_desktop(display);
}
if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
(e->new_window_state & GDK_WINDOW_STATE_ICONIFIED) &&
(w_desktop == c_desktop || w_desktop < 0)) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-minimized",
CA_PROP_EVENT_DESCRIPTION, "Window minimized",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
g_object_set_qdata(d->object, was_iconized_quark, GINT_TO_POINTER(1));
} else if ((e->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) &&
(e->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN))) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-maximized",
CA_PROP_EVENT_DESCRIPTION, "Window maximized",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
g_object_set_qdata(d->object, was_iconized_quark, GINT_TO_POINTER(0));
} else if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
!(e->new_window_state & GDK_WINDOW_STATE_ICONIFIED) &&
g_object_get_qdata(d->object, was_iconized_quark)) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-unminimized",
CA_PROP_EVENT_DESCRIPTION, "Window unminimized",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
g_object_set_qdata(d->object, was_iconized_quark, GINT_TO_POINTER(0));
} else if ((e->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) &&
!(e->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN))) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-unmaximized",
CA_PROP_EVENT_DESCRIPTION, "Window unmaximized",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
}
if (GTK_IS_CHECK_MENU_ITEM(d->object) && d->signal_id == signal_id_check_menu_item_toggled) {
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(d->object)))
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-toggle-on",
CA_PROP_EVENT_DESCRIPTION, "Check menu item checked",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
else
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-toggle-off",
CA_PROP_EVENT_DESCRIPTION, "Check menu item unchecked",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else if (GTK_IS_MENU_ITEM(d->object) && d->signal_id == signal_id_menu_item_activate) {
if (!gtk_menu_item_get_submenu(GTK_MENU_ITEM(d->object)))
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "menu-click",
CA_PROP_EVENT_DESCRIPTION, "Menu item clicked",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
if (GTK_IS_TOGGLE_BUTTON(d->object)) {
if (d->signal_id == signal_id_toggle_button_toggled) {
if (!is_child_of_combo_box(GTK_WIDGET(d->object))) {
/* We don't want to play this sound if this is a toggle
* button belonging to combo box. */
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(d->object)))
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-toggle-on",
CA_PROP_EVENT_DESCRIPTION, "Toggle button checked",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
else
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-toggle-off",
CA_PROP_EVENT_DESCRIPTION, "Toggle button unchecked",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
}
} else if (GTK_IS_LINK_BUTTON(d->object)) {
if (d->signal_id == signal_id_button_pressed) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "link-pressed",
CA_PROP_EVENT_DESCRIPTION, "Link pressed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else if (d->signal_id == signal_id_button_released) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "link-released",
CA_PROP_EVENT_DESCRIPTION, "Link released",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
} else if (GTK_IS_BUTTON(d->object) && !GTK_IS_TOGGLE_BUTTON(d->object)) {
if (d->signal_id == signal_id_button_pressed) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-pressed",
CA_PROP_EVENT_DESCRIPTION, "Button pressed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
} else if (d->signal_id == signal_id_button_released) {
GtkDialog *dialog;
gboolean dont_play = FALSE;
if ((dialog = find_parent_dialog(GTK_WIDGET(d->object)))) {
int response;
/* Don't play the click sound if this is a response widget
* we will generate a dialog-xxx event sound anyway. */
response = gtk_dialog_get_response_for_widget(dialog, GTK_WIDGET(d->object));
dont_play = !!translate_response(response);
}
if (!dont_play)
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-released",
CA_PROP_EVENT_DESCRIPTION, "Button released",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
}
}
if (GTK_IS_NOTEBOOK(d->object) && d->signal_id == signal_id_notebook_switch_page) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "notebook-tab-changed",
CA_PROP_EVENT_DESCRIPTION, "Tab changed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
}
if (GTK_IS_TREE_VIEW(d->object) && d->signal_id == signal_id_tree_view_cursor_changed) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "item-selected",
CA_PROP_EVENT_DESCRIPTION, "Item selected",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
}
if (GTK_IS_ICON_VIEW(d->object) && d->signal_id == signal_id_icon_view_selection_changed) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "item-selected",
CA_PROP_EVENT_DESCRIPTION, "Item selected",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
}
if (GTK_IS_EXPANDER(d->object) && d->signal_id == signal_id_expander_activate) {
if (gtk_expander_get_expanded(GTK_EXPANDER(d->object)))
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "expander-toggle-on",
CA_PROP_EVENT_DESCRIPTION, "Expander expanded",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
else
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "expander-toggle-off",
CA_PROP_EVENT_DESCRIPTION, "Expander unexpanded",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
}
if (GTK_IS_WIDGET(d->object)) {
if (d->signal_id == signal_id_widget_drag_begin) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "drag-start",
CA_PROP_EVENT_DESCRIPTION, "Drag started",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
} else if (d->signal_id == signal_id_widget_drag_drop) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "drag-accept",
CA_PROP_EVENT_DESCRIPTION, "Drag accepted",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
} else if (d->signal_id == signal_id_widget_drag_failed) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "drag-fail",
CA_PROP_EVENT_DESCRIPTION, "Drag failed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
goto finish;
}
}
finish:
;
/* if (ret != CA_SUCCESS) */
/* g_warning("Failed to play event sound: %s", ca_strerror(ret)); */
}
static void dispatch_queue(void) {
SoundEventData *d;
while ((d = g_queue_pop_head(&sound_event_queue))) {
if (!(d = filter_sound_event(d)))
continue;
dispatch_sound_event(d);
free_sound_event(d);
}
}
static gboolean idle_cb(void *userdata) {
idle_id = 0;
dispatch_queue();
return FALSE;
}
static void connect_settings(void);
static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_values, const GValue *param_values, gpointer data) {
static SoundEventData *d = NULL;
GdkEvent *e;
GObject *object;
connect_settings();
if (disabled)
return TRUE;
object = g_value_get_object(¶m_values[0]);
/* g_message("signal '%s' on object of type '%s' with name '%s'", */
/* g_signal_name(hint->signal_id), */
/* G_OBJECT_TYPE_NAME(object), */
/* gtk_widget_get_name(GTK_WIDGET(object))); */
/* if (GTK_IS_WINDOW(object)) */
/* g_message("window role='%s' title='%s' type='%u'", */
/* gtk_window_get_role(GTK_WINDOW(object)), */
/* gtk_window_get_title(GTK_WINDOW(object)), */
/* gtk_window_get_type_hint(GTK_WINDOW(object))); */
/* Filter a few very often occuring signals as quickly as possible */
if ((hint->signal_id == signal_id_widget_hide ||
hint->signal_id == signal_id_widget_show ||
hint->signal_id == signal_id_widget_window_state_event) &&
!GTK_IS_WINDOW(object))
return TRUE;
if (hint->signal_id != signal_id_widget_hide &&
hint->signal_id != signal_id_dialog_response &&
!gtk_widget_is_drawable(GTK_WIDGET (object)))
return TRUE;
d = g_slice_new0(SoundEventData);
d->object = g_object_ref(object);
d->signal_id = hint->signal_id;
if (d->signal_id == signal_id_widget_window_state_event) {
d->event = gdk_event_copy(g_value_peek_pointer(¶m_values[1]));
} else if ((e = gtk_get_current_event()))
d->event = gdk_event_copy(e);
if (n_param_values > 1) {
g_value_init(&d->arg1, G_VALUE_TYPE(¶m_values[1]));
g_value_copy(¶m_values[1], &d->arg1);
d->arg1_is_set = TRUE;
}
g_queue_push_tail(&sound_event_queue, d);
if (idle_id == 0)
idle_id = gdk_threads_add_idle_full(GDK_PRIORITY_REDRAW-1, (GSourceFunc) idle_cb, NULL, NULL);
return TRUE;
}
static void install_hook(GType type, const char *sig, guint *sn) {
GTypeClass *type_class;
type_class = g_type_class_ref(type);
*sn = g_signal_lookup(sig, type);
g_signal_add_emission_hook(*sn, 0, emission_hook_cb, NULL, NULL);
g_type_class_unref(type_class);
}
static void read_enable_input_feedback_sounds(GtkSettings *s) {
gboolean enabled = !disabled;
if (g_getenv("CANBERRA_FORCE_INPUT_FEEDBACK_SOUNDS"))
disabled = FALSE;
else {
g_object_get(G_OBJECT(s), "gtk-enable-input-feedback-sounds", &enabled, NULL);
disabled = !enabled;
}
}
static void enable_input_feedback_sounds_changed(GtkSettings *s, GParamSpec *arg1, gpointer userdata) {
read_enable_input_feedback_sounds(s);
}
static void connect_settings(void) {
GtkSettings *s;
static gboolean connected = FALSE;
if (connected)
return;
if (!(s = gtk_settings_get_default()))
return;
if (g_object_class_find_property(G_OBJECT_GET_CLASS(s), "gtk-enable-input-feedback-sounds")) {
g_signal_connect(G_OBJECT(s), "notify::gtk-enable-input-feedback-sounds", G_CALLBACK(enable_input_feedback_sounds_changed), NULL);
read_enable_input_feedback_sounds(s);
} else
g_debug("This Gtk+ version doesn't have the GtkSettings::gtk-enable-input-feedback-sounds property.");
connected = TRUE;
}
#if GTK_CHECK_VERSION(3,0,0)
#warning "We really need a quit handler in Gtk 3.0, https://bugzilla.gnome.org/show_bug.cgi?id=639770"
#else
static gboolean quit_handler(gpointer data) {
dispatch_queue();
return FALSE;
}
#endif
G_MODULE_EXPORT void gtk_module_init(gint *argc, gchar ***argv[]) {
/* This is the same quark libgnomeui uses! */
disable_sound_quark = g_quark_from_string("gnome_disable_sound_events");
was_iconized_quark = g_quark_from_string("canberra_was_iconized");
is_xembed_quark = g_quark_from_string("canberra_is_xembed");
/* Hook up the gtk setting */
connect_settings();
install_hook(GTK_TYPE_WINDOW, "show", &signal_id_widget_show);
install_hook(GTK_TYPE_WINDOW, "hide", &signal_id_widget_hide);
install_hook(GTK_TYPE_DIALOG, "response", &signal_id_dialog_response);
install_hook(GTK_TYPE_MENU_ITEM, "activate", &signal_id_menu_item_activate);
install_hook(GTK_TYPE_CHECK_MENU_ITEM, "toggled", &signal_id_check_menu_item_toggled);
install_hook(GTK_TYPE_TOGGLE_BUTTON, "toggled", &signal_id_toggle_button_toggled);
install_hook(GTK_TYPE_BUTTON, "pressed", &signal_id_button_pressed);
install_hook(GTK_TYPE_BUTTON, "released", &signal_id_button_released);
install_hook(GTK_TYPE_WIDGET, "window-state-event", &signal_id_widget_window_state_event);
install_hook(GTK_TYPE_NOTEBOOK, "switch-page", &signal_id_notebook_switch_page);
install_hook(GTK_TYPE_TREE_VIEW, "cursor-changed", &signal_id_tree_view_cursor_changed);
install_hook(GTK_TYPE_ICON_VIEW, "selection-changed", &signal_id_icon_view_selection_changed);
install_hook(GTK_TYPE_WIDGET, "drag-begin", &signal_id_widget_drag_begin);
install_hook(GTK_TYPE_WIDGET, "drag-drop", &signal_id_widget_drag_drop);
install_hook(GTK_TYPE_WIDGET, "drag-failed", &signal_id_widget_drag_failed);
install_hook(GTK_TYPE_EXPANDER, "activate", &signal_id_expander_activate);
#if !GTK_CHECK_VERSION(3,0,0)
gtk_quit_add(1, quit_handler, NULL);
#endif
}
G_MODULE_EXPORT gchar* g_module_check_init(GModule *module);
G_MODULE_EXPORT gchar* g_module_check_init(GModule *module) {
g_module_make_resident(module);
return NULL;
}
0707010000001F000081A4000000000000000000000001509D8F37000000C5000000000000000000000000000000000000003300000000libcanberra-0.30+2/src/canberra-gtk-module.desktop[GTK Module]
Name=canberra-gtk-module
Description=Event Sound Module
X-GTK-Module-Name=canberra-gtk-module
X-GTK-Module-Enabled-Schema=org.gnome.desktop.sound
X-GTK-Module-Enabled-Key=event-sounds
07070100000020000081A4000000000000000000000001509D8F3700001A79000000000000000000000000000000000000002B00000000libcanberra-0.30+2/src/canberra-gtk-play.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <locale.h>
#include <gtk/gtk.h>
#include <canberra-gtk.h>
static int ret = 0;
static ca_proplist *proplist = NULL;
static int n_loops = 1;
static void callback(ca_context *c, uint32_t id, int error, void *userdata);
static gboolean idle_quit(gpointer userdata) {
gtk_main_quit();
return FALSE;
}
static gboolean idle_play(gpointer userdata) {
int r;
g_assert(n_loops > 1);
n_loops--;
r = ca_context_play_full(ca_gtk_context_get(), 1, proplist, callback, NULL);
if (r < 0) {
g_printerr("Failed to play sound: %s\n", ca_strerror(r));
ret = 1;
gtk_main_quit();
}
return FALSE;
}
static void callback(ca_context *c, uint32_t id, int error, void *userdata) {
if (error < 0) {
g_printerr("Failed to play sound (callback): %s\n", ca_strerror(error));
ret = 1;
} else if (n_loops > 1) {
/* So, why don't we call ca_context_play_full() here directly?
-- Because the context this callback is called from is
explicitly documented as undefined and no libcanberra function
may be called from it. */
g_idle_add(idle_play, NULL);
return;
}
/* So, why don't we call gtk_main_quit() here directly? -- Because
* otherwise we might end up with a small race condition: this
* callback might get called before the main loop actually started
* running */
g_idle_add(idle_quit, NULL);
}
static GQuark error_domain(void) {
return g_quark_from_static_string("canberra-error-quark");
}
static gboolean property_callback(
const gchar *option_name,
const gchar *value,
gpointer data,
GError **error) {
const char *equal;
char *t;
if (!(equal = strchr(value, '='))) {
g_set_error(error, error_domain(), 0, "Property lacks '='.");
return FALSE;
}
t = g_strndup(value, equal - value);
if (ca_proplist_sets(proplist, t, equal + 1) < 0) {
g_set_error(error, error_domain(), 0, "Invalid property.");
g_free(t);
return FALSE;
}
g_free(t);
return TRUE;
}
int main (int argc, char *argv[]) {
GOptionContext *oc;
static gchar *event_id = NULL, *filename = NULL, *event_description = NULL, *cache_control = NULL, *volume = NULL;
int r;
static gboolean version = FALSE;
GError *error = NULL;
static const GOptionEntry options[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display version number and quit", NULL },
{ "id", 'i', 0, G_OPTION_ARG_STRING, &event_id, "Event sound identifier", "STRING" },
{ "file", 'f', 0, G_OPTION_ARG_STRING, &filename, "Play file", "PATH" },
{ "description", 'd', 0, G_OPTION_ARG_STRING, &event_description, "Event sound description", "STRING" },
{ "cache-control", 'c', 0, G_OPTION_ARG_STRING, &cache_control, "Cache control (permanent, volatile, never)", "STRING" },
{ "loop", 'l', 0, G_OPTION_ARG_INT, &n_loops, "Loop how many times (detault: 1)", "INTEGER" },
{ "volume", 'V', 0, G_OPTION_ARG_STRING, &volume, "A floating point dB value for the sample volume (ex: 0.0)", "STRING" },
{ "property", 0, 0, G_OPTION_ARG_CALLBACK, (void*) property_callback, "An arbitrary property", "STRING" },
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
setlocale(LC_ALL, "");
g_type_init();
ca_proplist_create(&proplist);
oc = g_option_context_new("- canberra-gtk-play");
g_option_context_add_main_entries(oc, options, NULL);
g_option_context_add_group(oc, gtk_get_option_group(TRUE));
g_option_context_set_help_enabled(oc, TRUE);
if (!(g_option_context_parse(oc, &argc, &argv, &error))) {
g_print("Option parsing failed: %s\n", error->message);
return 1;
}
g_option_context_free(oc);
if (version) {
g_print("canberra-gtk-play from %s\n", PACKAGE_STRING);
return 0;
}
if (!event_id && !filename) {
g_printerr("No event id or file specified.\n");
return 1;
}
ca_context_change_props(ca_gtk_context_get(),
CA_PROP_APPLICATION_NAME, "canberra-gtk-play",
CA_PROP_APPLICATION_VERSION, PACKAGE_VERSION,
CA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra.gtk-play",
NULL);
if (event_id)
ca_proplist_sets(proplist, CA_PROP_EVENT_ID, event_id);
if (filename)
ca_proplist_sets(proplist, CA_PROP_MEDIA_FILENAME, filename);
if (cache_control)
ca_proplist_sets(proplist, CA_PROP_CANBERRA_CACHE_CONTROL, cache_control);
if (event_description)
ca_proplist_sets(proplist, CA_PROP_EVENT_DESCRIPTION, event_description);
if (volume)
ca_proplist_sets(proplist, CA_PROP_CANBERRA_VOLUME, volume);
r = ca_context_play_full(ca_gtk_context_get(), 1, proplist, callback, NULL);
if (r < 0) {
g_printerr("Failed to play sound: %s\n", ca_strerror(r));
ret = 1;
goto finish;
}
gtk_main();
finish:
ca_proplist_destroy(proplist);
return ret;
}
07070100000021000081A4000000000000000000000001509D8F3700004E16000000000000000000000000000000000000002600000000libcanberra-0.30+2/src/canberra-gtk.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#include "canberra.h"
#include "canberra-gtk.h"
#include "common.h"
#include "malloc.h"
#include "proplist.h"
#include "fork-detect.h"
/**
* SECTION:canberra-gtk
* @short_description: Gtk+ libcanberra Bindings
*
* libcanberra-gtk provides a few functions that simplify libcanberra
* usage from Gtk+ programs. It maintains a single ca_context object
* per #GdkScreen that is made accessible via
* ca_gtk_context_get_for_screen(), with a shortcut ca_gtk_context_get()
* to get the context for the default screen. More importantly, it provides
* a few functions
* to compile event sound property lists based on GtkWidget objects or
* GdkEvent events.
*/
static void read_sound_theme_name(ca_context *c, GtkSettings *s) {
gchar *theme_name = NULL;
g_object_get(G_OBJECT(s), "gtk-sound-theme-name", &theme_name, NULL);
if (theme_name) {
ca_context_change_props(c, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
g_free(theme_name);
}
}
static void read_enable_event_sounds(ca_context *c, GtkSettings *s) {
gboolean enable_event_sounds = TRUE;
if (!g_getenv("CANBERRA_FORCE_EVENT_SOUNDS"))
g_object_get(G_OBJECT(s), "gtk-enable-event-sounds", &enable_event_sounds, NULL);
ca_context_change_props(c, CA_PROP_CANBERRA_ENABLE, enable_event_sounds ? "1" : "0", NULL);
}
static void sound_theme_name_changed(GtkSettings *s, GParamSpec *arg1, ca_context *c) {
read_sound_theme_name(c, s);
}
static void enable_event_sounds_changed(GtkSettings *s, GParamSpec *arg1, ca_context *c) {
read_enable_event_sounds(c, s);
}
/**
* ca_gtk_context_get:
*
* Gets the single ca_context object for the default screen. See
* ca_gtk_context_get_for_screen().
*
* Returns: a ca_context object. The object is owned by libcanberra-gtk
* and must not be destroyed
*/
ca_context *ca_gtk_context_get(void) {
return ca_gtk_context_get_for_screen(NULL);
}
/**
* ca_gtk_context_get_for_screen:
* @screen: the #GdkScreen to get the context for, or %NULL to use
* the default screen
*
* libcanberra-gtk maintains a single ca_context object for each
* #GdkScreen. Use this function to access it. The
* %CA_PROP_CANBERRA_XDG_THEME_NAME of this context property is
* dynamically bound to the XSETTINGS setting for the XDG theme
* name. CA_PROP_APPLICATION_NAME is bound to
* g_get_application_name().
*
* Returns: a ca_context object. The object is owned by libcanberra-gtk
* and must not be destroyed
*
* Since: 0.13
*/
ca_context *ca_gtk_context_get_for_screen(GdkScreen *screen) {
ca_context *c = NULL;
ca_proplist *p = NULL;
const char *name;
GtkSettings *s;
if (!screen)
screen = gdk_screen_get_default();
if ((c = g_object_get_data(G_OBJECT(screen), "canberra::gtk::context")))
return c;
if (ca_context_create(&c) != CA_SUCCESS)
return NULL;
if (ca_proplist_create(&p) != CA_SUCCESS) {
ca_context_destroy(c);
return NULL;
}
if ((name = g_get_application_name()))
ca_proplist_sets(p, CA_PROP_APPLICATION_NAME, name);
else {
ca_proplist_sets(p, CA_PROP_APPLICATION_NAME, "libcanberra-gtk");
ca_proplist_sets(p, CA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
ca_proplist_sets(p, CA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra.gtk");
}
if ((name = gtk_window_get_default_icon_name()))
ca_proplist_sets(p, CA_PROP_APPLICATION_ICON_NAME, name);
if ((name = gdk_display_get_name(gdk_screen_get_display(screen))))
ca_proplist_sets(p, CA_PROP_WINDOW_X11_DISPLAY, name);
ca_proplist_setf(p, CA_PROP_WINDOW_X11_SCREEN, "%i", gdk_screen_get_number(screen));
ca_context_change_props_full(c, p);
ca_proplist_destroy(p);
if ((s = gtk_settings_get_for_screen(screen))) {
if (g_object_class_find_property(G_OBJECT_GET_CLASS(s), "gtk-sound-theme-name")) {
g_signal_connect(G_OBJECT(s), "notify::gtk-sound-theme-name", G_CALLBACK(sound_theme_name_changed), c);
read_sound_theme_name(c, s);
} else
g_debug("This Gtk+ version doesn't have the GtkSettings::gtk-sound-theme-name property.");
if (g_object_class_find_property(G_OBJECT_GET_CLASS(s), "gtk-enable-event-sounds")) {
g_signal_connect(G_OBJECT(s), "notify::gtk-enable-event-sounds", G_CALLBACK(enable_event_sounds_changed), c);
read_enable_event_sounds(c, s);
} else
g_debug("This Gtk+ version doesn't have the GtkSettings::gtk-enable-event-sounds property.");
}
g_object_set_data_full(G_OBJECT(screen), "canberra::gtk::context", c, (GDestroyNotify) ca_context_destroy);
return c;
}
static GtkWindow* get_toplevel(GtkWidget *w) {
if (!(w = gtk_widget_get_toplevel(w)))
return NULL;
if (!GTK_IS_WINDOW(w))
return NULL;
return GTK_WINDOW(w);
}
static gint window_get_desktop(GdkDisplay *d, GdkWindow *w) {
Atom type_return;
gint format_return;
gulong nitems_return;
gulong bytes_after_return;
guchar *data = NULL;
gint ret = -1;
#ifdef GDK_IS_X11_DISPLAY
if (!GDK_IS_X11_DISPLAY(d))
return 0;
#endif
if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w),
gdk_x11_get_xatom_by_name_for_display(d, "_NET_WM_DESKTOP"),
0, G_MAXLONG, False, XA_CARDINAL, &type_return,
&format_return, &nitems_return, &bytes_after_return,
&data) != Success)
return -1;
if (type_return == XA_CARDINAL && format_return == 32 && data) {
guint32 desktop = *(guint32*) data;
if (desktop != 0xFFFFFFFF)
ret = (gint) desktop;
}
if (type_return != None && data != NULL)
XFree(data);
return ret;
}
/**
* ca_gtk_proplist_set_for_widget:
* @p: The proplist to store these sound event properties in
* @w: The Gtk widget to base these sound event properties on
*
* Fill in a ca_proplist object for a sound event that shall originate
* from the specified Gtk Widget. This will fill in properties like
* %CA_PROP_WINDOW_NAME or %CA_PROP_WINDOW_X11_DISPLAY for you.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *widget) {
GtkWindow *w;
int ret;
const char *t, *role;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(widget, CA_ERROR_INVALID);
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
if (!(w = get_toplevel(widget)))
return CA_ERROR_INVALID;
if ((t = gtk_window_get_title(w)))
if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_NAME, t)) < 0)
return ret;
if ((role = gtk_window_get_role(w))) {
if (role && t) {
char *id = ca_sprintf_malloc("%s#%s", t, role);
if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_ID, id)) < 0) {
ca_free(id);
return ret;
}
ca_free(id);
}
} else if (t)
if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_ID, t)) < 0)
return ret;
if ((t = gtk_window_get_icon_name(w)))
if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_ICON_NAME, t)) < 0)
return ret;
if (gtk_widget_get_realized(GTK_WIDGET(w))) {
GdkWindow *dw = NULL;
GdkScreen *screen = NULL;
GdkDisplay *display = NULL;
gint x = -1, y = -1, width = -1, height = -1, screen_width = -1, screen_height = -1;
if ((dw = gtk_widget_get_window(GTK_WIDGET(w))))
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X11_XID, "%lu", (unsigned long) GDK_WINDOW_XID(dw))) < 0)
return ret;
if ((display = gtk_widget_get_display(GTK_WIDGET(w)))) {
if ((t = gdk_display_get_name(display)))
if ((ret = ca_proplist_sets(p, CA_PROP_WINDOW_X11_DISPLAY, t)) < 0)
return ret;
if (dw) {
gint desktop = window_get_desktop(display, dw);
if (desktop >= 0)
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_DESKTOP, "%i", desktop)) < 0)
return ret;
}
}
if ((screen = gtk_widget_get_screen(GTK_WIDGET(w)))) {
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X11_SCREEN, "%i", gdk_screen_get_number(screen))) < 0)
return ret;
if (dw)
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X11_MONITOR, "%i", gdk_screen_get_monitor_at_window(screen, dw))) < 0)
return ret;
}
/* FIXME, this might cause a round trip */
if (dw) {
gdk_window_get_origin(dw, &x, &y);
if (x >= 0)
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_X, "%i", x)) < 0)
return ret;
if (y >= 0)
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_Y, "%i", y)) < 0)
return ret;
}
gtk_window_get_size(w, &width, &height);
if (width > 0)
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_WIDTH, "%i", width)) < 0)
return ret;
if (height > 0)
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_HEIGHT, "%i", height)) < 0)
return ret;
if (x >= 0 && width > 0) {
screen_width = gdk_screen_get_width(gtk_widget_get_screen(GTK_WIDGET(w)));
x += width/2;
x = CA_CLAMP(x, 0, screen_width-1);
/* We use these strange format strings here to avoid that libc
* applies locale information on the formatting of floating
* numbers. */
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_HPOS, "%i.%03i",
(int) (x/(screen_width-1)), (int) (1000.0*x/(screen_width-1)) % 1000)) < 0)
return ret;
}
if (y >= 0 && height > 0) {
screen_height = gdk_screen_get_height(gtk_widget_get_screen(GTK_WIDGET(w)));
y += height/2;
y = CA_CLAMP(y, 0, screen_height-1);
if ((ret = ca_proplist_setf(p, CA_PROP_WINDOW_VPOS, "%i.%03i",
(int) (y/(screen_height-1)), (int) (1000.0*y/(screen_height-1)) % 1000)) < 0)
return ret;
}
}
return CA_SUCCESS;
}
/**
* ca_gtk_proplist_set_for_event:
* @p: The proplist to store these sound event properties in
* @e: The Gdk event to base these sound event properties on
*
* Fill in a ca_proplist object for a sound event that is being
* triggered by the specified Gdk Event. This will fill in properties
* like %CA_PROP_EVENT_MOUSE_X or %CA_PROP_EVENT_MOUSE_BUTTON for
* you. This will internally also cal ca_gtk_proplist_set_for_widget()
* on the widget this event belongs to.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e) {
gdouble x, y;
GdkWindow *gw;
GtkWidget *w = NULL;
int ret;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(e, CA_ERROR_INVALID);
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
if ((gw = e->any.window)) {
gdk_window_get_user_data(gw, (gpointer*) &w);
if (w)
if ((ret = ca_gtk_proplist_set_for_widget(p, w)) < 0)
return ret;
}
if (gdk_event_get_root_coords(e, &x, &y)) {
if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_X, "%0.0f", x)) < 0)
return ret;
if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_Y, "%0.0f", y)) < 0)
return ret;
if (w) {
int width, height;
width = gdk_screen_get_width(gtk_widget_get_screen(w));
height = gdk_screen_get_height(gtk_widget_get_screen(w));
/* We use these strange format strings here to avoid that
* libc applies locale information on the formatting of
* floating numbers. */
if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_HPOS, "%i.%03i",
(int) (x/(width-1)), (int) (1000.0*x/(width-1)) % 1000)) < 0)
return ret;
if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_VPOS, "%i.%03i",
(int) (y/(height-1)), (int) (1000.0*y/(height-1)) % 1000)) < 0)
return ret;
}
}
if (e->type == GDK_BUTTON_PRESS ||
e->type == GDK_2BUTTON_PRESS ||
e->type == GDK_3BUTTON_PRESS ||
e->type == GDK_BUTTON_RELEASE) {
if ((ret = ca_proplist_setf(p, CA_PROP_EVENT_MOUSE_BUTTON, "%u", e->button.button)) < 0)
return ret;
}
return CA_SUCCESS;
}
/**
* ca_gtk_play_for_widget:
* @w: The Gtk widget to base these sound event properties on
* @id: The event id that can later be used to cancel this event sound
* using ca_context_cancel(). This can be any integer and shall be
* chosen be the client program. It is a good idea to pass 0 here if
* cancelling the sound later is not needed. If the same id is passed
* to multiple sounds they can be canceled with a single
* ca_context_cancel() call.
* @...: additional event properties as pairs of strings, terminated by NULL.
*
* Play a sound event for the specified widget. This will internally
* call ca_gtk_proplist_set_for_widget() and then merge them with the
* properties passed in via the NULL terminated argument
* list. Finally, it will call ca_context_play_full() to actually play
* the event sound.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) {
va_list ap;
int ret;
ca_proplist *p;
GdkScreen *s;
ca_return_val_if_fail(w, CA_ERROR_INVALID);
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
if ((ret = ca_proplist_create(&p)) < 0)
return ret;
if ((ret = ca_gtk_proplist_set_for_widget(p, w)) < 0)
goto fail;
va_start(ap, id);
ret = ca_proplist_merge_ap(p, ap);
va_end(ap);
if (ret < 0)
goto fail;
s = gtk_widget_get_screen(w);
ret = ca_context_play_full(ca_gtk_context_get_for_screen(s), id, p, NULL, NULL);
fail:
ca_assert_se(ca_proplist_destroy(p) == 0);
return ret;
}
/**
* ca_gtk_play_for_event:
* @e: The Gdk event to base these sound event properties on
* @id: The event id that can later be used to cancel this event sound
* using ca_context_cancel(). This can be any integer and shall be
* chosen be the client program. It is a good idea to pass 0 here if
* cancelling the sound later is not needed. If the same id is passed
* to multiple sounds they can be canceled with a single
* ca_context_cancel() call.
* @...: additional event properties as pairs of strings, terminated by NULL.
*
* Play a sound event for the specified event. This will internally
* call ca_gtk_proplist_set_for_event() and then merge them with the
* properties passed in via the NULL terminated argument
* list. Finally, it will call ca_context_play_full() to actually play
* the event sound.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_gtk_play_for_event(GdkEvent *e, uint32_t id, ...) {
va_list ap;
int ret;
ca_proplist *p;
GdkScreen *s;
ca_return_val_if_fail(e, CA_ERROR_INVALID);
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
if ((ret = ca_proplist_create(&p)) < 0)
return ret;
if ((ret = ca_gtk_proplist_set_for_event(p, e)) < 0)
goto fail;
va_start(ap, id);
ret = ca_proplist_merge_ap(p, ap);
va_end(ap);
if (ret < 0)
goto fail;
if (e->any.window)
#if GTK_CHECK_VERSION (2, 90, 7)
s = gdk_window_get_screen(e->any.window);
#else
s = gdk_drawable_get_screen(GDK_DRAWABLE(e->any.window));
#endif
else
s = gdk_screen_get_default();
ret = ca_context_play_full(ca_gtk_context_get_for_screen(s), id, p, NULL, NULL);
fail:
ca_assert_se(ca_proplist_destroy(p) == 0);
return ret;
}
/**
* ca_gtk_widget_disable_sounds:
* @w: The Gtk widget to disable automatic event sounds for.
* @enable: Boolean specifying whether sound events shall be enabled or disabled for this widget.
*
* By default sound events are automatically generated for all kinds
* of input events. Use this function to disable this. This is
* intended to be used for widgets which directly generate sound
* events.
*/
void ca_gtk_widget_disable_sounds(GtkWidget *w, gboolean enable) {
static GQuark disable_sound_quark = 0;
/* This is the same quark used by libgnomeui! */
if (!disable_sound_quark)
disable_sound_quark = g_quark_from_static_string("gnome_disable_sound_events");
g_object_set_qdata(G_OBJECT(w), disable_sound_quark, GINT_TO_POINTER(!!enable));
}
07070100000022000081A4000000000000000000000001509D8F3700000599000000000000000000000000000000000000002600000000libcanberra-0.30+2/src/canberra-gtk.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberragtkhfoo
#define foocanberragtkhfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <canberra.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#ifndef GDK_MULTIHEAD_SAFE
ca_context *ca_gtk_context_get(void);
#endif
ca_context *ca_gtk_context_get_for_screen(GdkScreen *screen);
int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *w);
int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) G_GNUC_NULL_TERMINATED;
int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e);
int ca_gtk_play_for_event(GdkEvent *e, uint32_t id, ...) G_GNUC_NULL_TERMINATED;
void ca_gtk_widget_disable_sounds(GtkWidget *w, gboolean enable);
G_END_DECLS
#endif
07070100000023000081A4000000000000000000000001509D8F37000001EB000000000000000000000000000000000000003900000000libcanberra-0.30+2/src/canberra-system-bootup.service.in[Unit]
Description=Play Bootup Sound
DefaultDependencies=no
After=alsa-restore.service
Before=shutdown.target
Conflicts=shutdown.target
# A little optimization under the assumption that we are using the
# standard freedesktop theme
ConditionPathExists=/usr/share/sounds/freedesktop/stereo/system-bootup.oga
[Service]
Type=oneshot
ExecStart=-@bindir@/canberra-boot system-bootup
[Install]
WantedBy=sound.target
Also=canberra-system-shutdown.service canberra-system-shutdown-reboot.service
07070100000024000081A4000000000000000000000001509D8F37000001FD000000000000000000000000000000000000004200000000libcanberra-0.30+2/src/canberra-system-shutdown-reboot.service.in[Unit]
Description=Play Reboot Sound
DefaultDependencies=no
Before=shutdown.target
# A little optimization under the assumption that we are using the
# standard freedesktop theme
ConditionPathExists=|/usr/share/sounds/freedesktop/stereo/system-shutdown.oga
ConditionPathExists=|/usr/share/sounds/freedesktop/stereo/system-shutdown-reboot.oga
[Service]
Type=oneshot
ExecStart=-@bindir@/canberra-boot system-shutdown-reboot
[Install]
WantedBy=reboot.target kexec.target
Also=canberra-system-shutdown.service
07070100000025000081A4000000000000000000000001509D8F37000001D2000000000000000000000000000000000000003B00000000libcanberra-0.30+2/src/canberra-system-shutdown.service.in[Unit]
Description=Play Shutdown Sound
DefaultDependencies=no
Before=shutdown.target
# A little optimization under the assumption that we are using the
# standard freedesktop theme
ConditionPathExists=/usr/share/sounds/freedesktop/stereo/system-shutdown.oga
[Service]
Type=oneshot
ExecStart=-@bindir@/canberra-boot system-shutdown
[Install]
WantedBy=halt.target poweroff.target
Also=canberra-system-shutdown-reboot.service canberra-system-shutdown-reboot.service
07070100000026000081A4000000000000000000000001509D8F3700004605000000000000000000000000000000000000002500000000libcanberra-0.30+2/src/canberra.h.in/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberrahfoo
#define foocanberrahfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <sys/types.h>
#include <sys/param.h>
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __GNUC__
/* Make sure __attribute__ works on non-gcc systems. Yes, might be a bit ugly */
#define __attribute__(x)
#endif
/**
* CA_MAJOR:
*
* Evaluates to the major version number of libcanberra.
*/
#define CA_MAJOR (@CA_MAJOR@)
/**
* CA_MINOR:
*
* Evaluates to the minor version number of libcanberra.
*/
#define CA_MINOR (@CA_MINOR@)
/**
* CA_CHECK_VERSION:
*
* Evaluates to TRUE when the library version is newer than the
* specified parameters.
*/
#define CA_CHECK_VERSION(major,minor) \
((CA_MAJOR > (major)) || \
(CA_MAJOR == (major) && CA_MINOR >= (minor)))
/**
* CA_PROP_MEDIA_NAME:
*
* A name describing the media being played. Localized if possible and applicable.
*/
#define CA_PROP_MEDIA_NAME "media.name"
/**
* CA_PROP_MEDIA_TITLE:
*
* A (song) title describing the media being played. Localized if possible and applicable.
*/
#define CA_PROP_MEDIA_TITLE "media.title"
/**
* CA_PROP_MEDIA_ARTIST:
*
* The artist of this media. Localized if possible and applicable.
*/
#define CA_PROP_MEDIA_ARTIST "media.artist"
/**
* CA_PROP_MEDIA_LANGUAGE:
*
* The language this media is in, in some standard POSIX locale string, such as "de_DE".
*/
#define CA_PROP_MEDIA_LANGUAGE "media.language"
/**
* CA_PROP_MEDIA_FILENAME:
*
* The file name this media was or can be loaded from.
*/
#define CA_PROP_MEDIA_FILENAME "media.filename"
/**
* CA_PROP_MEDIA_ICON:
*
* An icon for this media in binary PNG format.
*/
#define CA_PROP_MEDIA_ICON "media.icon"
/**
* CA_PROP_MEDIA_ICON_NAME:
*
* An icon name as defined in the XDG icon naming specifcation.
*/
#define CA_PROP_MEDIA_ICON_NAME "media.icon_name"
/**
* CA_PROP_MEDIA_ROLE:
*
* The "role" this media is played in. For event sounds the string
* "event". For other cases strings like "music", "video", "game", ...
*/
#define CA_PROP_MEDIA_ROLE "media.role"
/**
* CA_PROP_EVENT_ID:
*
* A textual id for an event sound, as mandated by the XDG sound naming specification.
*/
#define CA_PROP_EVENT_ID "event.id"
/**
* CA_PROP_EVENT_DESCRIPTION:
*
* A descriptive string for the sound event. Localized if possible and applicable.
*/
#define CA_PROP_EVENT_DESCRIPTION "event.description"
/**
* CA_PROP_EVENT_MOUSE_X:
*
* If this sound event was triggered by a mouse input event, the X
* position of the mouse cursor on the screen, formatted as string.
*/
#define CA_PROP_EVENT_MOUSE_X "event.mouse.x"
/**
* CA_PROP_EVENT_MOUSE_Y:
*
* If this sound event was triggered by a mouse input event, the Y
* position of the mouse cursor on the screen, formatted as string.
*/
#define CA_PROP_EVENT_MOUSE_Y "event.mouse.y"
/**
* CA_PROP_EVENT_MOUSE_HPOS:
*
* If this sound event was triggered by a mouse input event, the X
* position of the mouse cursor as fractional value between 0 and 1,
* formatted as string, 0 reflecting the left side of the screen, 1
* the right side.
*/
#define CA_PROP_EVENT_MOUSE_HPOS "event.mouse.hpos"
/**
* CA_PROP_EVENT_MOUSE_VPOS:
*
* If this sound event was triggered by a mouse input event, the Y
* position of the mouse cursor as fractional value between 0 and 1,
* formatted as string, 0 reflecting the top end of the screen, 1
* the bottom end.
*/
#define CA_PROP_EVENT_MOUSE_VPOS "event.mouse.vpos"
/**
* CA_PROP_EVENT_MOUSE_BUTTON:
*
* If this sound event was triggered by a mouse input event, the
* number of the mouse button that triggered it, formatted as string. 1
* for left mouse button, 3 for right, 2 for middle.
*/
#define CA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button"
/**
* CA_PROP_WINDOW_NAME:
*
* If this sound event was triggered by a window on the screen, the
* name of this window as human readable string.
*/
#define CA_PROP_WINDOW_NAME "window.name"
/**
* CA_PROP_WINDOW_ID:
*
* If this sound event was triggered by a window on the screen, some
* identification string for this window, so that the sound system can
* recognize specific windows.
*/
#define CA_PROP_WINDOW_ID "window.id"
/**
* CA_PROP_WINDOW_ICON:
*
* If this sound event was triggered by a window on the screen, binary
* icon data in PNG format for this window.
*/
#define CA_PROP_WINDOW_ICON "window.icon"
/**
* CA_PROP_WINDOW_ICON_NAME:
*
* If this sound event was triggered by a window on the screen, an
* icon name for this window, as defined in the XDG icon naming
* specification.
*/
#define CA_PROP_WINDOW_ICON_NAME "window.icon_name"
/**
* CA_PROP_WINDOW_X:
*
* If this sound event was triggered by a window on the screen, the X
* position of the window measured from the top left corner of the
* screen to the top left corner of the window.
*
* Since: 0.17
*/
#define CA_PROP_WINDOW_X "window.x"
/**
* CA_PROP_WINDOW_Y:
*
* If this sound event was triggered by a window on the screen, the y
* position of the window measured from the top left corner of the
* screen to the top left corner of the window.
*
* Since: 0.17
*/
#define CA_PROP_WINDOW_Y "window.y"
/**
* CA_PROP_WINDOW_WIDTH:
*
* If this sound event was triggered by a window on the screen, the
* pixel width of the window.
*
* Since: 0.17
*/
#define CA_PROP_WINDOW_WIDTH "window.width"
/**
* CA_PROP_WINDOW_HEIGHT:
*
* If this sound event was triggered by a window on the screen, the
* pixel height of the window.
*
* Since: 0.17
*/
#define CA_PROP_WINDOW_HEIGHT "window.height"
/**
* CA_PROP_WINDOW_HPOS:
*
* If this sound event was triggered by a window on the screen, the X
* position of the center of the window as fractional value between 0
* and 1, formatted as string, 0 reflecting the left side of the
* screen, 1 the right side.
*
* Since: 0.17
*/
#define CA_PROP_WINDOW_HPOS "window.hpos"
/**
* CA_PROP_WINDOW_VPOS:
*
* If this sound event was triggered by a window on the screen, the Y
* position of the center of the window as fractional value between 0
* and 1, formatted as string, 0 reflecting the top side of the
* screen, 1 the bottom side.
*
* Since: 0.17
*/
#define CA_PROP_WINDOW_VPOS "window.vpos"
/**
* CA_PROP_WINDOW_DESKTOP:
*
* If this sound event was triggered by a window on the screen and the
* windowing system supports multiple desktops, a comma seperated list
* of indexes of the desktops this window is visible on. If this
* property is an empty string, it is visible on all desktops
* (i.e. 'sticky'). The first desktop is 0. (e.g. "0,2,3")
*
* Since: 0.18
*/
#define CA_PROP_WINDOW_DESKTOP "window.desktop"
/**
* CA_PROP_WINDOW_X11_DISPLAY:
*
* If this sound event was triggered by a window on the screen and the
* windowing system is X11, the X display name of the window (e.g. ":0").
*/
#define CA_PROP_WINDOW_X11_DISPLAY "window.x11.display"
/**
* CA_PROP_WINDOW_X11_SCREEN:
*
* If this sound event was triggered by a window on the screen and the
* windowing system is X11, the X screen id of the window formatted as
* string (e.g. "0").
*/
#define CA_PROP_WINDOW_X11_SCREEN "window.x11.screen"
/**
* CA_PROP_WINDOW_X11_MONITOR:
*
* If this sound event was triggered by a window on the screen and the
* windowing system is X11, the X monitor id of the window formatted as
* string (e.g. "0").
*/
#define CA_PROP_WINDOW_X11_MONITOR "window.x11.monitor"
/**
* CA_PROP_WINDOW_X11_XID:
*
* If this sound event was triggered by a window on the screen and the
* windowing system is X11, the XID of the window formatted as string.
*/
#define CA_PROP_WINDOW_X11_XID "window.x11.xid"
/**
* CA_PROP_APPLICATION_NAME:
*
* The name of the application this sound event was triggered by as
* human readable string. (e.g. "GNU Emacs") Localized if possible and
* applicable.
*/
#define CA_PROP_APPLICATION_NAME "application.name"
/**
* CA_PROP_APPLICATION_ID:
*
* An identifier for the program this sound event was triggered
* by. (e.g. "org.gnu.emacs").
*/
#define CA_PROP_APPLICATION_ID "application.id"
/**
* CA_PROP_APPLICATION_VERSION:
*
* A version number for the program this sound event was triggered
* by. (e.g. "22.2")
*/
#define CA_PROP_APPLICATION_VERSION "application.version"
/**
* CA_PROP_APPLICATION_ICON:
*
* Binary icon data in PNG format for the application this sound event
* is triggered by.
*/
#define CA_PROP_APPLICATION_ICON "application.icon"
/**
* CA_PROP_APPLICATION_ICON_NAME:
*
* An icon name for the application this sound event is triggered by,
* as defined in the XDG icon naming specification.
*/
#define CA_PROP_APPLICATION_ICON_NAME "application.icon_name"
/**
* CA_PROP_APPLICATION_LANGUAGE:
*
* The locale string the application that is triggering this sound
* event is running in. A POSIX locale string such as de_DE@euro.
*/
#define CA_PROP_APPLICATION_LANGUAGE "application.language"
/**
* CA_PROP_APPLICATION_PROCESS_ID:
*
* The unix PID of the process that is triggering this sound event, formatted as string.
*/
#define CA_PROP_APPLICATION_PROCESS_ID "application.process.id"
/**
* CA_PROP_APPLICATION_PROCESS_BINARY:
*
* The path to the process binary of the process that is triggering this sound event.
*/
#define CA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary"
/**
* CA_PROP_APPLICATION_PROCESS_USER:
*
* The user that owns the process that is triggering this sound event.
*/
#define CA_PROP_APPLICATION_PROCESS_USER "application.process.user"
/**
* CA_PROP_APPLICATION_PROCESS_HOST:
*
* The host name of the host the process that is triggering this sound event runs on.
*/
#define CA_PROP_APPLICATION_PROCESS_HOST "application.process.host"
/**
* CA_PROP_CANBERRA_CACHE_CONTROL:
*
* A special property that can be used to control the automatic sound
* caching of sounds in the sound server. One of "permanent",
* "volatile", "never". "permanent" will cause this sample to be
* cached in the server permanently. This is useful for very
* frequently used sound events such as those used for input
* feedback. "volatile" may be used for cacheing sounds in the sound
* server temporarily. They will expire after some time or on cache
* pressure. Finally, "never" may be used for sounds that should never
* be cached, because they are only generated very seldomly or even
* only once at most (such as desktop login sounds).
*
* If this property is not explicitly passed to ca_context_play() it
* will default to "never". If it is not explicitly passed to
* ca_context_cache() it will default to "permanent".
*
* If the list of properties is handed on to the sound server this
* property is stripped from it.
*/
#define CA_PROP_CANBERRA_CACHE_CONTROL "canberra.cache-control"
/**
* CA_PROP_CANBERRA_VOLUME:
*
* A special property that can be used to control the volume this
* sound event is played in if the backend supports it. A floating
* point value for the decibel multiplier for the sound. 0 dB relates
* to zero gain, and is the default volume these sounds are played in.
*
* If the list of properties is handed on to the sound server this
* property is stripped from it.
*/
#define CA_PROP_CANBERRA_VOLUME "canberra.volume"
/**
* CA_PROP_CANBERRA_XDG_THEME_NAME:
*
* A special property that can be used to control the XDG sound theme that
* is used for this sample.
*
* If the list of properties is handed on to the sound server this
* property is stripped from it.
*/
#define CA_PROP_CANBERRA_XDG_THEME_NAME "canberra.xdg-theme.name"
/**
* CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE:
*
* A special property that can be used to control the XDG sound theme
* output profile that is used for this sample.
*
* If the list of properties is handed on to the sound server this
* property is stripped from it.
*/
#define CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE "canberra.xdg-theme.output-profile"
/**
* CA_PROP_CANBERRA_ENABLE:
*
* A special property that can be used to control whether any sounds
* are played at all. If this property is "1" or unset sounds are
* played as normal. However, if it is "0" all calls to
* ca_context_play() will fail with CA_ERROR_DISABLED.
*
* If the list of properties is handed on to the sound server this
* property is stripped from it.
*/
#define CA_PROP_CANBERRA_ENABLE "canberra.enable"
/**
* CA_PROP_CANBERRA_FORCE_CHANNEL:
*
* A special property that can be used to control on which channel a
* sound is played. The value should be one of mono, front-left,
* front-right, front-center, rear-left, rear-right, rear-center, lfe,
* front-left-of-center, front-right-of-center, side-left, side-right,
* top-center, top-front-left, top-front-right, top-front-center,
* top-rear-left, top-rear-right, top-rear-center. This property is
* only honoured by some backends, other backends may choose to ignore
* it completely.
*
* If the list of properties is handed on to the sound server this
* property is stripped from it.
*
* Since: 0.13
*/
#define CA_PROP_CANBERRA_FORCE_CHANNEL "canberra.force_channel"
/**
* ca_context:
*
* A libcanberra context object.
*/
typedef struct ca_context ca_context;
/**
* ca_finish_callback_t:
* @c: The libcanberra context this callback is called for
* @id: The numerical id passed to the ca_context_play_full() when starting the event sound playback.
* @error_code: A numerical error code describing the reason this callback is called. If CA_SUCCESS is passed in the playback of the event sound was successfully completed.
* @userdata: Some arbitrary user data the caller of ca_context_play_full() passed in.
*
* Playback completion event callback. The context this callback is
* called in is undefined, it might or might not be called from a
* background thread, and from any stack frame. The code implementing
* this function may not call any libcanberra API call from this
* callback -- this might result in a deadlock. Instead it may only be
* used to asynchronously signal some kind of notification object
* (semaphore, message queue, ...).
*/
typedef void (*ca_finish_callback_t)(ca_context *c, uint32_t id, int error_code, void *userdata);
/**
* Error codes:
* @CA_SUCCESS: Success
*
* Error codes
*/
enum {
CA_SUCCESS = 0,
CA_ERROR_NOTSUPPORTED = -1,
CA_ERROR_INVALID = -2,
CA_ERROR_STATE = -3,
CA_ERROR_OOM = -4,
CA_ERROR_NODRIVER = -5,
CA_ERROR_SYSTEM = -6,
CA_ERROR_CORRUPT = -7,
CA_ERROR_TOOBIG = -8,
CA_ERROR_NOTFOUND = -9,
CA_ERROR_DESTROYED = -10,
CA_ERROR_CANCELED = -11,
CA_ERROR_NOTAVAILABLE = -12,
CA_ERROR_ACCESS = -13,
CA_ERROR_IO = -14,
CA_ERROR_INTERNAL = -15,
CA_ERROR_DISABLED = -16,
CA_ERROR_FORKED = -17,
CA_ERROR_DISCONNECTED = -18,
_CA_ERROR_MAX = -19
};
/**
* ca_proplist:
*
* A canberra property list object. Basically a hashtable.
*/
typedef struct ca_proplist ca_proplist;
int ca_proplist_create(ca_proplist **p);
int ca_proplist_destroy(ca_proplist *p);
int ca_proplist_sets(ca_proplist *p, const char *key, const char *value);
int ca_proplist_setf(ca_proplist *p, const char *key, const char *format, ...) __attribute__((format(printf, 3, 4)));
int ca_proplist_set(ca_proplist *p, const char *key, const void *data, size_t nbytes);
int ca_context_create(ca_context **c);
int ca_context_set_driver(ca_context *c, const char *driver);
int ca_context_change_device(ca_context *c, const char *device);
int ca_context_open(ca_context *c);
int ca_context_destroy(ca_context *c);
int ca_context_change_props(ca_context *c, ...) __attribute__((sentinel));
int ca_context_change_props_full(ca_context *c, ca_proplist *p);
int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata);
int ca_context_play(ca_context *c, uint32_t id, ...) __attribute__((sentinel));
int ca_context_cache_full(ca_context *c, ca_proplist *p);
int ca_context_cache(ca_context *c, ...) __attribute__((sentinel));
int ca_context_cancel(ca_context *c, uint32_t id);
int ca_context_playing(ca_context *c, uint32_t id, int *playing);
const char *ca_strerror(int code);
#ifdef __cplusplus
}
#endif
#endif
07070100000027000081A4000000000000000000000001509D8F3700005FA3000000000000000000000000000000000000002000000000libcanberra-0.30+2/src/common.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdarg.h>
#include "canberra.h"
#include "common.h"
#include "malloc.h"
#include "driver.h"
#include "proplist.h"
#include "macro.h"
#include "fork-detect.h"
/**
* SECTION:canberra
* @short_description: General libcanberra API
*
* libcanberra defines a simple abstract interface for playing event sounds.
*
* libcanberra relies on the XDG sound naming specification for
* identifying event sounds. On Unix/Linux the right sound to play is
* found via the mechanisms defined in the XDG sound themeing
* specification. On other systems the XDG sound name is translated to
* the native sound id for the operating system.
*
* An event sound is triggered via libcanberra by calling the
* ca_context_play() function on a previously created ca_context
* object. The ca_context_play() takes a list of key-value pairs that
* describe the event sound to generate as closely as possible. The
* most important property is %CA_PROP_EVENT_ID which defines the XDG
* sound name for the sound to play.
*
* libcanberra is not a generic event abstraction system. It's only
* purpose is playing sounds -- however in a very elaborate way. As
* much information about the context the sound is triggered from
* shall be supplied to the sound system as possible, so that it can
* replace the sound with some other kind of feedback for a11y
* cases. Also this additional information can be used to enhance user
* experience (e.g. by positioning sounds in space depending on the
* place on the screen the sound was triggered from, and similar
* uses).
*
* The set of properties defined for event sounds is extensible and
* shared with other audio systems, such as PulseAudio. Some of
* the properties that may be set are specific to an application, to a
* window, to an input event or to the media being played back.
*
* The user can attach a set of properties to the context itself,
* which is than automatically inherited by each sample being played
* back. (ca_context_change_props()).
*
* Some of the properties can be filled in by libcanberra or one of
* its backends automatically and thus need not be be filled in by the
* application (such as %CA_PROP_APPLICATION_PROCESS_ID and
* friends). However the application can always overwrite any of these
* implicit properties.
*
* libcanberra is thread-safe and OOM-safe (as far as the backend
* allows this). It is not async-signal safe.
*
* Most libcanberra functions return an integer that indicates success
* when 0 (%CA_SUCCESS) or an error when negative. In the latter case
* ca_strerror() can be used to convert this code into a human
* readable string.
*
* libcanberra property names need to be in 7bit ASCII, string
* property values UTF8.
*
* Optionally a libcanberra backend can support caching of sounds in a
* sound system. If this functionality is used, the latencies for
* event sound playback can be much smaller and fewer resources are
* needed to start playback. If a backend does not support cacheing,
* the respective functions will return an error code of
* %CA_ERROR_NOTSUPPORTED.
*
* It is highly recommended that the application sets the
* %CA_PROP_APPLICATION_NAME, %CA_PROP_APPLICATION_ID,
* %CA_PROP_APPLICATION_ICON_NAME/%CA_PROP_APPLICATION_ICON properties
* immediately after creating the ca_context, before calling
* ca_context_open() or ca_context_play().
*
* Its is highly recommended to pass at least %CA_PROP_EVENT_ID,
* %CA_PROP_EVENT_DESCRIPTION to ca_context_play() for each event
* sound generated. For sound events based on mouse inputs events
* %CA_PROP_EVENT_MOUSE_X, %CA_PROP_EVENT_MOUSE_Y, %CA_PROP_EVENT_MOUSE_HPOS,
* %CA_PROP_EVENT_MOUSE_VPOS, %CA_PROP_EVENT_MOUSE_BUTTON should be
* passed. For sound events attached to a widget on the screen, the
* %CA_PROP_WINDOW_xxx properties should be set.
*
*
*/
/**
* ca_context_create:
* @c: A pointer wheere to fill in the newly created context object.
*
* Create an (unconnected) context object. This call will not connect
* to the sound system, calling this function might even suceed if no
* working driver backend is available. To find out if one is
* available call ca_context_open().
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_create(ca_context **_c) {
ca_context *c;
int ret;
const char *d;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(_c, CA_ERROR_INVALID);
if (!(c = ca_new0(ca_context, 1)))
return CA_ERROR_OOM;
if (!(c->mutex = ca_mutex_new())) {
ca_context_destroy(c);
return CA_ERROR_OOM;
}
if ((ret = ca_proplist_create(&c->props)) < 0) {
ca_context_destroy(c);
return ret;
}
if ((d = getenv("CANBERRA_DRIVER"))) {
if ((ret = ca_context_set_driver(c, d)) < 0) {
ca_context_destroy(c);
return ret;
}
}
if ((d = getenv("CANBERRA_DEVICE"))) {
if ((ret = ca_context_change_device(c, d)) < 0) {
ca_context_destroy(c);
return ret;
}
}
*_c = c;
return CA_SUCCESS;
}
/**
* ca_context_destroy:
* @c: the context to destroy.
*
* Destroy a (connected or unconnected) context object.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_destroy(ca_context *c) {
int ret = CA_SUCCESS;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
/* There's no locking necessary here, because the application is
* broken anyway if it destructs this object in one thread and
* still is calling a method of it in another. */
if (c->opened)
ret = driver_destroy(c);
if (c->props)
ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS);
if (c->mutex)
ca_mutex_free(c->mutex);
ca_free(c->driver);
ca_free(c->device);
ca_free(c);
return ret;
}
/**
* ca_context_set_driver:
* @c: the context to change the backend driver for
* @driver: the backend driver to use (e.g. "alsa", "pulse", "null", ...)
*
* Specify the backend driver used. This function may not be called again after
* ca_context_open() suceeded. This function might suceed even when
* the specified driver backend is not available. Use
* ca_context_open() to find out whether the backend is available.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_set_driver(ca_context *c, const char *driver) {
char *n;
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex);
if (!driver)
n = NULL;
else if (!(n = ca_strdup(driver))) {
ret = CA_ERROR_OOM;
goto fail;
}
ca_free(c->driver);
c->driver = n;
ret = CA_SUCCESS;
fail:
ca_mutex_unlock(c->mutex);
return ret;
}
/**
* ca_context_change_device:
* @c: the context to change the backend device for
* @device: the backend device to use, in a format that is specific to the backend.
*
* Specify the backend device to use. This function may be called not be called after
* ca_context_open() suceeded. This function might suceed even when
* the specified driver backend is not available. Use
* ca_context_open() to find out whether the backend is available
*
* Depending on the backend use this might or might not cause all
* currently playing event sounds to be moved to the new device..
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_change_device(ca_context *c, const char *device) {
char *n;
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
if (!device)
n = NULL;
else if (!(n = ca_strdup(device))) {
ret = CA_ERROR_OOM;
goto fail;
}
ret = c->opened ? driver_change_device(c, n) : CA_SUCCESS;
if (ret == CA_SUCCESS) {
ca_free(c->device);
c->device = n;
} else
ca_free(n);
fail:
ca_mutex_unlock(c->mutex);
return ret;
}
static int context_open_unlocked(ca_context *c) {
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
if (c->opened)
return CA_SUCCESS;
if ((ret = driver_open(c)) == CA_SUCCESS)
c->opened = TRUE;
return ret;
}
/**
* ca_context_open:
* @c: the context to connect.
*
* Connect the context to the sound system. This call is implicitly
* called in ca_context_play() or ca_context_cache() if not called
* explicitly. It is recommended to initialize application properties
* with ca_context_change_props() before calling this function.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_open(ca_context *c) {
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex);
ret = context_open_unlocked(c);
ca_mutex_unlock(c->mutex);
return ret;
}
/**
* ca_context_change_props:
* @c: the context to set the properties on.
* @...: the list of string pairs for the properties. Needs to be a NULL terminated list.
*
* Write one or more string properties to the context object. Requires
* final NULL sentinel. Properties set like this will be attached to
* both the client object of the sound server and to all event sounds
* played or cached. It is recommended to call this function at least
* once before calling ca_context_open(), so that the initial
* application properties are set properly before the initial
* connection to the sound system. This function can be called both
* before and after the ca_context_open() call. Properties that have
* already been set before will be overwritten.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_change_props(ca_context *c, ...) {
va_list ap;
int ret;
ca_proplist *p = NULL;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
va_start(ap, c);
ret = ca_proplist_from_ap(&p, ap);
va_end(ap);
if (ret < 0)
return ret;
ret = ca_context_change_props_full(c, p);
ca_assert_se(ca_proplist_destroy(p) == 0);
return ret;
}
/**
* ca_context_change_props_full:
* @c: the context to set the properties on.
* @p: the property list to set.
*
* Similar to ca_context_change_props(), but takes a ca_proplist
* instead of a variable list of properties. Can be used to set binary
* properties such as %CA_PROP_APPLICATION_ICON.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_change_props_full(ca_context *c, ca_proplist *p) {
int ret;
ca_proplist *merged;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
if ((ret = ca_proplist_merge(&merged, c->props, p)) < 0)
goto finish;
ret = c->opened ? driver_change_props(c, p, merged) : CA_SUCCESS;
if (ret == CA_SUCCESS) {
ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS);
c->props = merged;
} else
ca_assert_se(ca_proplist_destroy(merged) == CA_SUCCESS);
finish:
ca_mutex_unlock(c->mutex);
return ret;
}
/**
* ca_context_play:
* @c: the context to play the event sound on
* @id: an integer id this sound can later be identified with when calling ca_context_cancel()
* @...: additional properties for this sound event.
*
* Play one event sound. id can be any numeric value which later can
* be used to cancel an event sound that is currently being
* played. You may use the same id twice or more times if you want to
* cancel multiple event sounds with a single ca_context_cancel() call
* at once. It is recommended to pass 0 for the id if the event sound
* shall never be canceled. If the requested sound is not cached in
* the server yet this call might result in the sample being uploaded
* temporarily or permanently (this may be controlled with %CA_PROP_CANBERRA_CACHE_CONTROL). This function will start playback
* in the background. It will not wait until playback
* completed. Depending on the backend used a sound that is started
* shortly before your application terminates might or might not continue to
* play after your application terminated. If you want to make sure
* that all sounds finish to play you need to wait synchronously for
* the callback function of ca_context_play_full() to be called before you
* terminate your application.
*
* The sample to play is identified by the %CA_PROP_EVENT_ID
* property. If it is already cached in the server the cached version
* is played. The properties passed in this call are merged with the
* properties supplied when the sample was cached (if applicable)
* and the context properties as set with ca_context_change_props().
*
* If %CA_PROP_EVENT_ID is not defined the sound file passed in the
* %CA_PROP_MEDIA_FILENAME is played.
*
* On Linux/Unix the right sound to play is determined according to
* %CA_PROP_EVENT_ID,
* %CA_PROP_APPLICATION_LANGUAGE/%CA_PROP_MEDIA_LANGUAGE, the system
* locale, %CA_PROP_CANBERRA_XDG_THEME_NAME and
* %CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE, following the XDG Sound
* Theming Specification. On non-Unix systems the native event sound
* that matches the XDG sound name in %CA_PROP_EVENT_ID is played.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_play(ca_context *c, uint32_t id, ...) {
int ret;
va_list ap;
ca_proplist *p = NULL;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
va_start(ap, id);
ret = ca_proplist_from_ap(&p, ap);
va_end(ap);
if (ret < 0)
return ret;
ret = ca_context_play_full(c, id, p, NULL, NULL);
ca_assert_se(ca_proplist_destroy(p) == 0);
return ret;
}
/**
* ca_context_play_full:
* @c: the context to play the event sound on
* @id: an integer id this sound can be later be identified with when calling ca_context_cancel() or when the callback is called.
* @p: A property list of properties for this event sound
* @cb: A callback to call when this sound event sucessfully finished playing or when an error occured during playback.
*
* Play one event sound, and call the specified callback function when
* completed. See ca_finish_callback_t for the semantics the callback
* is called in. Also see ca_context_play().
*
* It is guaranteed that the callback is called exactly once if
* ca_context_play_full() returns CA_SUCCESS. You thus may safely pass
* allocated memory to the callback and assume that it is freed
* properly.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) {
int ret;
const char *t;
ca_bool_t enabled = TRUE;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) ||
ca_proplist_contains(c->props, CA_PROP_EVENT_ID) ||
ca_proplist_contains(p, CA_PROP_MEDIA_FILENAME) ||
ca_proplist_contains(c->props, CA_PROP_MEDIA_FILENAME), CA_ERROR_INVALID, c->mutex);
ca_mutex_lock(c->props->mutex);
if ((t = ca_proplist_gets_unlocked(c->props, CA_PROP_CANBERRA_ENABLE)))
enabled = !ca_streq(t, "0");
ca_mutex_unlock(c->props->mutex);
ca_mutex_lock(p->mutex);
if ((t = ca_proplist_gets_unlocked(p, CA_PROP_CANBERRA_ENABLE)))
enabled = !ca_streq(t, "0");
ca_mutex_unlock(p->mutex);
ca_return_val_if_fail_unlock(enabled, CA_ERROR_DISABLED, c->mutex);
if ((ret = context_open_unlocked(c)) < 0)
goto finish;
ca_assert(c->opened);
ret = driver_play(c, id, p, cb, userdata);
finish:
ca_mutex_unlock(c->mutex);
return ret;
}
/**
*
* ca_context_cancel:
* @c: the context to cancel the sounds on
* @id: the id that identify the sounds to cancel.
*
* Cancel one or more event sounds that have been started via
* ca_context_play(). If the sound was started with
* ca_context_play_full() and a callback function was passed this
* might cause this function to be called with %CA_ERROR_CANCELED as
* error code.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_cancel(ca_context *c, uint32_t id) {
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex);
ret = driver_cancel(c, id);
ca_mutex_unlock(c->mutex);
return ret;
}
/**
* ca_context_cache:
* @c: The context to use for uploading.
* @...: The properties for this event sound. Terminated with NULL.
*
* Upload the specified sample into the audio server and attach the
* specified properties to it. This function will only return after
* the sample upload was finished.
*
* The sound to cache is found with the same algorithm that is used to
* find the sounds for ca_context_play().
*
* If the backend doesn't support caching sound samples this function
* will return %CA_ERROR_NOTSUPPORTED.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_cache(ca_context *c, ...) {
int ret;
va_list ap;
ca_proplist *p = NULL;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
va_start(ap, c);
ret = ca_proplist_from_ap(&p, ap);
va_end(ap);
if (ret < 0)
return ret;
ret = ca_context_cache_full(c, p);
ca_assert_se(ca_proplist_destroy(p) == 0);
return ret;
}
/**
* ca_context_cache_full:
* @c: The context to use for uploading.
* @p: The property list for this event sound.
*
* Upload the specified sample into the server and attach the
* specified properties to it. Similar to ca_context_cache() but takes
* a ca_proplist instead of a variable number of arguments.
*
* If the backend doesn't support caching sound samples this function
* will return CA_ERROR_NOTSUPPORTED.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_context_cache_full(ca_context *c, ca_proplist *p) {
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) ||
ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex);
if ((ret = context_open_unlocked(c)) < 0)
goto finish;
ca_assert(c->opened);
ret = driver_cache(c, p);
finish:
ca_mutex_unlock(c->mutex);
return ret;
}
/**
* ca_strerror:
* @code: Numerical error code as returned by a libcanberra API function
*
* Converts a numerical error code as returned by most libcanberra API functions into a human readable error string.
*
* Returns: a human readable error string.
*/
const char *ca_strerror(int code) {
const char * const error_table[-_CA_ERROR_MAX] = {
[-CA_SUCCESS] = "Success",
[-CA_ERROR_NOTSUPPORTED] = "Operation not supported",
[-CA_ERROR_INVALID] = "Invalid argument",
[-CA_ERROR_STATE] = "Invalid state",
[-CA_ERROR_OOM] = "Out of memory",
[-CA_ERROR_NODRIVER] = "No such driver",
[-CA_ERROR_SYSTEM] = "System error",
[-CA_ERROR_CORRUPT] = "File or data corrupt",
[-CA_ERROR_TOOBIG] = "File or data too large",
[-CA_ERROR_NOTFOUND] = "File or data not found",
[-CA_ERROR_DESTROYED] = "Destroyed",
[-CA_ERROR_CANCELED] = "Canceled",
[-CA_ERROR_NOTAVAILABLE] = "Not available",
[-CA_ERROR_ACCESS] = "Access forbidden",
[-CA_ERROR_IO] = "IO error",
[-CA_ERROR_INTERNAL] = "Internal error",
[-CA_ERROR_DISABLED] = "Sound disabled",
[-CA_ERROR_FORKED] = "Process forked",
[-CA_ERROR_DISCONNECTED] = "Disconnected"
};
ca_return_val_if_fail(code <= 0, NULL);
ca_return_val_if_fail(code > _CA_ERROR_MAX, NULL);
return error_table[-code];
}
/* Not exported */
int ca_parse_cache_control(ca_cache_control_t *control, const char *c) {
ca_return_val_if_fail(control, CA_ERROR_INVALID);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
if (ca_streq(c, "never"))
*control = CA_CACHE_CONTROL_NEVER;
else if (ca_streq(c, "permanent"))
*control = CA_CACHE_CONTROL_PERMANENT;
else if (ca_streq(c, "volatile"))
*control = CA_CACHE_CONTROL_VOLATILE;
else
return CA_ERROR_INVALID;
return CA_SUCCESS;
}
/**
* ca_context_playing:
* @c: the context to check if sound is still playing
* @id: the id that identify the sounds to check
* @playing: a pointer to a boolean that will be updated with the play status
*
* Check if at least one sound with the specified id is still
* playing. Returns 0 in *playing if no sound with this id is playing
* anymore or non-zero if there is at least one playing.
*
* Returns: 0 on success, negative error code on error.
* Since: 0.16
*/
int ca_context_playing(ca_context *c, uint32_t id, int *playing) {
int ret;
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex);
ret = driver_playing(c, id, playing);
ca_mutex_unlock(c->mutex);
return ret;
}
07070100000028000081A4000000000000000000000001509D8F3700000549000000000000000000000000000000000000002000000000libcanberra-0.30+2/src/common.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberracommonh
#define foocanberracommonh
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include "canberra.h"
#include "macro.h"
#include "mutex.h"
struct ca_context {
ca_bool_t opened;
ca_mutex *mutex;
ca_proplist *props;
char *driver;
char *device;
void *private;
#ifdef HAVE_DSO
void *private_dso;
#endif
};
typedef enum ca_cache_control {
CA_CACHE_CONTROL_NEVER,
CA_CACHE_CONTROL_PERMANENT,
CA_CACHE_CONTROL_VOLATILE
} ca_cache_control_t;
int ca_parse_cache_control(ca_cache_control_t *control, const char *c);
#endif
07070100000029000081A4000000000000000000000001509D8F3700000474000000000000000000000000000000000000002600000000libcanberra-0.30+2/src/driver-order.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "canberra.h"
#include "driver-order.h"
const char* const ca_driver_order[] = {
#ifdef HAVE_PULSE
"pulse",
#endif
#ifdef HAVE_ALSA
"alsa",
#endif
#ifdef HAVE_OSS
"oss",
#endif
#ifdef HAVE_GSTREAMER
"gstreamer",
#endif
/* ... */
NULL
};
0707010000002A000081A4000000000000000000000001509D8F3700000384000000000000000000000000000000000000002600000000libcanberra-0.30+2/src/driver-order.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberradriverorderhfoo
#define foocanberradriverorderhfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
extern const char* const ca_driver_order[];
#endif
0707010000002B000081A4000000000000000000000001509D8F370000053F000000000000000000000000000000000000002000000000libcanberra-0.30+2/src/driver.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberradriverhfoo
#define foocanberradriverhfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include "canberra.h"
int driver_open(ca_context *c);
int driver_destroy(ca_context *c);
int driver_change_device(ca_context *c, const char *device);
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged);
int driver_play(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata);
int driver_cancel(ca_context *c, uint32_t id);
int driver_cache(ca_context *c, ca_proplist *p);
int driver_playing(ca_context *c, uint32_t id, int *playing);
#endif
0707010000002C000081A4000000000000000000000001509D8F3700002EEA000000000000000000000000000000000000001D00000000libcanberra-0.30+2/src/dso.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <ltdl.h>
#include <string.h>
#include <errno.h>
#include "driver.h"
#include "common.h"
#include "malloc.h"
#include "driver-order.h"
struct private_dso {
lt_dlhandle module;
ca_bool_t ltdl_initialized;
int (*driver_open)(ca_context *c);
int (*driver_destroy)(ca_context *c);
int (*driver_change_device)(ca_context *c, const char *device);
int (*driver_change_props)(ca_context *c, ca_proplist *changed, ca_proplist *merged);
int (*driver_play)(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata);
int (*driver_cancel)(ca_context *c, uint32_t id);
int (*driver_cache)(ca_context *c, ca_proplist *p);
int (*driver_playing)(ca_context *c, uint32_t id, int *playing);
};
#define PRIVATE_DSO(c) ((struct private_dso *) ((c)->private_dso))
static int ca_error_from_lt_error(int code) {
static const int table[] = {
[LT_ERROR_UNKNOWN] = CA_ERROR_INTERNAL,
[LT_ERROR_DLOPEN_NOT_SUPPORTED] = CA_ERROR_NOTSUPPORTED,
[LT_ERROR_INVALID_LOADER] = CA_ERROR_INTERNAL,
[LT_ERROR_INIT_LOADER] = CA_ERROR_INTERNAL,
[LT_ERROR_REMOVE_LOADER] = CA_ERROR_INTERNAL,
[LT_ERROR_FILE_NOT_FOUND] = CA_ERROR_NOTFOUND,
[LT_ERROR_DEPLIB_NOT_FOUND] = CA_ERROR_NOTFOUND,
[LT_ERROR_NO_SYMBOLS] = CA_ERROR_NOTFOUND,
[LT_ERROR_CANNOT_OPEN] = CA_ERROR_ACCESS,
[LT_ERROR_CANNOT_CLOSE] = CA_ERROR_INTERNAL,
[LT_ERROR_SYMBOL_NOT_FOUND] = CA_ERROR_NOTFOUND,
[LT_ERROR_NO_MEMORY] = CA_ERROR_OOM,
[LT_ERROR_INVALID_HANDLE] = CA_ERROR_INVALID,
[LT_ERROR_BUFFER_OVERFLOW] = CA_ERROR_TOOBIG,
[LT_ERROR_INVALID_ERRORCODE] = CA_ERROR_INVALID,
[LT_ERROR_SHUTDOWN] = CA_ERROR_INTERNAL,
[LT_ERROR_CLOSE_RESIDENT_MODULE] = CA_ERROR_INTERNAL,
[LT_ERROR_INVALID_MUTEX_ARGS] = CA_ERROR_INTERNAL,
[LT_ERROR_INVALID_POSITION] = CA_ERROR_INTERNAL
#ifdef LT_ERROR_CONFLICTING_FLAGS
, [LT_ERROR_CONFLICTING_FLAGS] = CA_ERROR_INTERNAL
#endif
};
if (code < 0 || code >= (int) CA_ELEMENTSOF(table))
return CA_ERROR_INTERNAL;
return table[code];
}
static int lt_error_from_string(const char *t) {
struct lt_error_code {
int code;
const char *text;
};
static const struct lt_error_code lt_error_codes[] = {
/* This is so disgustingly ugly, it makes me vomit. But that's
* all ltdl's fault. */
#define LT_ERROR(u, s) { .code = LT_ERROR_ ## u, .text = s },
lt_dlerror_table
#undef LT_ERROR
{ .code = 0, .text = NULL }
};
const struct lt_error_code *c;
for (c = lt_error_codes; c->text; c++)
if (ca_streq(t, c->text))
return c->code;
return -1;
}
static int ca_error_from_string(const char *t) {
int err;
if ((err = lt_error_from_string(t)) < 0)
return CA_ERROR_INTERNAL;
return ca_error_from_lt_error(err);
}
static int try_open(ca_context *c, const char *t) {
char *mn;
struct private_dso *p;
p = PRIVATE_DSO(c);
if (!(mn = ca_sprintf_malloc(CA_PLUGIN_PATH "/libcanberra-%s", t)))
return CA_ERROR_OOM;
errno = 0;
p->module = lt_dlopenext(mn);
ca_free(mn);
if (!p->module) {
int ret;
if (errno == ENOENT)
ret = CA_ERROR_NOTFOUND;
else
ret = ca_error_from_string(lt_dlerror());
if (ret == CA_ERROR_NOTFOUND)
ret = CA_ERROR_NODRIVER;
return ret;
}
return CA_SUCCESS;
}
static void* real_dlsym(lt_module m, const char *name, const char *symbol) {
char sn[256];
char *s;
void *r;
ca_return_null_if_fail(m);
ca_return_null_if_fail(name);
ca_return_null_if_fail(symbol);
snprintf(sn, sizeof(sn), "%s_%s", name, symbol);
sn[sizeof(sn)-1] = 0;
for (s = sn; *s; s++) {
if (*s >= 'a' && *s <= 'z')
continue;
if (*s >= 'A' && *s <= 'Z')
continue;
if (*s >= '0' && *s <= '9')
continue;
*s = '_';
}
if ((r = lt_dlsym(m, sn)))
return r;
return lt_dlsym(m, symbol);
}
#define MAKE_FUNC_PTR(ret, args, x) ((ret (*) args ) (size_t) (x))
#define GET_FUNC_PTR(module, name, symbol, ret, args) MAKE_FUNC_PTR(ret, args, real_dlsym((module), (name), (symbol)))
int driver_open(ca_context *c) {
int ret;
struct private_dso *p;
char *driver;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!PRIVATE_DSO(c), CA_ERROR_STATE);
if (!(c->private_dso = p = ca_new0(struct private_dso, 1)))
return CA_ERROR_OOM;
if (lt_dlinit() != 0) {
ret = ca_error_from_string(lt_dlerror());
driver_destroy(c);
return ret;
}
p->ltdl_initialized = TRUE;
if (c->driver) {
char *e;
size_t n;
if (!(e = ca_strdup(c->driver))) {
driver_destroy(c);
return CA_ERROR_OOM;
}
n = strcspn(e, ",:");
e[n] = 0;
if (n == 0) {
driver_destroy(c);
ca_free(e);
return CA_ERROR_INVALID;
}
if ((ret = try_open(c, e)) < 0) {
driver_destroy(c);
ca_free(e);
return ret;
}
driver = e;
} else {
const char *const * e;
for (e = ca_driver_order; *e; e++) {
if ((ret = try_open(c, *e)) == CA_SUCCESS)
break;
if (ret != CA_ERROR_NODRIVER &&
ret != CA_ERROR_NOTAVAILABLE &&
ret != CA_ERROR_NOTFOUND) {
driver_destroy(c);
return ret;
}
}
if (!*e) {
driver_destroy(c);
return CA_ERROR_NODRIVER;
}
if (!(driver = ca_strdup(*e))) {
driver_destroy(c);
return CA_ERROR_OOM;
}
}
ca_assert(p->module);
if (!(p->driver_open = GET_FUNC_PTR(p->module, driver, "driver_open", int, (ca_context*))) ||
!(p->driver_destroy = GET_FUNC_PTR(p->module, driver, "driver_destroy", int, (ca_context*))) ||
!(p->driver_change_device = GET_FUNC_PTR(p->module, driver, "driver_change_device", int, (ca_context*, const char *))) ||
!(p->driver_change_props = GET_FUNC_PTR(p->module, driver, "driver_change_props", int, (ca_context *, ca_proplist *, ca_proplist *))) ||
!(p->driver_play = GET_FUNC_PTR(p->module, driver, "driver_play", int, (ca_context*, uint32_t, ca_proplist *, ca_finish_callback_t, void *))) ||
!(p->driver_cancel = GET_FUNC_PTR(p->module, driver, "driver_cancel", int, (ca_context*, uint32_t))) ||
!(p->driver_cache = GET_FUNC_PTR(p->module, driver, "driver_cache", int, (ca_context*, ca_proplist *))) ||
!(p->driver_playing = GET_FUNC_PTR(p->module, driver, "driver_playing", int, (ca_context*, uint32_t, int*)))) {
ca_free(driver);
driver_destroy(c);
return CA_ERROR_CORRUPT;
}
ca_free(driver);
if ((ret = p->driver_open(c)) < 0) {
p->driver_destroy = NULL;
driver_destroy(c);
return ret;
}
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
struct private_dso *p;
int ret = CA_SUCCESS;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
p = PRIVATE_DSO(c);
if (p->driver_destroy)
ret = p->driver_destroy(c);
if (p->module)
lt_dlclose(p->module);
if (p->ltdl_initialized) {
lt_dlexit();
p->ltdl_initialized = FALSE;
}
ca_free(p);
c->private_dso = NULL;
return ret;
}
int driver_change_device(ca_context *c, const char *device) {
struct private_dso *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
p = PRIVATE_DSO(c);
ca_return_val_if_fail(p->driver_change_device, CA_ERROR_STATE);
return p->driver_change_device(c, device);
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
struct private_dso *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
p = PRIVATE_DSO(c);
ca_return_val_if_fail(p->driver_change_props, CA_ERROR_STATE);
return p->driver_change_props(c, changed, merged);
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *pl, ca_finish_callback_t cb, void *userdata) {
struct private_dso *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
p = PRIVATE_DSO(c);
ca_return_val_if_fail(p->driver_play, CA_ERROR_STATE);
return p->driver_play(c, id, pl, cb, userdata);
}
int driver_cancel(ca_context *c, uint32_t id) {
struct private_dso *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
p = PRIVATE_DSO(c);
ca_return_val_if_fail(p->driver_cancel, CA_ERROR_STATE);
return p->driver_cancel(c, id);
}
int driver_cache(ca_context *c, ca_proplist *pl) {
struct private_dso *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
p = PRIVATE_DSO(c);
ca_return_val_if_fail(p->driver_cache, CA_ERROR_STATE);
return p->driver_cache(c, pl);
}
int driver_playing(ca_context *c, uint32_t id, int *playing) {
struct private_dso *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private_dso, CA_ERROR_STATE);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
p = PRIVATE_DSO(c);
ca_return_val_if_fail(p->driver_playing, CA_ERROR_STATE);
return p->driver_playing(c, id, playing);
}
0707010000002D000081A4000000000000000000000001509D8F3700000655000000000000000000000000000000000000002500000000libcanberra-0.30+2/src/fork-detect.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2009 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <sys/types.h>
#include "fork-detect.h"
int ca_detect_fork(void) {
static volatile pid_t pid = (pid_t) -1;
pid_t v, we;
/* Some really stupid applications (Hey, vim, that means you!)
* love to fork after initializing gtk/libcanberra. This is really
* bad style. We however have to deal with this cleanly, so we try
* to detect the forks making sure all our calls fail cleanly
* after the fork. */
/* Ideally we'd use atomic operations here, but we don't have them
* and this is not exactly crucial, so we don't care */
v = pid;
we = getpid();
if (v == we || v == (pid_t) -1) {
pid = we;
return 0;
}
return 1;
}
0707010000002E000081A4000000000000000000000001509D8F370000036A000000000000000000000000000000000000002500000000libcanberra-0.30+2/src/fork-detect.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberraforkdetecth
#define foocanberraforkdetecth
/***
This file is part of libcanberra.
Copyright 2009 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
int ca_detect_fork(void);
#endif
0707010000002F000081A4000000000000000000000001509D8F37000046FD000000000000000000000000000000000000002300000000libcanberra-0.30+2/src/gstreamer.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Nokia Corporation and/or its subsidiary(-ies).
Author: Marc-Andre Lureau <marc-andre.lureau@nokia.com>
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <gst/gst.h>
#include "canberra.h"
#include "common.h"
#include "driver.h"
#include "llist.h"
#include "read-sound-file.h"
#include "sound-theme-spec.h"
#include "malloc.h"
struct outstanding {
CA_LLIST_FIELDS(struct outstanding);
ca_bool_t dead;
uint32_t id;
int err;
ca_finish_callback_t callback;
void *userdata;
GstElement *pipeline;
struct ca_context *context;
};
struct private {
ca_theme_data *theme;
ca_bool_t signal_semaphore;
sem_t semaphore;
GstBus *mgr_bus;
/* Everything below protected by the outstanding_mutex */
ca_mutex *outstanding_mutex;
ca_bool_t mgr_thread_running;
ca_bool_t semaphore_allocated;
CA_LLIST_HEAD(struct outstanding, outstanding);
};
#define PRIVATE(c) ((struct private *) ((c)->private))
static void* thread_func(void *userdata);
static void send_eos_msg(struct outstanding *out, int err);
static void send_mgr_exit_msg (struct private *p);
static void outstanding_free(struct outstanding *o) {
GstBus *bus;
ca_assert(o);
if (o->pipeline) {
bus = gst_pipeline_get_bus(GST_PIPELINE (o->pipeline));
if (bus != NULL) {
gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
gst_object_unref(bus);
}
gst_object_unref(GST_OBJECT(o->pipeline));
}
ca_free(o);
}
int driver_open(ca_context *c) {
GError *error = NULL;
struct private *p;
pthread_t thread;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_INVALID);
ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "gstreamer"), CA_ERROR_NODRIVER);
gst_init_check(NULL, NULL, &error);
if (error != NULL) {
g_warning("gst_init: %s ", error->message);
g_error_free(error);
return CA_ERROR_INVALID;
}
if (!(p = ca_new0(struct private, 1)))
return CA_ERROR_OOM;
c->private = p;
if (!(p->outstanding_mutex = ca_mutex_new())) {
driver_destroy(c);
return CA_ERROR_OOM;
}
if (sem_init(&p->semaphore, 0, 0) < 0) {
driver_destroy(c);
return CA_ERROR_OOM;
}
p->semaphore_allocated = TRUE;
p->mgr_bus = gst_bus_new();
if (p->mgr_bus == NULL) {
driver_destroy(c);
return CA_ERROR_OOM;
}
gst_bus_set_flushing(p->mgr_bus, FALSE);
/* Give a reference to the bus to the mgr thread */
if (pthread_create(&thread, NULL, thread_func, p) < 0) {
driver_destroy(c);
return CA_ERROR_OOM;
}
p->mgr_thread_running = TRUE;
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
p = PRIVATE(c);
if (p->outstanding_mutex) {
ca_mutex_lock(p->outstanding_mutex);
/* Tell all player threads to terminate */
out = p->outstanding;
while (out) {
if (!out->dead)
send_eos_msg(out, CA_ERROR_DESTROYED);
out = out->next;
}
/* Now that we've sent EOS for all pending players, append a
* message to wait for the mgr thread to exit */
if (p->mgr_thread_running && p->semaphore_allocated) {
send_mgr_exit_msg(p);
p->signal_semaphore = TRUE;
while (p->mgr_thread_running) {
ca_mutex_unlock(p->outstanding_mutex);
sem_wait(&p->semaphore);
ca_mutex_lock(p->outstanding_mutex);
}
}
ca_mutex_unlock(p->outstanding_mutex);
ca_mutex_free(p->outstanding_mutex);
}
if (p->mgr_bus)
g_object_unref(p->mgr_bus);
if (p->theme)
ca_theme_data_free(p->theme);
if (p->semaphore_allocated)
sem_destroy(&p->semaphore);
ca_free(p);
/* no gst_deinit(), see doc */
return CA_SUCCESS;
}
int driver_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
return CA_SUCCESS;
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(changed, CA_ERROR_INVALID);
ca_return_val_if_fail(merged, CA_ERROR_INVALID);
ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
return CA_SUCCESS;
}
static void
send_eos_msg(struct outstanding *out, int err) {
struct private *p;
GstMessage *m;
GstStructure *s;
out->dead = TRUE;
out->err = err;
p = PRIVATE(out->context);
s = gst_structure_new("application/eos", "info", G_TYPE_POINTER, out, NULL);
m = gst_message_new_application (GST_OBJECT (out->pipeline), s);
gst_bus_post (p->mgr_bus, m);
}
static GstBusSyncReply
bus_cb(GstBus *bus, GstMessage *message, gpointer data) {
int err;
struct outstanding *out;
struct private *p;
ca_return_val_if_fail(bus, GST_BUS_DROP);
ca_return_val_if_fail(message, GST_BUS_DROP);
ca_return_val_if_fail(data, GST_BUS_DROP);
out = data;
p = PRIVATE(out->context);
switch (GST_MESSAGE_TYPE(message)) {
/* for all elements */
case GST_MESSAGE_ERROR:
err = CA_ERROR_SYSTEM;
break;
case GST_MESSAGE_EOS:
/* only respect EOS from the toplevel pipeline */
if (GST_OBJECT(out->pipeline) != GST_MESSAGE_SRC(message))
return GST_BUS_PASS;
err = CA_SUCCESS;
break;
default:
return GST_BUS_PASS;
}
/* Bin finished playback: ask the manager thread to shut it
* down, since we can't from the sync message handler */
ca_mutex_lock(p->outstanding_mutex);
if (!out->dead)
send_eos_msg(out, err);
ca_mutex_unlock(p->outstanding_mutex);
return GST_BUS_PASS;
}
struct ca_sound_file {
GstElement *fdsrc;
};
static int ca_gst_sound_file_open(ca_sound_file **_f, const char *fn) {
int fd;
ca_sound_file *f;
ca_return_val_if_fail(_f, CA_ERROR_INVALID);
ca_return_val_if_fail(fn, CA_ERROR_INVALID);
if ((fd = open(fn, O_RDONLY)) == -1)
return errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
if (!(f = ca_new0(ca_sound_file, 1))) {
close(fd);
return CA_ERROR_OOM;
}
if (!(f->fdsrc = gst_element_factory_make("fdsrc", NULL))) {
close(fd);
ca_free(f);
return CA_ERROR_OOM;
}
g_object_set(GST_OBJECT(f->fdsrc), "fd", fd, NULL);
*_f = f;
return CA_SUCCESS;
}
static void on_pad_added(GstElement *element, GstPad *pad, gboolean arg1, gpointer data)
{
GstStructure *structure;
GstElement *sinkelement;
GstCaps *caps;
GstPad *vpad;
const char *type;
sinkelement = GST_ELEMENT(data);
caps = gst_pad_query_caps(pad, NULL);
if (gst_caps_is_empty(caps) || gst_caps_is_any(caps)) {
gst_caps_unref(caps);
return;
}
structure = gst_caps_get_structure(caps, 0);
type = gst_structure_get_name(structure);
if (g_str_has_prefix(type, "audio/x-raw") == TRUE) {
vpad = gst_element_get_static_pad(sinkelement, "sink");
gst_pad_link(pad, vpad);
gst_object_unref(vpad);
}
gst_caps_unref(caps);
}
static void
send_mgr_exit_msg (struct private *p) {
GstMessage *m;
GstStructure *s;
s = gst_structure_new("application/mgr-exit", NULL);
m = gst_message_new_application (NULL, s);
gst_bus_post (p->mgr_bus, m);
}
/* Global manager thread that shuts down GStreamer pipelines when ordered */
static void* thread_func(void *userdata) {
struct private *p = userdata;
GstBus *bus = g_object_ref(p->mgr_bus);
pthread_detach(pthread_self());
/* Pop messages from the manager bus until we see an exit command */
do {
GstMessage *m = gst_bus_timed_pop(bus, GST_CLOCK_TIME_NONE);
const GstStructure *s;
const GValue *v;
struct outstanding *out;
if (m == NULL)
break;
if (GST_MESSAGE_TYPE(m) != GST_MESSAGE_APPLICATION) {
gst_message_unref (m);
break;
}
s = gst_message_get_structure(m);
if (gst_structure_has_name(s, "application/mgr-exit")) {
gst_message_unref (m);
break;
}
/* Otherwise, this must be an EOS message for an outstanding pipe */
ca_assert(gst_structure_has_name(s, "application/eos"));
v = gst_structure_get_value(s, "info");
ca_assert(v);
out = g_value_get_pointer(v);
ca_assert(out);
/* Set pipeline back to NULL to close things. By the time this
* completes, we can be sure bus_cb won't be called */
if (gst_element_set_state(out->pipeline, GST_STATE_NULL) ==
GST_STATE_CHANGE_FAILURE) {
gst_message_unref (m);
break;
}
if (out->callback)
out->callback(out->context, out->id, out->err, out->userdata);
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
outstanding_free(out);
ca_mutex_unlock(p->outstanding_mutex);
gst_message_unref(m);
} while (TRUE);
/* Signal the semaphore and exit */
ca_mutex_lock(p->outstanding_mutex);
if (p->signal_semaphore)
sem_post(&p->semaphore);
p->mgr_thread_running = FALSE;
ca_mutex_unlock(p->outstanding_mutex);
gst_bus_set_flushing(bus, TRUE);
g_object_unref (bus);
return NULL;
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
struct private *p;
struct outstanding *out;
ca_sound_file *f;
GstElement *decodebin, *sink, *audioconvert, *audioresample, *abin;
GstBus *bus;
GstPad *audiopad;
int ret;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
out = NULL;
f = NULL;
sink = NULL;
decodebin = NULL;
audioconvert = NULL;
audioresample = NULL;
abin = NULL;
p = PRIVATE(c);
if ((ret = ca_lookup_sound_with_callback(&f, ca_gst_sound_file_open, NULL, &p->theme, c->props, proplist)) < 0)
goto fail;
if (!(out = ca_new0(struct outstanding, 1)))
return CA_ERROR_OOM;
out->id = id;
out->callback = cb;
out->userdata = userdata;
out->context = c;
if (!(out->pipeline = gst_pipeline_new(NULL))
|| !(decodebin = gst_element_factory_make("decodebin2", NULL))
|| !(audioconvert = gst_element_factory_make("audioconvert", NULL))
|| !(audioresample = gst_element_factory_make("audioresample", NULL))
|| !(sink = gst_element_factory_make("autoaudiosink", NULL))
|| !(abin = gst_bin_new ("audiobin"))) {
/* At this point, if there is a failure, free each plugin separately. */
if (out->pipeline != NULL)
g_object_unref (out->pipeline);
if (decodebin != NULL)
g_object_unref(decodebin);
if (audioconvert != NULL)
g_object_unref(audioconvert);
if (audioresample != NULL)
g_object_unref(audioresample);
if (sink != NULL)
g_object_unref(sink);
if (abin != NULL)
g_object_unref(abin);
ca_free(out);
ret = CA_ERROR_OOM;
goto fail;
}
bus = gst_pipeline_get_bus(GST_PIPELINE (out->pipeline));
gst_bus_set_sync_handler(bus, bus_cb, out, NULL);
gst_object_unref(bus);
g_signal_connect(decodebin, "new-decoded-pad",
G_CALLBACK (on_pad_added), abin);
gst_bin_add_many(GST_BIN (abin), audioconvert, audioresample, sink, NULL);
gst_element_link_many(audioconvert, audioresample, sink, NULL);
audiopad = gst_element_get_static_pad(audioconvert, "sink");
gst_element_add_pad(abin, gst_ghost_pad_new("sink", audiopad));
gst_object_unref(audiopad);
gst_bin_add_many(GST_BIN (out->pipeline),
f->fdsrc, decodebin, abin, NULL);
if (!gst_element_link(f->fdsrc, decodebin)) {
/* Bin now owns the fdsrc... */
f->fdsrc = NULL;
outstanding_free(out);
ret = CA_ERROR_OOM;
goto fail;
}
/* Bin now owns the fdsrc... */
f->fdsrc = NULL;
ca_free(f);
f = NULL;
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (gst_element_set_state(out->pipeline,
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
ret = CA_ERROR_NOTAVAILABLE;
goto fail;
}
return CA_SUCCESS;
fail:
if (f && f->fdsrc)
gst_object_unref(f->fdsrc);
if (f)
ca_free(f);
return ret;
}
int driver_cancel(ca_context *c, uint32_t id) {
struct private *p;
struct outstanding *out = NULL;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
p = PRIVATE(c);
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out;/* out = out->next*/) {
struct outstanding *next;
if (out->id != id || out->pipeline == NULL || out->dead == TRUE) {
out = out->next;
continue;
}
if (gst_element_set_state(out->pipeline, GST_STATE_NULL) ==
GST_STATE_CHANGE_FAILURE)
goto error;
if (out->callback)
out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
next = out->next;
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
outstanding_free(out);
out = next;
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
error:
ca_mutex_unlock(p->outstanding_mutex);
return CA_ERROR_SYSTEM;
}
int driver_cache(ca_context *c, ca_proplist *proplist) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
return CA_ERROR_NOTSUPPORTED;
}
int driver_playing(ca_context *c, uint32_t id, int *playing) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
p = PRIVATE(c);
*playing = 0;
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = out->next) {
if (out->id != id || out->pipeline == NULL || out->dead == TRUE)
continue;
*playing = 1;
break;
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
}
07070100000030000081A4000000000000000000000001509D8F3700000148000000000000000000000000000000000000003A00000000libcanberra-0.30+2/src/libcanberra-login-sound.desktop.in[Desktop Entry]
Type=Application
Name=GNOME Login Sound
Comment=Plays a sound whenever you log in
Exec=@bindir@/canberra-gtk-play --id="desktop-login" --description="GNOME Login"
OnlyShowIn=GNOME;
AutostartCondition=GSettings org.gnome.desktop.sound event-sounds
X-GNOME-Autostart-Phase=Application
X-GNOME-Provides=login-sound
07070100000031000081A4000000000000000000000001509D8F3700000059000000000000000000000000000000000000003600000000libcanberra-0.30+2/src/libcanberra-logout-sound.sh.in#!/bin/sh
@bindir@/canberra-gtk-play --id="desktop-logout" --description="GNOME Logout"
07070100000032000081A4000000000000000000000001509D8F3700000169000000000000000000000000000000000000003A00000000libcanberra-0.30+2/src/libcanberra-ready-sound.desktop.in[Desktop Entry]
Type=Application
Name=GNOME System Ready Sound
Comment=Plays a sound whenever your system is ready for login
Exec=@bindir@/canberra-gtk-play --id="system-ready" --description="GNOME System Ready"
OnlyShowIn=GNOME;
AutostartCondition=GSettings org.gnome.desktop.sound event-sounds
X-GNOME-Autostart-Phase=Application
X-GNOME-Provides=login-sound
07070100000033000081A4000000000000000000000001509D8F370000128D000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/llist.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberrallistfoo
#define foocanberrallistfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include "macro.h"
/* Some macros for maintaining doubly linked lists */
/* The head of the linked list. Use this in the structure that shall
* contain the head of the linked list */
#define CA_LLIST_HEAD(t,name) \
t *name
/* The pointers in the linked list's items. Use this in the item structure */
#define CA_LLIST_FIELDS(t) \
t *next, *prev
/* Initialize the list's head */
#define CA_LLIST_HEAD_INIT(t,item) \
do { \
(item) = (t*) NULL; } \
while(0)
/* Initialize a list item */
#define CA_LLIST_INIT(t,item) \
do { \
t *_item = (item); \
ca_assert(_item); \
_item->prev = _item->next = NULL; \
} while(0)
/* Prepend an item to the list */
#define CA_LLIST_PREPEND(t,head,item) \
do { \
t **_head = &(head), *_item = (item); \
ca_assert(_item); \
if ((_item->next = *_head)) \
_item->next->prev = _item; \
_item->prev = NULL; \
*_head = _item; \
} while (0)
/* Remove an item from the list */
#define CA_LLIST_REMOVE(t,head,item) \
do { \
t **_head = &(head), *_item = (item); \
ca_assert(_item); \
if (_item->next) \
_item->next->prev = _item->prev; \
if (_item->prev) \
_item->prev->next = _item->next; \
else { \
ca_assert(*_head == _item); \
*_head = _item->next; \
} \
_item->next = _item->prev = NULL; \
} while(0)
/* Find the head of the list */
#define CA_LLIST_FIND_HEAD(t,item,head) \
do { \
t **_head = (head), *_item = (item); \
*_head = _item; \
ca_assert(_head); \
while ((*_head)->prev) \
*_head = (*_head)->prev; \
} while (0)
/* Insert an item after another one (a = where, b = what) */
#define CA_LLIST_INSERT_AFTER(t,head,a,b) \
do { \
t **_head = &(head), *_a = (a), *_b = (b); \
ca_assert(_b); \
if (!_a) { \
if ((_b->next = *_head)) \
_b->next->prev = _b; \
_b->prev = NULL; \
*_head = _b; \
} else { \
if ((_b->next = _a->next)) \
_b->next->prev = _b; \
_b->prev = _a; \
_a->next = _b; \
} \
} while (0)
#endif
07070100000034000081A4000000000000000000000001509D8F37000003E3000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/macro.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "macro.h"
ca_bool_t ca_debug(void) {
const char *d;
if ((d = getenv("CANBERRA_DEBUG")))
return !!*d;
return FALSE;
}
07070100000035000081A4000000000000000000000001509D8F37000025D0000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/macro.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberramacrohfoo
#define foocanberramacrohfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <stdio.h>
#include <stdlib.h>
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#if defined (__GNUC__) && __GNUC__ >= 3
#define CA_LIKELY(x) (__builtin_expect(!!(x),1))
#define CA_UNLIKELY(x) (__builtin_expect((x),0))
#else
#define CA_LIKELY(x) (x)
#define CA_UNLIKELY(x) (x)
#endif
#ifdef __GNUC__
#define CA_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define CA_PRETTY_FUNCTION ""
#endif
#define ca_return_if_fail(expr) \
do { \
if (CA_UNLIKELY(!(expr))) { \
if (ca_debug()) \
fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \
return; \
} \
} while(FALSE)
#define ca_return_val_if_fail(expr, val) \
do { \
if (CA_UNLIKELY(!(expr))) { \
if (ca_debug()) \
fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \
return (val); \
} \
} while(FALSE)
#define ca_return_null_if_fail(expr) ca_return_val_if_fail(expr, NULL)
#define ca_return_if_fail_unlock(expr, mutex) \
do { \
if (CA_UNLIKELY(!(expr))) { \
if (ca_debug()) \
fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \
ca_mutex_unlock(mutex); \
return; \
} \
} while(FALSE)
#define ca_return_val_if_fail_unlock(expr, val, mutex) \
do { \
if (CA_UNLIKELY(!(expr))) { \
if (ca_debug()) \
fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \
ca_mutex_unlock(mutex); \
return (val); \
} \
} while(FALSE)
#define ca_return_null_if_fail_unlock(expr, mutex) ca_return_val_if_fail_unlock(expr, NULL, mutex)
/* An assert which guarantees side effects of x, i.e. is never
* optimized away */
#define ca_assert_se(expr) \
do { \
if (CA_UNLIKELY(!(expr))) { \
fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n", #expr , __FILE__, __LINE__, CA_PRETTY_FUNCTION); \
abort(); \
} \
} while (FALSE)
/* An assert that may be optimized away by defining NDEBUG */
#ifdef NDEBUG
#define ca_assert(expr) do {} while (FALSE)
#else
#define ca_assert(expr) ca_assert_se(expr)
#endif
#define ca_assert_not_reached() \
do { \
fprintf(stderr, "Code should not be reached at %s:%u, function %s(). Aborting.\n", __FILE__, __LINE__, CA_PRETTY_FUNCTION); \
abort(); \
} while (FALSE)
#define CA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
#ifdef __GNUC__
#define CA_MAX(a,b) \
__extension__ ({ typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a > _b ? _a : _b; \
})
#else
#define CA_MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifdef __GNUC__
#define CA_MIN(a,b) \
__extension__ ({ typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a < _b ? _a : _b; \
})
#else
#define CA_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifdef __GNUC__
#define CA_CLAMP(x, low, high) \
__extension__ ({ typeof(x) _x = (x); \
typeof(low) _low = (low); \
typeof(high) _high = (high); \
((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
})
#else
#define CA_CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#define CA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p))
#define CA_UINT_TO_PTR(u) ((void*) (unsigned long) (u))
#define CA_PTR_TO_UINT32(p) ((uint32_t) CA_PTR_TO_UINT(p))
#define CA_UINT32_TO_PTR(u) CA_UINT_TO_PTR((uint32_t) u)
#define CA_PTR_TO_INT(p) ((int) CA_PTR_TO_UINT(p))
#define CA_INT_TO_PTR(u) CA_UINT_TO_PTR((int) u)
#define CA_PTR_TO_INT32(p) ((int32_t) CA_PTR_TO_UINT(p))
#define CA_INT32_TO_PTR(u) CA_UINT_TO_PTR((int32_t) u)
typedef int ca_bool_t;
ca_bool_t ca_debug(void);
static inline size_t ca_align(size_t l) {
return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*));
}
#define CA_ALIGN(x) (ca_align(x))
typedef void (*ca_free_cb_t)(void *);
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#ifdef HAVE_BYTESWAP_H
#define CA_INT16_SWAP(x) ((int16_t) bswap_16((uint16_t) x))
#define CA_UINT16_SWAP(x) ((uint16_t) bswap_16((uint16_t) x))
#define CA_INT32_SWAP(x) ((int32_t) bswap_32((uint32_t) x))
#define CA_UINT32_SWAP(x) ((uint32_t) bswap_32((uint32_t) x))
#else
#define CA_INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
#define CA_UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
#define CA_INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
#define CA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
#endif
#ifdef WORDS_BIGENDIAN
#define CA_INT16_FROM_LE(x) CA_INT16_SWAP(x)
#define CA_INT16_FROM_BE(x) ((int16_t)(x))
#define CA_INT16_TO_LE(x) CA_INT16_SWAP(x)
#define CA_INT16_TO_BE(x) ((int16_t)(x))
#define CA_UINT16_FROM_LE(x) CA_UINT16_SWAP(x)
#define CA_UINT16_FROM_BE(x) ((uint16_t)(x))
#define CA_UINT16_TO_LE(x) CA_UINT16_SWAP(x)
#define CA_UINT16_TO_BE(x) ((uint16_t)(x))
#define CA_INT32_FROM_LE(x) CA_INT32_SWAP(x)
#define CA_INT32_FROM_BE(x) ((int32_t)(x))
#define CA_INT32_TO_LE(x) CA_INT32_SWAP(x)
#define CA_INT32_TO_BE(x) ((int32_t)(x))
#define CA_UINT32_FROM_LE(x) CA_UINT32_SWAP(x)
#define CA_UINT32_FROM_BE(x) ((uint32_t)(x))
#define CA_UINT32_TO_LE(x) CA_UINT32_SWAP(x)
#define CA_UINT32_TO_BE(x) ((uint32_t)(x))
#else
#define CA_INT16_FROM_LE(x) ((int16_t)(x))
#define CA_INT16_FROM_BE(x) CA_INT16_SWAP(x)
#define CA_INT16_TO_LE(x) ((int16_t)(x))
#define CA_INT16_TO_BE(x) CA_INT16_SWAP(x)
#define CA_UINT16_FROM_LE(x) ((uint16_t)(x))
#define CA_UINT16_FROM_BE(x) CA_UINT16_SWAP(x)
#define CA_UINT16_TO_LE(x) ((uint16_t)(x))
#define CA_UINT16_TO_BE(x) CA_UINT16_SWAP(x)
#define CA_INT32_FROM_LE(x) ((int32_t)(x))
#define CA_INT32_FROM_BE(x) CA_INT32_SWAP(x)
#define CA_INT32_TO_LE(x) ((int32_t)(x))
#define CA_INT32_TO_BE(x) CA_INT32_SWAP(x)
#define CA_UINT32_FROM_LE(x) ((uint32_t)(x))
#define CA_UINT32_FROM_BE(x) CA_UINT32_SWAP(x)
#define CA_UINT32_TO_LE(x) ((uint32_t)(x))
#define CA_UINT32_TO_BE(x) CA_UINT32_SWAP(x)
#endif
#define ca_streq(a, b) (strcmp((a),(b)) == 0)
#ifdef __GNUC__
#define CA_GCC_DESTRUCTOR __attribute__ ((destructor))
#else
#undef CA_GCC_DESTRUCTOR
#endif
#endif
07070100000036000081A4000000000000000000000001509D8F370000093F000000000000000000000000000000000000002000000000libcanberra-0.30+2/src/malloc.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "malloc.h"
#include "macro.h"
void* ca_memdup(const void* p, size_t size) {
void *r;
ca_assert(p);
if (!(r = ca_malloc(size)))
return NULL;
memcpy(r, p, size);
return r;
}
char *ca_sprintf_malloc(const char *format, ...) {
size_t size = 100;
char *c = NULL;
ca_assert(format);
for(;;) {
int r;
va_list ap;
ca_free(c);
if (!(c = ca_new(char, size)))
return NULL;
va_start(ap, format);
r = vsnprintf(c, size, format, ap);
va_end(ap);
c[size-1] = 0;
if (r > -1 && (size_t) r < size)
return c;
if (r > -1) /* glibc 2.1 */
size = (size_t) r+1;
else /* glibc 2.0 */
size *= 2;
}
}
#ifndef HAVE_STRNDUP
char *ca_strndup(const char *s, size_t n) {
size_t n_avail;
char *p;
if (!s)
return NULL;
if (memchr(s, '\0', n)) {
n_avail = strlen(s);
if (n_avail > n)
n_avail = n;
} else
n_avail = n;
if (!(p = ca_new(char, n_avail + 1)))
return NULL;
memcpy(p, s, n_avail);
p[n_avail] = '\0';
return p;
}
#endif
07070100000037000081A4000000000000000000000001509D8F3700000601000000000000000000000000000000000000002000000000libcanberra-0.30+2/src/malloc.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberramallochfoo
#define foocanberramallochfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <stdlib.h>
#include <string.h>
#include "canberra.h"
#include "macro.h"
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#define ca_malloc malloc
#define ca_free free
#define ca_malloc0(size) calloc(1, (size))
#define ca_strdup strdup
#ifdef HAVE_STRNDUP
#define ca_strndup strndup
#else
char *ca_strndup(const char *s, size_t n);
#endif
void* ca_memdup(const void* p, size_t size);
#define ca_new(t, n) ((t*) ca_malloc(sizeof(t)*(n)))
#define ca_new0(t, n) ((t*) ca_malloc0(sizeof(t)*(n)))
#define ca_newdup(t, p, n) ((t*) ca_memdup(p, sizeof(t)*(n)))
char *ca_sprintf_malloc(const char *format, ...) __attribute__((format(printf, 1, 2)));
#endif
07070100000038000081A4000000000000000000000001509D8F37000000A4000000000000000000000000000000000000002000000000libcanberra-0.30+2/src/map-fileCANBERRA_0 {
local:
driver_cache;
driver_cancel;
driver_change_device;
driver_change_props;
driver_destroy;
driver_open;
driver_play;
lt_*;
dlopen_*;
preopen_*;
};
07070100000039000081A4000000000000000000000001509D8F37000025E8000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/multi.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "driver.h"
#include "llist.h"
#include "malloc.h"
#include "common.h"
#include "driver-order.h"
struct backend {
CA_LLIST_FIELDS(struct backend);
ca_context *context;
};
struct private {
ca_context *context;
CA_LLIST_HEAD(struct backend, backends);
};
#define PRIVATE(c) ((struct private *) ((c)->private))
static int add_backend(struct private *p, const char *name) {
struct backend *b, *last;
int ret;
ca_assert(p);
ca_assert(name);
if (ca_streq(name, "multi"))
return CA_ERROR_NOTAVAILABLE;
for (b = p->backends; b; b = b->next)
if (ca_streq(b->context->driver, name))
return CA_ERROR_NOTAVAILABLE;
if (!(b = ca_new0(struct backend, 1)))
return CA_ERROR_OOM;
if ((ret = ca_context_create(&b->context)) < 0)
goto fail;
if ((ret = ca_context_change_props_full(b->context, p->context->props)) < 0)
goto fail;
if ((ret = ca_context_set_driver(b->context, name)) < 0)
goto fail;
if ((ret = ca_context_open(b->context)) < 0)
goto fail;
for (last = p->backends; last; last = last->next)
if (!last->next)
break;
CA_LLIST_INSERT_AFTER(struct backend, p->backends, last, b);
return CA_SUCCESS;
fail:
if (b->context)
ca_context_destroy(b->context);
ca_free(b);
return ret;
}
static int remove_backend(struct private *p, struct backend *b) {
int ret;
ca_assert(p);
ca_assert(b);
ret = ca_context_destroy(b->context);
CA_LLIST_REMOVE(struct backend, p->backends, b);
ca_free(b);
return ret;
}
int driver_open(ca_context *c) {
struct private *p;
int ret = CA_SUCCESS;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->driver, CA_ERROR_NODRIVER);
ca_return_val_if_fail(!strncmp(c->driver, "multi", 5), CA_ERROR_NODRIVER);
ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE);
if (!(c->private = p = ca_new0(struct private, 1)))
return CA_ERROR_OOM;
p->context = c;
if (c->driver) {
char *e, *k;
if (!(e = ca_strdup(c->driver))) {
driver_destroy(c);
return CA_ERROR_OOM;
}
k = e;
for (;;) {
size_t n;
ca_bool_t last;
n = strcspn(k, ",:");
last = k[n] == 0;
k[n] = 0;
if (n > 0) {
int r;
r = add_backend(p, k);
if (ret == CA_SUCCESS)
ret = r;
}
if (last)
break;
k += n+1 ;
}
ca_free(e);
} else {
const char *const *e;
for (e = ca_driver_order; *e; e++) {
int r;
r = add_backend(p, *e);
/* We return the error code of the first module that fails only */
if (ret == CA_SUCCESS)
ret = r;
}
}
if (!p->backends) {
driver_destroy(c);
return ret == CA_SUCCESS ? CA_ERROR_NODRIVER : ret;
}
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
int ret = CA_SUCCESS;
struct private *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
while (p->backends) {
int r;
r = remove_backend(p, p->backends);
if (ret == CA_SUCCESS)
ret = r;
}
ca_free(p);
c->private = NULL;
return ret;
}
int driver_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
return CA_ERROR_NOTSUPPORTED;
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
int ret = CA_SUCCESS;
struct private *p;
struct backend *b;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(changed, CA_ERROR_INVALID);
ca_return_val_if_fail(merged, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
for (b = p->backends; b; b = b->next) {
int r;
r = ca_context_change_props_full(b->context, changed);
/* We only return the first failure */
if (ret == CA_SUCCESS)
ret = r;
}
return ret;
}
struct closure {
ca_context *context;
ca_finish_callback_t callback;
void *userdata;
};
static void call_closure(ca_context *c, uint32_t id, int error_code, void *userdata) {
struct closure *closure = userdata;
closure->callback(closure->context, id, error_code, closure->userdata);
ca_free(closure);
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
int ret = CA_SUCCESS;
struct private *p;
struct backend *b;
struct closure *closure;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
if (cb) {
if (!(closure = ca_new(struct closure, 1)))
return CA_ERROR_OOM;
closure->context = c;
closure->callback = cb;
closure->userdata = userdata;
} else
closure = NULL;
/* The first backend that can play this, takes it */
for (b = p->backends; b; b = b->next) {
int r;
if ((r = ca_context_play_full(b->context, id, proplist, closure ? call_closure : NULL, closure)) == CA_SUCCESS)
return r;
/* We only return the first failure */
if (ret == CA_SUCCESS)
ret = r;
}
ca_free(closure);
return ret;
}
int driver_cancel(ca_context *c, uint32_t id) {
int ret = CA_SUCCESS;
struct private *p;
struct backend *b;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
for (b = p->backends; b; b = b->next) {
int r;
r = ca_context_cancel(b->context, id);
/* We only return the first failure */
if (ret == CA_SUCCESS)
ret = r;
}
return ret;
}
int driver_cache(ca_context *c, ca_proplist *proplist) {
int ret = CA_SUCCESS;
struct private *p;
struct backend *b;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
/* The first backend that can cache this, takes it */
for (b = p->backends; b; b = b->next) {
int r;
if ((r = ca_context_cache_full(b->context, proplist)) == CA_SUCCESS)
return r;
/* We only return the first failure */
if (ret == CA_SUCCESS)
ret = r;
}
return ret;
}
int driver_playing(ca_context *c, uint32_t id, int *playing) {
int ret = CA_SUCCESS;
struct private *p;
struct backend *b;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
*playing = 0;
for (b = p->backends; b; b = b->next) {
int r, _playing = 0;
r = ca_context_playing(b->context, id, &_playing);
/* We only return the first failure */
if (ret == CA_SUCCESS)
ret = r;
if (_playing)
*playing = 1;
}
return ret;
}
0707010000003A000081A4000000000000000000000001509D8F370000073B000000000000000000000000000000000000002500000000libcanberra-0.30+2/src/mutex-posix.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pthread.h>
#include <errno.h>
#include "mutex.h"
#include "malloc.h"
struct ca_mutex {
pthread_mutex_t mutex;
};
ca_mutex* ca_mutex_new(void) {
ca_mutex *m;
if (!(m = ca_new(ca_mutex, 1)))
return NULL;
if (pthread_mutex_init(&m->mutex, NULL) < 0) {
ca_free(m);
return NULL;
}
return m;
}
void ca_mutex_free(ca_mutex *m) {
ca_assert(m);
ca_assert_se(pthread_mutex_destroy(&m->mutex) == 0);
ca_free(m);
}
void ca_mutex_lock(ca_mutex *m) {
ca_assert(m);
ca_assert_se(pthread_mutex_lock(&m->mutex) == 0);
}
ca_bool_t ca_mutex_try_lock(ca_mutex *m) {
int r;
ca_assert(m);
if ((r = pthread_mutex_trylock(&m->mutex)) != 0) {
ca_assert(r == EBUSY);
return FALSE;
}
return TRUE;
}
void ca_mutex_unlock(ca_mutex *m) {
ca_assert(m);
ca_assert_se(pthread_mutex_unlock(&m->mutex) == 0);
}
0707010000003B000081A4000000000000000000000001509D8F3700000431000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/mutex.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberramutexhfoo
#define foocanberramutexhfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include "macro.h"
typedef struct ca_mutex ca_mutex;
ca_mutex* ca_mutex_new(void);
void ca_mutex_free(ca_mutex *m);
void ca_mutex_lock(ca_mutex *m);
ca_bool_t ca_mutex_try_lock(ca_mutex *m);
void ca_mutex_unlock(ca_mutex *m);
#endif
0707010000003C000081A4000000000000000000000001509D8F3700000955000000000000000000000000000000000000001E00000000libcanberra-0.30+2/src/null.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "canberra.h"
#include "common.h"
#include "driver.h"
int driver_open(ca_context *c) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "null"), CA_ERROR_NODRIVER);
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
return CA_SUCCESS;
}
int driver_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
return CA_SUCCESS;
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(changed, CA_ERROR_INVALID);
ca_return_val_if_fail(merged, CA_ERROR_INVALID);
return CA_SUCCESS;
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
if (cb)
cb(c, id, CA_SUCCESS, userdata);
return CA_SUCCESS;
}
int driver_cancel(ca_context *c, uint32_t id) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
return CA_SUCCESS;
}
int driver_cache(ca_context *c, ca_proplist *proplist) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
return CA_ERROR_NOTSUPPORTED;
}
0707010000003D000081A4000000000000000000000001509D8F370000391E000000000000000000000000000000000000001D00000000libcanberra-0.30+2/src/oss.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
Joe Marcus Clarke
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <poll.h>
#include <pthread.h>
#include <semaphore.h>
#ifdef HAVE_MACHINE_SOUNDCARD_H
# include <machine/soundcard.h>
#else
# ifdef HAVE_SOUNDCARD_H
# include <soundcard.h>
# else
# include <sys/soundcard.h>
# endif
#endif
#include "canberra.h"
#include "common.h"
#include "driver.h"
#include "llist.h"
#include "read-sound-file.h"
#include "sound-theme-spec.h"
#include "malloc.h"
struct private;
struct outstanding {
CA_LLIST_FIELDS(struct outstanding);
ca_bool_t dead;
uint32_t id;
ca_finish_callback_t callback;
void *userdata;
ca_sound_file *file;
int pcm;
int pipe_fd[2];
ca_context *context;
};
struct private {
ca_theme_data *theme;
ca_mutex *outstanding_mutex;
ca_bool_t signal_semaphore;
sem_t semaphore;
ca_bool_t semaphore_allocated;
CA_LLIST_HEAD(struct outstanding, outstanding);
};
#define PRIVATE(c) ((struct private *) ((c)->private))
static void outstanding_free(struct outstanding *o) {
ca_assert(o);
if (o->pipe_fd[1] >= 0)
close(o->pipe_fd[1]);
if (o->pipe_fd[0] >= 0)
close(o->pipe_fd[0]);
if (o->file)
ca_sound_file_close(o->file);
if (o->pcm >= 0) {
close(o->pcm);
o->pcm = -1;
}
ca_free(o);
}
int driver_open(ca_context *c) {
struct private *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "oss"), CA_ERROR_NODRIVER);
ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE);
if (!(c->private = p = ca_new0(struct private, 1)))
return CA_ERROR_OOM;
if (!(p->outstanding_mutex = ca_mutex_new())) {
driver_destroy(c);
return CA_ERROR_OOM;
}
if (sem_init(&p->semaphore, 0, 0) < 0) {
driver_destroy(c);
return CA_ERROR_OOM;
}
p->semaphore_allocated = TRUE;
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
if (p->outstanding_mutex) {
ca_mutex_lock(p->outstanding_mutex);
/* Tell all player threads to terminate */
for (out = p->outstanding; out; out = out->next) {
if (out->dead)
continue;
out->dead = TRUE;
if (out->callback)
out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata);
/* This will cause the thread to wakeup and terminate */
if (out->pipe_fd[1] >= 0) {
close(out->pipe_fd[1]);
out->pipe_fd[1] = -1;
}
}
if (p->semaphore_allocated) {
/* Now wait until all players are destroyed */
p->signal_semaphore = TRUE;
while (p->outstanding) {
ca_mutex_unlock(p->outstanding_mutex);
sem_wait(&p->semaphore);
ca_mutex_lock(p->outstanding_mutex);
}
}
ca_mutex_unlock(p->outstanding_mutex);
ca_mutex_free(p->outstanding_mutex);
}
if (p->theme)
ca_theme_data_free(p->theme);
if (p->semaphore_allocated)
sem_destroy(&p->semaphore);
ca_free(p);
c->private = NULL;
return CA_SUCCESS;
}
int driver_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
return CA_SUCCESS;
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(changed, CA_ERROR_INVALID);
ca_return_val_if_fail(merged, CA_ERROR_INVALID);
return CA_SUCCESS;
}
int driver_cache(ca_context *c, ca_proplist *proplist) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
return CA_ERROR_NOTSUPPORTED;
}
static int translate_error(int error) {
switch (error) {
case ENODEV:
case ENOENT:
return CA_ERROR_NOTFOUND;
case EACCES:
case EPERM:
return CA_ERROR_ACCESS;
case ENOMEM:
return CA_ERROR_OOM;
case EBUSY:
return CA_ERROR_NOTAVAILABLE;
case EINVAL:
return CA_ERROR_INVALID;
case ENOSYS:
return CA_ERROR_NOTSUPPORTED;
default:
if (ca_debug())
fprintf(stderr, "Got unhandled error from OSS: %s\n", strerror(error));
return CA_ERROR_IO;
}
}
static int open_oss(ca_context *c, struct outstanding *out) {
int mode, val, test, ret;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
ca_return_val_if_fail(out, CA_ERROR_INVALID);
/* In OSS we have no way to configure a channel mapping for
* multichannel streams. We cannot support those files hence */
ca_return_val_if_fail(ca_sound_file_get_nchannels(out->file) <= 2, CA_ERROR_NOTSUPPORTED);
if ((out->pcm = open(c->device ? c->device : "/dev/dsp", O_WRONLY | O_NONBLOCK, 0)) < 0)
goto finish_errno;
if ((mode = fcntl(out->pcm, F_GETFL)) < 0)
goto finish_errno;
mode &= ~O_NONBLOCK;
if (fcntl(out->pcm, F_SETFL, mode) < 0)
goto finish_errno;
switch (ca_sound_file_get_sample_type(out->file)) {
case CA_SAMPLE_U8:
val = AFMT_U8;
break;
case CA_SAMPLE_S16NE:
val = AFMT_S16_NE;
break;
case CA_SAMPLE_S16RE:
#if __BYTE_ORDER == __LITTLE_ENDIAN
val = AFMT_S16_BE;
#else
val = AFMT_S16_LE;
#endif
break;
}
test = val;
if (ioctl(out->pcm, SNDCTL_DSP_SETFMT, &val) < 0)
goto finish_errno;
if (val != test) {
ret = CA_ERROR_NOTSUPPORTED;
goto finish_ret;
}
test = val = (int) ca_sound_file_get_nchannels(out->file);
if (ioctl(out->pcm, SNDCTL_DSP_CHANNELS, &val) < 0)
goto finish_errno;
if (val != test) {
ret = CA_ERROR_NOTSUPPORTED;
goto finish_ret;
}
test = val = (int) ca_sound_file_get_rate(out->file);
if (ioctl(out->pcm, SNDCTL_DSP_SPEED, &val) < 0)
goto finish_errno;
/* Check to make sure the configured rate is close enough to the
* requested rate. */
if (fabs((double) (val - test)) > test * 0.05) {
ret = CA_ERROR_NOTSUPPORTED;
goto finish_ret;
}
return CA_SUCCESS;
finish_errno:
return translate_error(errno);
finish_ret:
return ret;
}
#define BUFSIZE (4*1024)
static void* thread_func(void *userdata) {
struct outstanding *out = userdata;
int ret;
void *data, *d = NULL;
size_t fs, data_size;
size_t nbytes = 0;
struct pollfd pfd[2];
nfds_t n_pfd = 2;
struct private *p;
p = PRIVATE(out->context);
pthread_detach(pthread_self());
fs = ca_sound_file_frame_size(out->file);
data_size = (BUFSIZE/fs)*fs;
if (!(data = ca_malloc(data_size))) {
ret = CA_ERROR_OOM;
goto finish;
}
pfd[0].fd = out->pipe_fd[0];
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = out->pcm;
pfd[1].events = POLLOUT;
pfd[1].revents = 0;
for (;;) {
ssize_t bytes_written;
if (out->dead)
break;
if (poll(pfd, n_pfd, -1) < 0) {
ret = CA_ERROR_SYSTEM;
goto finish;
}
/* We have been asked to shut down */
if (pfd[0].revents)
break;
if (pfd[1].revents != POLLOUT) {
ret = CA_ERROR_IO;
goto finish;
}
if (nbytes <= 0) {
nbytes = data_size;
if ((ret = ca_sound_file_read_arbitrary(out->file, data, &nbytes)) < 0)
goto finish;
d = data;
}
if (nbytes <= 0)
break;
if ((bytes_written = write(out->pcm, d, nbytes)) <= 0) {
ret = translate_error(errno);
goto finish;
}
nbytes -= (size_t) bytes_written;
d = (uint8_t*) d + (size_t) bytes_written;
}
ret = CA_SUCCESS;
finish:
ca_free(data);
if (!out->dead)
if (out->callback)
out->callback(out->context, out->id, ret, out->userdata);
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
if (!p->outstanding && p->signal_semaphore)
sem_post(&p->semaphore);
outstanding_free(out);
ca_mutex_unlock(p->outstanding_mutex);
return NULL;
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
struct private *p;
struct outstanding *out = NULL;
int ret;
pthread_t thread;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
if (!(out = ca_new0(struct outstanding, 1))) {
ret = CA_ERROR_OOM;
goto finish;
}
out->context = c;
out->id = id;
out->callback = cb;
out->userdata = userdata;
out->pipe_fd[0] = out->pipe_fd[1] = -1;
out->pcm = -1;
if (pipe(out->pipe_fd) < 0) {
ret = CA_ERROR_SYSTEM;
goto finish;
}
if ((ret = ca_lookup_sound(&out->file, NULL, &p->theme, c->props, proplist)) < 0)
goto finish;
if ((ret = open_oss(c, out)) < 0)
goto finish;
/* OK, we're ready to go, so let's add this to our list */
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (pthread_create(&thread, NULL, thread_func, out) < 0) {
ret = CA_ERROR_OOM;
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
goto finish;
}
ret = CA_SUCCESS;
finish:
/* We keep the outstanding struct around if we need clean up later to */
if (ret != CA_SUCCESS)
outstanding_free(out);
return ret;
}
int driver_cancel(ca_context *c, uint32_t id) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = out->next) {
if (out->id != id)
continue;
if (out->dead)
continue;
out->dead = TRUE;
if (out->callback)
out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
/* This will cause the thread to wakeup and terminate */
if (out->pipe_fd[1] >= 0) {
close(out->pipe_fd[1]);
out->pipe_fd[1] = -1;
}
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
}
int driver_playing(ca_context *c, uint32_t id, int *playing) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
p = PRIVATE(c);
*playing = 0;
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = out->next) {
if (out->dead ||
out->id != id)
continue;
*playing = 1;
break;
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
}
0707010000003E000081A4000000000000000000000001509D8F3700002AE8000000000000000000000000000000000000002200000000libcanberra-0.30+2/src/proplist.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdarg.h>
#include "canberra.h"
#include "proplist.h"
#include "macro.h"
#include "malloc.h"
static unsigned calc_hash(const char *c) {
unsigned hash = 0;
for (; *c; c++)
hash = 31 * hash + (unsigned) *c;
return hash;
}
/**
* ca_proplist_create:
* @p: A pointer where to fill in a pointer for the new property list.
*
* Allocate a new empty property list.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_proplist_create(ca_proplist **_p) {
ca_proplist *p;
ca_return_val_if_fail(_p, CA_ERROR_INVALID);
if (!(p = ca_new0(ca_proplist, 1)))
return CA_ERROR_OOM;
if (!(p->mutex = ca_mutex_new())) {
ca_free(p);
return CA_ERROR_OOM;
}
*_p = p;
return CA_SUCCESS;
}
static int _unset(ca_proplist *p, const char *key) {
ca_prop *prop, *nprop;
unsigned i;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(key, CA_ERROR_INVALID);
i = calc_hash(key) % N_HASHTABLE;
nprop = NULL;
for (prop = p->prop_hashtable[i]; prop; nprop = prop, prop = prop->next_in_slot)
if (strcmp(prop->key, key) == 0)
break;
if (prop) {
if (nprop)
nprop->next_in_slot = prop->next_in_slot;
else
p->prop_hashtable[i] = prop->next_in_slot;
if (prop->prev_item)
prop->prev_item->next_item = prop->next_item;
else
p->first_item = prop->next_item;
if (prop->next_item)
prop->next_item->prev_item = prop->prev_item;
ca_free(prop->key);
ca_free(prop);
}
return CA_SUCCESS;
}
/**
* ca_proplist_sets:
* @p: The property list to add this key/value pair to
* @key: The key for this key/value pair
* @value: The value for this key/value pair
*
* Add a new string key/value pair to the property list.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_proplist_sets(ca_proplist *p, const char *key, const char *value) {
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(key, CA_ERROR_INVALID);
ca_return_val_if_fail(value, CA_ERROR_INVALID);
return ca_proplist_set(p, key, value, strlen(value)+1);
}
/**
* ca_proplist_setf:
* @p: The property list to add this key/value pair to
* @key: The key for this key/value pair
* @format: The format string for the value for this key/value pair
* @...: The parameters for the format string
*
* Much like ca_proplist_sets(): add a new string key/value pair to
* the property list. Takes a standard C format string plus arguments
* and formats a string of it.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_proplist_setf(ca_proplist *p, const char *key, const char *format, ...) {
int ret;
char *k;
ca_prop *prop;
size_t size = 100;
unsigned h;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(key, CA_ERROR_INVALID);
ca_return_val_if_fail(format, CA_ERROR_INVALID);
if (!(k = ca_strdup(key)))
return CA_ERROR_OOM;
for (;;) {
va_list ap;
int r;
if (!(prop = ca_malloc(CA_ALIGN(sizeof(ca_prop)) + size))) {
ca_free(k);
return CA_ERROR_OOM;
}
va_start(ap, format);
r = vsnprintf(CA_PROP_DATA(prop), size, format, ap);
va_end(ap);
((char*) CA_PROP_DATA(prop))[size-1] = 0;
if (r > -1 && (size_t) r < size) {
prop->nbytes = (size_t) r+1;
break;
}
if (r > -1) /* glibc 2.1 */
size = (size_t) r+1;
else /* glibc 2.0 */
size *= 2;
ca_free(prop);
}
prop->key = k;
ca_mutex_lock(p->mutex);
if ((ret = _unset(p, key)) < 0) {
ca_free(prop);
ca_free(k);
goto finish;
}
h = calc_hash(key) % N_HASHTABLE;
prop->next_in_slot = p->prop_hashtable[h];
p->prop_hashtable[h] = prop;
prop->prev_item = NULL;
if ((prop->next_item = p->first_item))
prop->next_item->prev_item = prop;
p->first_item = prop;
finish:
ca_mutex_unlock(p->mutex);
return ret;
}
/**
* ca_proplist_set:
* @p: The property list to add this key/value pair to
* @key: The key for this key/value pair
* @data: The binary value for this key value pair
* @nbytes: The size of thebinary value for this key value pair.
*
* Add a new binary key/value pair to the property list.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_proplist_set(ca_proplist *p, const char *key, const void *data, size_t nbytes) {
int ret;
char *k;
ca_prop *prop;
unsigned h;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
ca_return_val_if_fail(key, CA_ERROR_INVALID);
ca_return_val_if_fail(!nbytes || data, CA_ERROR_INVALID);
if (!(k = ca_strdup(key)))
return CA_ERROR_OOM;
if (!(prop = ca_malloc(CA_ALIGN(sizeof(ca_prop)) + nbytes))) {
ca_free(k);
return CA_ERROR_OOM;
}
prop->key = k;
prop->nbytes = nbytes;
memcpy(CA_PROP_DATA(prop), data, nbytes);
ca_mutex_lock(p->mutex);
if ((ret = _unset(p, key)) < 0) {
ca_free(prop);
ca_free(k);
goto finish;
}
h = calc_hash(key) % N_HASHTABLE;
prop->next_in_slot = p->prop_hashtable[h];
p->prop_hashtable[h] = prop;
prop->prev_item = NULL;
if ((prop->next_item = p->first_item))
prop->next_item->prev_item = prop;
p->first_item = prop;
finish:
ca_mutex_unlock(p->mutex);
return ret;
}
/* Not exported, not self-locking */
ca_prop* ca_proplist_get_unlocked(ca_proplist *p, const char *key) {
ca_prop *prop;
unsigned i;
ca_return_val_if_fail(p, NULL);
ca_return_val_if_fail(key, NULL);
i = calc_hash(key) % N_HASHTABLE;
for (prop = p->prop_hashtable[i]; prop; prop = prop->next_in_slot)
if (strcmp(prop->key, key) == 0)
return prop;
return NULL;
}
/* Not exported, not self-locking */
const char* ca_proplist_gets_unlocked(ca_proplist *p, const char *key) {
ca_prop *prop;
ca_return_val_if_fail(p, NULL);
ca_return_val_if_fail(key, NULL);
if (!(prop = ca_proplist_get_unlocked(p, key)))
return NULL;
if (!memchr(CA_PROP_DATA(prop), 0, prop->nbytes))
return NULL;
return CA_PROP_DATA(prop);
}
/**
* ca_proplist_destroy:
* @p: The property list to destroy
*
* Destroys a property list that was created with ca_proplist_create() earlier.
*
* Returns: 0 on success, negative error code on error.
*/
int ca_proplist_destroy(ca_proplist *p) {
ca_prop *prop, *nprop;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
for (prop = p->first_item; prop; prop = nprop) {
nprop = prop->next_item;
ca_free(prop->key);
ca_free(prop);
}
ca_mutex_free(p->mutex);
ca_free(p);
return CA_SUCCESS;
}
static int merge_into(ca_proplist *a, ca_proplist *b) {
int ret = CA_SUCCESS;
ca_prop *prop;
ca_return_val_if_fail(a, CA_ERROR_INVALID);
ca_return_val_if_fail(b, CA_ERROR_INVALID);
ca_mutex_lock(b->mutex);
for (prop = b->first_item; prop; prop = prop->next_item)
if ((ret = ca_proplist_set(a, prop->key, CA_PROP_DATA(prop), prop->nbytes)) < 0)
break;
ca_mutex_unlock(b->mutex);
return ret;
}
int ca_proplist_merge(ca_proplist **_a, ca_proplist *b, ca_proplist *c) {
ca_proplist *a;
int ret;
ca_return_val_if_fail(_a, CA_ERROR_INVALID);
ca_return_val_if_fail(b, CA_ERROR_INVALID);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
if ((ret = ca_proplist_create(&a)) < 0)
return ret;
if ((ret = merge_into(a, b)) < 0 ||
(ret = merge_into(a, c)) < 0) {
ca_proplist_destroy(a);
return ret;
}
*_a = a;
return CA_SUCCESS;
}
ca_bool_t ca_proplist_contains(ca_proplist *p, const char *key) {
ca_bool_t b;
ca_return_val_if_fail(p, FALSE);
ca_return_val_if_fail(key, FALSE);
ca_mutex_lock(p->mutex);
b = !!ca_proplist_get_unlocked(p, key);
ca_mutex_unlock(p->mutex);
return b;
}
int ca_proplist_merge_ap(ca_proplist *p, va_list ap) {
int ret;
ca_return_val_if_fail(p, CA_ERROR_INVALID);
for (;;) {
const char *key, *value;
if (!(key = va_arg(ap, const char*)))
break;
if (!(value = va_arg(ap, const char*)))
return CA_ERROR_INVALID;
if ((ret = ca_proplist_sets(p, key, value)) < 0)
return ret;
}
return CA_SUCCESS;
}
int ca_proplist_from_ap(ca_proplist **_p, va_list ap) {
int ret;
ca_proplist *p;
ca_return_val_if_fail(_p, CA_ERROR_INVALID);
if ((ret = ca_proplist_create(&p)) < 0)
return ret;
if ((ret = ca_proplist_merge_ap(p, ap)) < 0)
goto fail;
*_p = p;
return CA_SUCCESS;
fail:
ca_assert_se(ca_proplist_destroy(p) == CA_SUCCESS);
return ret;
}
0707010000003F000081A4000000000000000000000001509D8F37000006D5000000000000000000000000000000000000002200000000libcanberra-0.30+2/src/proplist.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberraproplisthfoo
#define foocanberraproplisthfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <stdarg.h>
#include "canberra.h"
#include "mutex.h"
#define N_HASHTABLE 31
typedef struct ca_prop {
char *key;
size_t nbytes;
struct ca_prop *next_in_slot, *next_item, *prev_item;
} ca_prop;
#define CA_PROP_DATA(p) ((void*) ((char*) (p) + CA_ALIGN(sizeof(ca_prop))))
struct ca_proplist {
ca_mutex *mutex;
ca_prop *prop_hashtable[N_HASHTABLE];
ca_prop *first_item;
};
int ca_proplist_merge(ca_proplist **_a, ca_proplist *b, ca_proplist *c);
ca_bool_t ca_proplist_contains(ca_proplist *p, const char *key);
/* Both of the following two functions are not locked! Need manual locking! */
ca_prop* ca_proplist_get_unlocked(ca_proplist *p, const char *key);
const char* ca_proplist_gets_unlocked(ca_proplist *p, const char *key);
int ca_proplist_merge_ap(ca_proplist *p, va_list ap);
int ca_proplist_from_ap(ca_proplist **_p, va_list ap);
#endif
07070100000040000081A4000000000000000000000001509D8F370000A998000000000000000000000000000000000000001F00000000libcanberra-0.30+2/src/pulse.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* The locking order needs to be strictly followed! First take the
* mainloop mutex, only then take outstanding_mutex if you need both!
* Not the other way round, beacause we might then enter a
* deadlock! */
#include <errno.h>
#include <stdlib.h>
#include <pulse/thread-mainloop.h>
#include <pulse/context.h>
#include <pulse/scache.h>
#include <pulse/subscribe.h>
#include <pulse/introspect.h>
#include "canberra.h"
#include "common.h"
#include "driver.h"
#include "llist.h"
#include "read-sound-file.h"
#include "sound-theme-spec.h"
#include "malloc.h"
enum outstanding_type {
OUTSTANDING_SAMPLE,
OUTSTANDING_STREAM,
OUTSTANDING_UPLOAD
};
struct outstanding {
CA_LLIST_FIELDS(struct outstanding);
enum outstanding_type type;
ca_context *context;
uint32_t id;
uint32_t sink_input;
pa_stream *stream;
pa_operation *drain_operation;
ca_finish_callback_t callback;
void *userdata;
ca_sound_file *file;
int error;
unsigned clean_up:1; /* Handler needs to clean up the outstanding struct */
unsigned finished:1; /* finished playing */
};
struct private {
pa_threaded_mainloop *mainloop;
pa_context *context;
ca_theme_data *theme;
ca_bool_t subscribed;
ca_bool_t reconnect;
ca_mutex *outstanding_mutex;
CA_LLIST_HEAD(struct outstanding, outstanding);
};
#define PRIVATE(c) ((struct private *) ((c)->private))
static void context_state_cb(pa_context *pc, void *userdata);
static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata);
static void outstanding_disconnect(struct outstanding *o) {
ca_assert(o);
if (o->stream) {
if (o->drain_operation) {
pa_operation_cancel(o->drain_operation);
pa_operation_unref(o->drain_operation);
o->drain_operation = NULL;
}
pa_stream_set_write_callback(o->stream, NULL, NULL);
pa_stream_set_state_callback(o->stream, NULL, NULL);
pa_stream_disconnect(o->stream);
pa_stream_unref(o->stream);
o->stream = NULL;
}
}
static void outstanding_free(struct outstanding *o) {
ca_assert(o);
outstanding_disconnect(o);
if (o->file)
ca_sound_file_close(o->file);
ca_free(o);
}
static int convert_proplist(pa_proplist **_l, ca_proplist *c) {
pa_proplist *l;
ca_prop *i;
ca_return_val_if_fail(_l, CA_ERROR_INVALID);
ca_return_val_if_fail(c, CA_ERROR_INVALID);
if (!(l = pa_proplist_new()))
return CA_ERROR_OOM;
ca_mutex_lock(c->mutex);
for (i = c->first_item; i; i = i->next_item)
if (pa_proplist_set(l, i->key, CA_PROP_DATA(i), i->nbytes) < 0) {
ca_mutex_unlock(c->mutex);
pa_proplist_free(l);
return CA_ERROR_INVALID;
}
ca_mutex_unlock(c->mutex);
*_l = l;
return CA_SUCCESS;
}
static pa_proplist *strip_prefix(pa_proplist *l, const char *prefix) {
const char *key;
void *state = NULL;
ca_assert(l);
while ((key = pa_proplist_iterate(l, &state)))
if (strncmp(key, prefix, strlen(prefix)) == 0)
pa_proplist_unset(l, key);
return l;
}
static void add_common(pa_proplist *l) {
ca_assert(l);
if (!pa_proplist_contains(l, CA_PROP_MEDIA_ROLE))
pa_proplist_sets(l, CA_PROP_MEDIA_ROLE, "event");
if (!pa_proplist_contains(l, CA_PROP_MEDIA_NAME)) {
const char *t;
if ((t = pa_proplist_gets(l, CA_PROP_EVENT_ID)))
pa_proplist_sets(l, CA_PROP_MEDIA_NAME, t);
else if ((t = pa_proplist_gets(l, CA_PROP_MEDIA_FILENAME)))
pa_proplist_sets(l, CA_PROP_MEDIA_NAME, t);
else
pa_proplist_sets(l, CA_PROP_MEDIA_NAME, "libcanberra");
}
}
static int translate_error(int error) {
static const int table[PA_ERR_MAX] = {
[PA_OK] = CA_SUCCESS,
[PA_ERR_ACCESS] = CA_ERROR_ACCESS,
[PA_ERR_COMMAND] = CA_ERROR_IO,
[PA_ERR_INVALID] = CA_ERROR_INVALID,
[PA_ERR_EXIST] = CA_ERROR_IO,
[PA_ERR_NOENTITY] = CA_ERROR_NOTFOUND,
[PA_ERR_CONNECTIONREFUSED] = CA_ERROR_NOTAVAILABLE,
[PA_ERR_PROTOCOL] = CA_ERROR_IO,
[PA_ERR_TIMEOUT] = CA_ERROR_IO,
[PA_ERR_AUTHKEY] = CA_ERROR_ACCESS,
[PA_ERR_INTERNAL] = CA_ERROR_IO,
[PA_ERR_CONNECTIONTERMINATED] = CA_ERROR_IO,
[PA_ERR_KILLED] = CA_ERROR_DESTROYED,
[PA_ERR_INVALIDSERVER] = CA_ERROR_INVALID,
[PA_ERR_MODINITFAILED] = CA_ERROR_NODRIVER,
[PA_ERR_BADSTATE] = CA_ERROR_STATE,
[PA_ERR_NODATA] = CA_ERROR_IO,
[PA_ERR_VERSION] = CA_ERROR_NOTSUPPORTED,
[PA_ERR_TOOLARGE] = CA_ERROR_TOOBIG,
#ifdef PA_ERR_NOTSUPPORTED
[PA_ERR_NOTSUPPORTED] = CA_ERROR_NOTSUPPORTED,
#endif
#ifdef PA_ERR_UNKNOWN
[PA_ERR_UNKNOWN] = CA_ERROR_IO,
#endif
#ifdef PA_ERR_NOEXTENSION
[PA_ERR_NOEXTENSION] = CA_ERROR_NOTSUPPORTED,
#endif
#ifdef PA_ERR_OBSOLETE
[PA_ERR_OBSOLETE] = CA_ERROR_NOTSUPPORTED,
#endif
#ifdef PA_ERR_NOTIMPLEMENTED
[PA_ERR_NOTIMPLEMENTED] = CA_ERROR_NOTSUPPORTED
#endif
};
ca_assert(error >= 0);
if (error >= PA_ERR_MAX || !table[error])
return CA_ERROR_IO;
return table[error];
}
static int context_connect(ca_context *c, ca_bool_t nofail) {
pa_proplist *l;
struct private *p;
int ret;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(p = c->private, CA_ERROR_STATE);
ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE);
ca_return_val_if_fail(!p->context, CA_ERROR_STATE);
/* If this immediate attempt fails, don't try to reconnect. */
p->reconnect = FALSE;
if ((ret = convert_proplist(&l, c->props)) < 0)
return ret;
strip_prefix(l, "canberra.");
if (!pa_proplist_contains(l, PA_PROP_APPLICATION_NAME)) {
pa_proplist_sets(l, PA_PROP_APPLICATION_NAME, "libcanberra");
pa_proplist_sets(l, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
if (!pa_proplist_contains(l, PA_PROP_APPLICATION_ID))
pa_proplist_sets(l, PA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra");
}
if (!(p->context = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(p->mainloop), NULL, l))) {
pa_proplist_free(l);
return CA_ERROR_OOM;
}
pa_proplist_free(l);
pa_context_set_state_callback(p->context, context_state_cb, c);
pa_context_set_subscribe_callback(p->context, context_subscribe_cb, c);
if (pa_context_connect(p->context, NULL, nofail ? PA_CONTEXT_NOFAIL : 0, NULL) < 0) {
ret = translate_error(p->context ? pa_context_errno(p->context) : PA_ERR_CONNECTIONREFUSED);
if (p->context) {
pa_context_disconnect(p->context);
pa_context_unref(p->context);
p->context = NULL;
}
return ret;
}
return CA_SUCCESS;
}
static void context_state_cb(pa_context *pc, void *userdata) {
ca_context *c = userdata;
pa_context_state_t state;
struct private *p;
ca_assert(pc);
ca_assert(c);
p = PRIVATE(c);
state = pa_context_get_state(pc);
if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) {
struct outstanding *out;
int ret;
if (state == PA_CONTEXT_TERMINATED)
ret = CA_ERROR_DESTROYED;
else
ret = translate_error(pa_context_errno(pc));
ca_mutex_lock(p->outstanding_mutex);
while ((out = p->outstanding)) {
outstanding_disconnect(out);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (out->callback)
out->callback(c, out->id, ret, out->userdata);
outstanding_free(out);
ca_mutex_lock(p->outstanding_mutex);
}
ca_mutex_unlock(p->outstanding_mutex);
if (state == PA_CONTEXT_FAILED && p->reconnect) {
if (p->context) {
pa_context_disconnect(p->context);
pa_context_unref(p->context);
p->context = NULL;
}
p->subscribed = FALSE;
/* If we managed to connect once, then let's try to
* reconnect, and pass NOFAIL */
context_connect(c, TRUE);
}
} else if (state == PA_CONTEXT_READY)
/* OK, the connection suceeded once, if it dies now try to
* reconnect */
p->reconnect = TRUE;
pa_threaded_mainloop_signal(p->mainloop, FALSE);
}
static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
struct outstanding *out, *n;
CA_LLIST_HEAD(struct outstanding, l);
ca_context *c = userdata;
struct private *p;
ca_assert(pc);
ca_assert(c);
if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE))
return;
p = PRIVATE(c);
CA_LLIST_HEAD_INIT(struct outstanding, l);
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = n) {
n = out->next;
if (!out->clean_up || out->type != OUTSTANDING_SAMPLE || out->sink_input != idx)
continue;
outstanding_disconnect(out);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
CA_LLIST_PREPEND(struct outstanding, l, out);
}
ca_mutex_unlock(p->outstanding_mutex);
while (l) {
out = l;
CA_LLIST_REMOVE(struct outstanding, l, out);
if (out->callback)
out->callback(c, out->id, CA_SUCCESS, out->userdata);
outstanding_free(out);
}
}
int driver_open(ca_context *c) {
struct private *p;
int ret;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "pulse"), CA_ERROR_NODRIVER);
ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE);
if (!(c->private = p = ca_new0(struct private, 1)))
return CA_ERROR_OOM;
if (!(p->outstanding_mutex = ca_mutex_new())) {
driver_destroy(c);
return CA_ERROR_OOM;
}
if (!(p->mainloop = pa_threaded_mainloop_new())) {
driver_destroy(c);
return CA_ERROR_OOM;
}
/* The initial connection is without NOFAIL, since we want to have
* this call fail cleanly if we cannot connect. */
if ((ret = context_connect(c, FALSE)) != CA_SUCCESS) {
driver_destroy(c);
return ret;
}
pa_threaded_mainloop_lock(p->mainloop);
if (pa_threaded_mainloop_start(p->mainloop) < 0) {
pa_threaded_mainloop_unlock(p->mainloop);
driver_destroy(c);
return CA_ERROR_OOM;
}
for (;;) {
pa_context_state_t state;
if (!p->context) {
ret = translate_error(PA_ERR_CONNECTIONREFUSED);
pa_threaded_mainloop_unlock(p->mainloop);
driver_destroy(c);
return ret;
}
state = pa_context_get_state(p->context);
if (state == PA_CONTEXT_READY)
break;
if (state == PA_CONTEXT_FAILED) {
ret = translate_error(pa_context_errno(p->context));
pa_threaded_mainloop_unlock(p->mainloop);
driver_destroy(c);
return ret;
}
ca_assert(state != PA_CONTEXT_TERMINATED);
pa_threaded_mainloop_wait(p->mainloop);
}
pa_threaded_mainloop_unlock(p->mainloop);
return CA_SUCCESS;
}
int driver_destroy(ca_context *c) {
struct private *p;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
if (p->mainloop)
pa_threaded_mainloop_stop(p->mainloop);
if (p->context) {
pa_context_disconnect(p->context);
pa_context_unref(p->context);
}
while (p->outstanding) {
struct outstanding *out = p->outstanding;
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
if (out->callback)
out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata);
outstanding_free(out);
}
if (p->mainloop)
pa_threaded_mainloop_free(p->mainloop);
if (p->theme)
ca_theme_data_free(p->theme);
if (p->outstanding_mutex)
ca_mutex_free(p->outstanding_mutex);
ca_free(p);
c->private = NULL;
return CA_SUCCESS;
}
int driver_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
/* We're happy with any device change. We might however add code
* here eventually to move all currently played back event sounds
* to the new device. */
return CA_SUCCESS;
}
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
struct private *p;
pa_operation *o;
pa_proplist *l;
int ret = CA_SUCCESS;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(changed, CA_ERROR_INVALID);
ca_return_val_if_fail(merged, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE);
pa_threaded_mainloop_lock(p->mainloop);
if (!p->context) {
pa_threaded_mainloop_unlock(p->mainloop);
return CA_ERROR_STATE; /* can be silently ignored */
}
if ((ret = convert_proplist(&l, changed)) < 0)
return ret;
strip_prefix(l, "canberra.");
/* We start these asynchronously and don't care about the return
* value */
if (!(o = pa_context_proplist_update(p->context, PA_UPDATE_REPLACE, l, NULL, NULL)))
ret = translate_error(pa_context_errno(p->context));
else
pa_operation_unref(o);
pa_threaded_mainloop_unlock(p->mainloop);
pa_proplist_free(l);
return ret;
}
static int subscribe(ca_context *c) {
struct private *p;
pa_operation *o;
int ret = CA_SUCCESS;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE);
if (p->subscribed)
return CA_SUCCESS;
pa_threaded_mainloop_lock(p->mainloop);
if (!p->context) {
pa_threaded_mainloop_unlock(p->mainloop);
return CA_ERROR_STATE;
}
/* We start these asynchronously and don't care about the return
* value */
if (!(o = pa_context_subscribe(p->context, PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL)))
ret = translate_error(pa_context_errno(p->context));
else
pa_operation_unref(o);
pa_threaded_mainloop_unlock(p->mainloop);
p->subscribed = TRUE;
return ret;
}
static void play_sample_cb(pa_context *c, uint32_t idx, void *userdata) {
struct private *p;
struct outstanding *out = userdata;
ca_assert(c);
ca_assert(out);
p = PRIVATE(out->context);
if (idx != PA_INVALID_INDEX) {
out->error = CA_SUCCESS;
out->sink_input = idx;
} else
out->error = translate_error(pa_context_errno(c));
pa_threaded_mainloop_signal(p->mainloop, FALSE);
}
static void stream_state_cb(pa_stream *s, void *userdata) {
struct private *p;
struct outstanding *out = userdata;
pa_stream_state_t state;
ca_assert(s);
ca_assert(out);
p = PRIVATE(out->context);
state = pa_stream_get_state(s);
switch (state) {
case PA_STREAM_CREATING:
case PA_STREAM_UNCONNECTED:
break;
case PA_STREAM_READY:
out->sink_input = pa_stream_get_index(out->stream);
break;
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED: {
int err;
err = state == PA_STREAM_FAILED ? translate_error(pa_context_errno(pa_stream_get_context(s))) : CA_ERROR_DESTROYED;
if (out->clean_up) {
ca_mutex_lock(p->outstanding_mutex);
outstanding_disconnect(out);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (out->callback)
out->callback(out->context, out->id, out->error, out->userdata);
outstanding_free(out);
} else {
out->finished = TRUE;
out->error = err;
}
break;
}
}
pa_threaded_mainloop_signal(p->mainloop, FALSE);
}
static void stream_drain_cb(pa_stream *s, int success, void *userdata) {
struct private *p;
struct outstanding *out = userdata;
int err;
ca_assert(s);
ca_assert(out);
ca_assert(out->type == OUTSTANDING_STREAM);
p = PRIVATE(out->context);
err = success ? CA_SUCCESS : translate_error(pa_context_errno(p->context));
if (out->clean_up) {
ca_mutex_lock(p->outstanding_mutex);
outstanding_disconnect(out);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (out->callback)
out->callback(out->context, out->id, err, out->userdata);
outstanding_free(out);
} else {
pa_stream_disconnect(s);
out->error = err;
out->finished = TRUE;
if (out->drain_operation) {
pa_operation_unref(out->drain_operation);
out->drain_operation = NULL;
}
}
pa_threaded_mainloop_signal(p->mainloop, FALSE);
}
static void stream_write_cb(pa_stream *s, size_t bytes, void *userdata) {
struct outstanding *out = userdata;
struct private *p;
void *data;
int ret;
ca_bool_t eof = FALSE;
ca_assert(s);
ca_assert(bytes > 0);
ca_assert(out);
p = PRIVATE(out->context);
while (bytes > 0) {
size_t rbytes = bytes;
if (!(data = ca_malloc(rbytes))) {
ret = CA_ERROR_OOM;
goto finish;
}
if ((ret = ca_sound_file_read_arbitrary(out->file, data, &rbytes)) < 0)
goto finish;
if (rbytes <= 0) {
eof = TRUE;
break;
}
ca_assert(rbytes <= bytes);
if ((ret = pa_stream_write(s, data, rbytes, ca_free, 0, PA_SEEK_RELATIVE)) < 0) {
ret = translate_error(ret);
goto finish;
}
data = NULL;
bytes -= rbytes;
}
if (eof || ca_sound_file_get_size(out->file) <= 0) {
/* We reached EOF */
if (out->type == OUTSTANDING_UPLOAD) {
if (pa_stream_finish_upload(s) < 0) {
ret = translate_error(pa_context_errno(p->context));
goto finish;
}
/* Let's just signal driver_cache() which has been waiting for us */
pa_threaded_mainloop_signal(p->mainloop, FALSE);
} else {
ca_assert(out->type == OUTSTANDING_STREAM);
if (out->drain_operation) {
pa_operation_cancel(out->drain_operation);
pa_operation_unref(out->drain_operation);
}
if (!(out->drain_operation = pa_stream_drain(s, stream_drain_cb, out))) {
ret = translate_error(pa_context_errno(p->context));
goto finish;
}
}
pa_stream_set_write_callback(s, NULL, NULL);
}
ca_free(data);
return;
finish:
ca_free(data);
if (out->clean_up) {
ca_mutex_lock(p->outstanding_mutex);
outstanding_disconnect(out);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
if (out->callback)
out->callback(out->context, out->id, ret, out->userdata);
outstanding_free(out);
} else {
pa_stream_disconnect(s);
out->error = ret;
out->finished = TRUE;
}
pa_threaded_mainloop_signal(p->mainloop, FALSE);
}
static const pa_sample_format_t sample_type_table[] = {
[CA_SAMPLE_S16NE] = PA_SAMPLE_S16NE,
[CA_SAMPLE_S16RE] = PA_SAMPLE_S16RE,
[CA_SAMPLE_U8] = PA_SAMPLE_U8
};
static const pa_channel_position_t channel_table[_CA_CHANNEL_POSITION_MAX] = {
[CA_CHANNEL_MONO] = PA_CHANNEL_POSITION_MONO,
[CA_CHANNEL_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT,
[CA_CHANNEL_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT,
[CA_CHANNEL_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER,
[CA_CHANNEL_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT,
[CA_CHANNEL_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT,
[CA_CHANNEL_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTER,
[CA_CHANNEL_LFE] = PA_CHANNEL_POSITION_LFE,
[CA_CHANNEL_FRONT_LEFT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
[CA_CHANNEL_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
[CA_CHANNEL_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFT,
[CA_CHANNEL_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHT,
[CA_CHANNEL_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTER,
[CA_CHANNEL_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT,
[CA_CHANNEL_TOP_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT,
[CA_CHANNEL_TOP_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER,
[CA_CHANNEL_TOP_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT,
[CA_CHANNEL_TOP_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT,
[CA_CHANNEL_TOP_REAR_CENTER] = PA_CHANNEL_POSITION_TOP_REAR_CENTER
};
static ca_bool_t convert_channel_map(ca_sound_file *f, pa_channel_map *cm) {
const ca_channel_position_t *positions;
unsigned c;
ca_assert(f);
ca_assert(cm);
if (!(positions = ca_sound_file_get_channel_map(f)))
return FALSE;
cm->channels = ca_sound_file_get_nchannels(f);
for (c = 0; c < cm->channels; c++)
cm->map[c] = channel_table[positions[c]];
return TRUE;
}
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
struct private *p;
pa_proplist *l = NULL;
const char *n, *vol, *ct, *channel;
char *name = NULL;
#if defined(PA_MAJOR) && ((PA_MAJOR > 0) || (PA_MAJOR == 0 && PA_MINOR > 9) || (PA_MAJOR == 0 && PA_MINOR == 9 && PA_MICRO >= 15))
pa_volume_t v = (pa_volume_t) -1;
#else
pa_volume_t v = PA_VOLUME_NORM;
#endif
ca_bool_t volume_set = FALSE;
pa_cvolume cvol;
pa_sample_spec ss;
pa_channel_map cm;
pa_channel_position_t position = PA_CHANNEL_POSITION_INVALID;
ca_bool_t cm_good;
ca_cache_control_t cache_control = CA_CACHE_CONTROL_NEVER;
struct outstanding *out = NULL;
int try = 3;
int ret;
pa_operation *o;
char *sp;
pa_buffer_attr ba;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE);
if (!(out = ca_new0(struct outstanding, 1))) {
ret = CA_ERROR_OOM;
goto finish_unlocked;
}
out->type = OUTSTANDING_SAMPLE;
out->context = c;
out->sink_input = PA_INVALID_INDEX;
out->id = id;
out->callback = cb;
out->userdata = userdata;
if ((ret = convert_proplist(&l, proplist)) < 0)
goto finish_unlocked;
if ((n = pa_proplist_gets(l, CA_PROP_EVENT_ID)))
if (!(name = ca_strdup(n))) {
ret = CA_ERROR_OOM;
goto finish_unlocked;
}
if ((vol = pa_proplist_gets(l, CA_PROP_CANBERRA_VOLUME))) {
char *e = NULL;
double dvol;
errno = 0;
dvol = strtod(vol, &e);
if (errno != 0 || !e || *e) {
ret = CA_ERROR_INVALID;
goto finish_unlocked;
}
v = pa_sw_volume_from_dB(dvol);
volume_set = TRUE;
}
if ((ct = pa_proplist_gets(l, CA_PROP_CANBERRA_CACHE_CONTROL)))
if ((ret = ca_parse_cache_control(&cache_control, ct)) < 0) {
ret = CA_ERROR_INVALID;
goto finish_unlocked;
}
if ((channel = pa_proplist_gets(l, CA_PROP_CANBERRA_FORCE_CHANNEL))) {
pa_channel_map t;
if (!pa_channel_map_parse(&t, channel) ||
t.channels != 1) {
ret = CA_ERROR_INVALID;
goto finish_unlocked;
}
position = t.map[0];
/* We cannot remap cached samples, so let's fail when cacheing
* shall be used */
if (cache_control != CA_CACHE_CONTROL_NEVER) {
ret = CA_ERROR_NOTSUPPORTED;
goto finish_unlocked;
}
}
strip_prefix(l, "canberra.");
add_common(l);
if ((ret = subscribe(c)) < 0)
goto finish_unlocked;
if (name && cache_control != CA_CACHE_CONTROL_NEVER) {
/* Ok, this sample has an event id, let's try to play it from the cache */
for (;;) {
ca_bool_t canceled;
pa_threaded_mainloop_lock(p->mainloop);
if (!p->context) {
ret = CA_ERROR_STATE;
goto finish_locked;
}
/* Let's try to play the sample */
if (!(o = pa_context_play_sample_with_proplist(p->context, name, c->device, v, l, play_sample_cb, out))) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
for (;;) {
pa_operation_state_t state = pa_operation_get_state(o);
if (state == PA_OPERATION_DONE) {
canceled = FALSE;
break;
} else if (state == PA_OPERATION_CANCELED) {
canceled = TRUE;
break;
}
pa_threaded_mainloop_wait(p->mainloop);
}
pa_operation_unref(o);
if (!canceled && p->context && out->error == CA_SUCCESS) {
ret = CA_SUCCESS;
goto finish_locked;
}
pa_threaded_mainloop_unlock(p->mainloop);
/* The operation might have been canceled due to connection termination */
if (canceled || !p->context) {
ret = CA_ERROR_DISCONNECTED;
goto finish_unlocked;
}
/* Did some other error occur? */
if (out->error != CA_ERROR_NOTFOUND) {
ret = out->error;
goto finish_unlocked;
}
/* Hmm, we need to play it directly */
if (cache_control != CA_CACHE_CONTROL_PERMANENT)
break;
/* Don't loop forever */
if (--try <= 0)
break;
/* Let's upload the sample and retry playing */
if ((ret = driver_cache(c, proplist)) < 0)
goto finish_unlocked;
}
}
out->type = OUTSTANDING_STREAM;
/* Let's stream the sample directly */
if ((ret = ca_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0)
goto finish_unlocked;
if (sp)
if (!pa_proplist_contains(l, CA_PROP_MEDIA_FILENAME))
pa_proplist_sets(l, CA_PROP_MEDIA_FILENAME, sp);
ca_free(sp);
ss.format = sample_type_table[ca_sound_file_get_sample_type(out->file)];
ss.channels = (uint8_t) ca_sound_file_get_nchannels(out->file);
ss.rate = ca_sound_file_get_rate(out->file);
if (position != PA_CHANNEL_POSITION_INVALID) {
unsigned u;
/* Apply canberra.force_channel */
cm.channels = ss.channels;
for (u = 0; u < cm.channels; u++)
cm.map[u] = position;
cm_good = TRUE;
} else
cm_good = convert_channel_map(out->file, &cm);
pa_threaded_mainloop_lock(p->mainloop);
if (!p->context) {
ret = CA_ERROR_STATE;
goto finish_locked;
}
if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL, &ss, cm_good ? &cm : NULL, l))) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
pa_stream_set_state_callback(out->stream, stream_state_cb, out);
pa_stream_set_write_callback(out->stream, stream_write_cb, out);
if (volume_set)
pa_cvolume_set(&cvol, ss.channels, v);
/* Make sure we get the longest latency possible, to minimize CPU
* consumption */
ba.maxlength = (uint32_t) -1;
ba.tlength = (uint32_t) -1;
ba.prebuf = (uint32_t) -1;
ba.minreq = (uint32_t) -1;
ba.fragsize = (uint32_t) -1;
if (pa_stream_connect_playback(out->stream, c->device, &ba,
#ifdef PA_STREAM_FAIL_ON_SUSPEND
PA_STREAM_FAIL_ON_SUSPEND
#else
0
#endif
| (position != PA_CHANNEL_POSITION_INVALID ? PA_STREAM_NO_REMIX_CHANNELS : 0)
, volume_set ? &cvol : NULL, NULL) < 0) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
for (;;) {
pa_stream_state_t state;
if (!p->context || !out->stream) {
ret = CA_ERROR_STATE;
goto finish_locked;
}
state = pa_stream_get_state(out->stream);
/* Stream sucessfully created */
if (state == PA_STREAM_READY)
break;
/* Check for failure */
if (state == PA_STREAM_FAILED) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
/* Prematurely ended */
if (state == PA_STREAM_TERMINATED) {
ret = out->error;
goto finish_locked;
}
pa_threaded_mainloop_wait(p->mainloop);
}
ret = CA_SUCCESS;
finish_locked:
/* We keep the outstanding struct around to clean up later if the sound din't finish yet*/
if (ret == CA_SUCCESS && !out->finished) {
out->clean_up = TRUE;
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
} else
outstanding_free(out);
out = NULL;
pa_threaded_mainloop_unlock(p->mainloop);
finish_unlocked:
if (out)
outstanding_free(out);
if (l)
pa_proplist_free(l);
ca_free(name);
return ret;
}
int driver_cancel(ca_context *c, uint32_t id) {
struct private *p;
pa_operation *o;
int ret = CA_SUCCESS;
struct outstanding *out, *n;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE);
pa_threaded_mainloop_lock(p->mainloop);
if (!p->context) {
pa_threaded_mainloop_unlock(p->mainloop);
return CA_ERROR_STATE;
}
ca_mutex_lock(p->outstanding_mutex);
/* We start these asynchronously and don't care about the return
* value */
for (out = p->outstanding; out; out = n) {
int ret2 = CA_SUCCESS;
n = out->next;
if (out->type == OUTSTANDING_UPLOAD ||
out->id != id ||
out->sink_input == PA_INVALID_INDEX)
continue;
if (!(o = pa_context_kill_sink_input(p->context, out->sink_input, NULL, NULL)))
ret2 = translate_error(pa_context_errno(p->context));
else
pa_operation_unref(o);
/* We make sure here to kill all streams identified by the id
* here. However, we will return only the first error we
* encounter */
if (ret2 && ret == CA_SUCCESS)
ret = ret2;
if (out->callback)
out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
outstanding_disconnect(out);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
outstanding_free(out);
}
ca_mutex_unlock(p->outstanding_mutex);
pa_threaded_mainloop_unlock(p->mainloop);
return ret;
}
int driver_cache(ca_context *c, ca_proplist *proplist) {
struct private *p;
pa_proplist *l = NULL;
const char *n, *ct;
pa_sample_spec ss;
pa_channel_map cm;
ca_bool_t cm_good;
ca_cache_control_t cache_control = CA_CACHE_CONTROL_PERMANENT;
struct outstanding *out;
int ret;
char *sp;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
p = PRIVATE(c);
ca_return_val_if_fail(p->mainloop, CA_ERROR_STATE);
if (!(out = ca_new0(struct outstanding, 1))) {
ret = CA_ERROR_OOM;
goto finish_unlocked;
}
out->type = OUTSTANDING_UPLOAD;
out->context = c;
out->sink_input = PA_INVALID_INDEX;
if ((ret = convert_proplist(&l, proplist)) < 0)
goto finish_unlocked;
if (!(n = pa_proplist_gets(l, CA_PROP_EVENT_ID))) {
ret = CA_ERROR_INVALID;
goto finish_unlocked;
}
if ((ct = pa_proplist_gets(l, CA_PROP_CANBERRA_CACHE_CONTROL)))
if ((ret = ca_parse_cache_control(&cache_control, ct)) < 0) {
ret = CA_ERROR_INVALID;
goto finish_unlocked;
}
if (cache_control != CA_CACHE_CONTROL_PERMANENT) {
ret = CA_ERROR_INVALID;
goto finish_unlocked;
}
if ((ct = pa_proplist_gets(l, CA_PROP_CANBERRA_FORCE_CHANNEL))) {
ret = CA_ERROR_NOTSUPPORTED;
goto finish_unlocked;
}
strip_prefix(l, "canberra.");
strip_prefix(l, "event.mouse.");
strip_prefix(l, "window.");
add_common(l);
/* Let's stream the sample directly */
if ((ret = ca_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0)
goto finish_unlocked;
if (sp)
if (!pa_proplist_contains(l, CA_PROP_MEDIA_FILENAME))
pa_proplist_sets(l, CA_PROP_MEDIA_FILENAME, sp);
ca_free(sp);
ss.format = sample_type_table[ca_sound_file_get_sample_type(out->file)];
ss.channels = (uint8_t) ca_sound_file_get_nchannels(out->file);
ss.rate = ca_sound_file_get_rate(out->file);
cm_good = convert_channel_map(out->file, &cm);
pa_threaded_mainloop_lock(p->mainloop);
if (!p->context) {
ret = CA_ERROR_STATE;
goto finish_locked;
}
if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL, &ss, cm_good ? &cm : NULL, l))) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
pa_stream_set_state_callback(out->stream, stream_state_cb, out);
pa_stream_set_write_callback(out->stream, stream_write_cb, out);
if (pa_stream_connect_upload(out->stream, (size_t) ca_sound_file_get_size(out->file)) < 0) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
for (;;) {
pa_stream_state_t state;
if (!p->context || !out->stream) {
ret = CA_ERROR_STATE;
goto finish_locked;
}
state = pa_stream_get_state(out->stream);
/* Stream sucessfully created and uploaded */
if (state == PA_STREAM_TERMINATED)
break;
/* Check for failure */
if (state == PA_STREAM_FAILED) {
ret = translate_error(pa_context_errno(p->context));
goto finish_locked;
}
pa_threaded_mainloop_wait(p->mainloop);
}
ret = CA_SUCCESS;
finish_locked:
outstanding_free(out);
out = NULL;
pa_threaded_mainloop_unlock(p->mainloop);
finish_unlocked:
if (out)
outstanding_free(out);
if (l)
pa_proplist_free(l);
return ret;
}
int driver_playing(ca_context *c, uint32_t id, int *playing) {
struct private *p;
struct outstanding *out;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(c->private, CA_ERROR_STATE);
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
p = PRIVATE(c);
*playing = 0;
ca_mutex_lock(p->outstanding_mutex);
for (out = p->outstanding; out; out = out->next) {
if (out->type == OUTSTANDING_UPLOAD ||
out->id != id ||
out->sink_input == PA_INVALID_INDEX)
continue;
*playing = 1;
break;
}
ca_mutex_unlock(p->outstanding_mutex);
return CA_SUCCESS;
}
07070100000041000081A4000000000000000000000001509D8F37000017C9000000000000000000000000000000000000002900000000libcanberra-0.30+2/src/read-sound-file.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include "read-sound-file.h"
#include "read-wav.h"
#include "read-vorbis.h"
#include "macro.h"
#include "malloc.h"
#include "canberra.h"
struct ca_sound_file {
ca_wav *wav;
ca_vorbis *vorbis;
char *filename;
unsigned nchannels;
unsigned rate;
ca_sample_type_t type;
};
int ca_sound_file_open(ca_sound_file **_f, const char *fn) {
FILE *file;
ca_sound_file *f;
int ret;
ca_return_val_if_fail(_f, CA_ERROR_INVALID);
ca_return_val_if_fail(fn, CA_ERROR_INVALID);
if (!(f = ca_new0(ca_sound_file, 1)))
return CA_ERROR_OOM;
if (!(f->filename = ca_strdup(fn))) {
ret = CA_ERROR_OOM;
goto fail;
}
if (!(file = fopen(fn, "r"))) {
ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
goto fail;
}
if ((ret = ca_wav_open(&f->wav, file)) == CA_SUCCESS) {
f->nchannels = ca_wav_get_nchannels(f->wav);
f->rate = ca_wav_get_rate(f->wav);
f->type = ca_wav_get_sample_type(f->wav);
*_f = f;
return CA_SUCCESS;
}
if (ret == CA_ERROR_CORRUPT) {
if (fseek(file, 0, SEEK_SET) < 0) {
ret = CA_ERROR_SYSTEM;
goto fail;
}
if ((ret = ca_vorbis_open(&f->vorbis, file)) == CA_SUCCESS) {
f->nchannels = ca_vorbis_get_nchannels(f->vorbis);
f->rate = ca_vorbis_get_rate(f->vorbis);
f->type = CA_SAMPLE_S16NE;
*_f = f;
return CA_SUCCESS;
}
}
fail:
ca_free(f->filename);
ca_free(f);
return ret;
}
void ca_sound_file_close(ca_sound_file *f) {
ca_assert(f);
if (f->wav)
ca_wav_close(f->wav);
if (f->vorbis)
ca_vorbis_close(f->vorbis);
ca_free(f->filename);
ca_free(f);
}
unsigned ca_sound_file_get_nchannels(ca_sound_file *f) {
ca_assert(f);
return f->nchannels;
}
unsigned ca_sound_file_get_rate(ca_sound_file *f) {
ca_assert(f);
return f->rate;
}
ca_sample_type_t ca_sound_file_get_sample_type(ca_sound_file *f) {
ca_assert(f);
return f->type;
}
const ca_channel_position_t* ca_sound_file_get_channel_map(ca_sound_file *f) {
ca_assert(f);
if (f->wav)
return ca_wav_get_channel_map(f->wav);
else
return ca_vorbis_get_channel_map(f->vorbis);
}
int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n) {
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(d, CA_ERROR_INVALID);
ca_return_val_if_fail(n, CA_ERROR_INVALID);
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
ca_return_val_if_fail(f->wav || f->vorbis, CA_ERROR_STATE);
ca_return_val_if_fail(f->type == CA_SAMPLE_S16NE || f->type == CA_SAMPLE_S16RE, CA_ERROR_STATE);
if (f->wav)
return ca_wav_read_s16le(f->wav, d, n);
else
return ca_vorbis_read_s16ne(f->vorbis, d, n);
}
int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n) {
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(d, CA_ERROR_INVALID);
ca_return_val_if_fail(n, CA_ERROR_INVALID);
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
ca_return_val_if_fail(f->wav && !f->vorbis, CA_ERROR_STATE);
ca_return_val_if_fail(f->type == CA_SAMPLE_U8, CA_ERROR_STATE);
if (f->wav)
return ca_wav_read_u8(f->wav, d, n);
return CA_ERROR_STATE;
}
int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n) {
int ret;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(d, CA_ERROR_INVALID);
ca_return_val_if_fail(n, CA_ERROR_INVALID);
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
switch (f->type) {
case CA_SAMPLE_S16NE:
case CA_SAMPLE_S16RE: {
size_t k;
k = *n / sizeof(int16_t);
if ((ret = ca_sound_file_read_int16(f, d, &k)) == CA_SUCCESS)
*n = k * sizeof(int16_t);
break;
}
case CA_SAMPLE_U8: {
size_t k;
k = *n;
if ((ret = ca_sound_file_read_uint8(f, d, &k)) == CA_SUCCESS)
*n = k;
break;
}
default:
ca_assert_not_reached();
}
return ret;
}
off_t ca_sound_file_get_size(ca_sound_file *f) {
ca_return_val_if_fail(f, (off_t) -1);
if (f->wav)
return ca_wav_get_size(f->wav);
else
return ca_vorbis_get_size(f->vorbis);
}
size_t ca_sound_file_frame_size(ca_sound_file *f) {
unsigned c;
ca_assert(f);
c = ca_sound_file_get_nchannels(f);
return c * (ca_sound_file_get_sample_type(f) == CA_SAMPLE_U8 ? 1U : 2U);
}
07070100000042000081A4000000000000000000000001509D8F37000009A1000000000000000000000000000000000000002900000000libcanberra-0.30+2/src/read-sound-file.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberrareadsoundfilehfoo
#define foocanberrareadsoundfilehfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <sys/types.h>
#include <inttypes.h>
typedef enum ca_sample_type {
CA_SAMPLE_S16NE,
CA_SAMPLE_S16RE,
CA_SAMPLE_U8
} ca_sample_type_t;
typedef enum ca_channel_position {
CA_CHANNEL_MONO,
CA_CHANNEL_FRONT_LEFT,
CA_CHANNEL_FRONT_RIGHT,
CA_CHANNEL_FRONT_CENTER,
CA_CHANNEL_REAR_LEFT,
CA_CHANNEL_REAR_RIGHT,
CA_CHANNEL_REAR_CENTER,
CA_CHANNEL_LFE,
CA_CHANNEL_FRONT_LEFT_OF_CENTER,
CA_CHANNEL_FRONT_RIGHT_OF_CENTER,
CA_CHANNEL_SIDE_LEFT,
CA_CHANNEL_SIDE_RIGHT,
CA_CHANNEL_TOP_CENTER,
CA_CHANNEL_TOP_FRONT_LEFT,
CA_CHANNEL_TOP_FRONT_RIGHT,
CA_CHANNEL_TOP_FRONT_CENTER,
CA_CHANNEL_TOP_REAR_LEFT,
CA_CHANNEL_TOP_REAR_RIGHT,
CA_CHANNEL_TOP_REAR_CENTER,
_CA_CHANNEL_POSITION_MAX
} ca_channel_position_t;
typedef struct ca_sound_file ca_sound_file;
int ca_sound_file_open(ca_sound_file **f, const char *fn);
void ca_sound_file_close(ca_sound_file *f);
unsigned ca_sound_file_get_nchannels(ca_sound_file *f);
unsigned ca_sound_file_get_rate(ca_sound_file *f);
ca_sample_type_t ca_sound_file_get_sample_type(ca_sound_file *f);
const ca_channel_position_t* ca_sound_file_get_channel_map(ca_sound_file *f);
off_t ca_sound_file_get_size(ca_sound_file *f);
int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n);
int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n);
int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n);
size_t ca_sound_file_frame_size(ca_sound_file *f);
#endif
07070100000043000081A4000000000000000000000001509D8F3700001A20000000000000000000000000000000000000002500000000libcanberra-0.30+2/src/read-vorbis.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <vorbis/vorbisfile.h>
#include <vorbis/codec.h>
#include "canberra.h"
#include "read-vorbis.h"
#include "macro.h"
#include "malloc.h"
#define FILE_SIZE_MAX ((off_t) (64U*1024U*1024U))
struct ca_vorbis {
OggVorbis_File ovf;
off_t size;
ca_channel_position_t channel_map[8];
};
static int convert_error(int or) {
switch (or) {
case OV_ENOSEEK:
case OV_EBADPACKET:
case OV_EBADLINK:
case OV_EFAULT:
case OV_EREAD:
case OV_HOLE:
return CA_ERROR_IO;
case OV_EIMPL:
case OV_EVERSION:
case OV_ENOTAUDIO:
return CA_ERROR_NOTSUPPORTED;
case OV_ENOTVORBIS:
case OV_EBADHEADER:
case OV_EOF:
return CA_ERROR_CORRUPT;
case OV_EINVAL:
return CA_ERROR_INVALID;
default:
return CA_ERROR_IO;
}
}
int ca_vorbis_open(ca_vorbis **_v, FILE *f) {
int ret, or;
ca_vorbis *v;
int64_t n;
ca_return_val_if_fail(_v, CA_ERROR_INVALID);
ca_return_val_if_fail(f, CA_ERROR_INVALID);
if (!(v = ca_new0(ca_vorbis, 1)))
return CA_ERROR_OOM;
if ((or = ov_open(f, &v->ovf, NULL, 0)) < 0) {
ret = convert_error(or);
goto fail;
}
if ((n = ov_pcm_total(&v->ovf, -1)) < 0) {
ret = convert_error(or);
ov_clear(&v->ovf);
goto fail;
}
if (((off_t) n * (off_t) sizeof(int16_t)) > FILE_SIZE_MAX) {
ret = CA_ERROR_TOOBIG;
ov_clear(&v->ovf);
goto fail;
}
v->size = (off_t) n * (off_t) sizeof(int16_t) * ca_vorbis_get_nchannels(v);
*_v = v;
return CA_SUCCESS;
fail:
ca_free(v);
return ret;
}
void ca_vorbis_close(ca_vorbis *v) {
ca_assert(v);
ov_clear(&v->ovf);
ca_free(v);
}
unsigned ca_vorbis_get_nchannels(ca_vorbis *v) {
const vorbis_info *vi;
ca_assert(v);
ca_assert_se(vi = ov_info(&v->ovf, -1));
return (unsigned) vi->channels;
}
unsigned ca_vorbis_get_rate(ca_vorbis *v) {
const vorbis_info *vi;
ca_assert(v);
ca_assert_se(vi = ov_info(&v->ovf, -1));
return (unsigned) vi->rate;
}
const ca_channel_position_t* ca_vorbis_get_channel_map(ca_vorbis *v) {
/* See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */
switch (ca_vorbis_get_nchannels(v)) {
case 8:
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
v->channel_map[1] = CA_CHANNEL_FRONT_CENTER;
v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT;
v->channel_map[3] = CA_CHANNEL_SIDE_LEFT;
v->channel_map[4] = CA_CHANNEL_SIDE_RIGHT;
v->channel_map[5] = CA_CHANNEL_REAR_LEFT;
v->channel_map[6] = CA_CHANNEL_REAR_RIGHT;
v->channel_map[7] = CA_CHANNEL_LFE;
return v->channel_map;
case 7:
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
v->channel_map[1] = CA_CHANNEL_FRONT_CENTER;
v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT;
v->channel_map[3] = CA_CHANNEL_SIDE_LEFT;
v->channel_map[4] = CA_CHANNEL_SIDE_RIGHT;
v->channel_map[5] = CA_CHANNEL_REAR_CENTER;
v->channel_map[6] = CA_CHANNEL_LFE;
return v->channel_map;
case 6:
v->channel_map[5] = CA_CHANNEL_LFE;
/* fall through */
case 5:
v->channel_map[3] = CA_CHANNEL_REAR_LEFT;
v->channel_map[4] = CA_CHANNEL_REAR_RIGHT;
/* fall through */
case 3:
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
v->channel_map[1] = CA_CHANNEL_FRONT_CENTER;
v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT;
return v->channel_map;
case 4:
v->channel_map[2] = CA_CHANNEL_REAR_LEFT;
v->channel_map[3] = CA_CHANNEL_REAR_RIGHT;
/* fall through */
case 2:
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
v->channel_map[1] = CA_CHANNEL_FRONT_RIGHT;
return v->channel_map;
case 1:
v->channel_map[0] = CA_CHANNEL_MONO;
return v->channel_map;
}
return NULL;
}
int ca_vorbis_read_s16ne(ca_vorbis *v, int16_t *d, size_t *n){
long r;
int section;
int length;
size_t n_read = 0;
ca_return_val_if_fail(v, CA_ERROR_INVALID);
ca_return_val_if_fail(d, CA_ERROR_INVALID);
ca_return_val_if_fail(n, CA_ERROR_INVALID);
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
length = (int) (*n * sizeof(int16_t));
do {
r = ov_read(&v->ovf, (char*) d, length,
#ifdef WORDS_BIGENDIAN
1,
#else
0,
#endif
2, 1, §ion);
if (r < 0)
return convert_error((int) r);
if (r == 0)
break;
/* We only read the first section */
if (section != 0)
break;
length -= (int) r;
d += r/sizeof(int16_t);
n_read += (size_t) r;
} while (length >= 4096);
ca_assert(v->size >= (off_t) n_read);
v->size -= (off_t) n_read;
*n = n_read/sizeof(int16_t);
return CA_SUCCESS;
}
off_t ca_vorbis_get_size(ca_vorbis *v) {
ca_return_val_if_fail(v, (off_t) -1);
return v->size;
}
07070100000044000081A4000000000000000000000001509D8F370000051E000000000000000000000000000000000000002500000000libcanberra-0.30+2/src/read-vorbis.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberrareadvorbishfoo
#define foocanberrareadvorbishfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <stdio.h>
#include <inttypes.h>
#include "read-sound-file.h"
typedef struct ca_vorbis ca_vorbis;
int ca_vorbis_open(ca_vorbis **v, FILE *f);
void ca_vorbis_close(ca_vorbis *v);
unsigned ca_vorbis_get_nchannels(ca_vorbis *v);
unsigned ca_vorbis_get_rate(ca_vorbis *v);
const ca_channel_position_t* ca_vorbis_get_channel_map(ca_vorbis *v);
int ca_vorbis_read_s16ne(ca_vorbis *v, int16_t *d, size_t *n);
off_t ca_vorbis_get_size(ca_vorbis *f);
#endif
07070100000045000081A4000000000000000000000001509D8F370000278F000000000000000000000000000000000000002200000000libcanberra-0.30+2/src/read-wav.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "canberra.h"
#include "read-wav.h"
#include "macro.h"
#include "malloc.h"
#define FILE_SIZE_MAX (64U*1024U*1024U)
/* Stores the bit indexes in dwChannelMask */
enum {
BIT_FRONT_LEFT,
BIT_FRONT_RIGHT,
BIT_FRONT_CENTER,
BIT_LOW_FREQUENCY,
BIT_BACK_LEFT,
BIT_BACK_RIGHT,
BIT_FRONT_LEFT_OF_CENTER,
BIT_FRONT_RIGHT_OF_CENTER,
BIT_BACK_CENTER,
BIT_SIDE_LEFT,
BIT_SIDE_RIGHT,
BIT_TOP_CENTER,
BIT_TOP_FRONT_LEFT,
BIT_TOP_FRONT_CENTER,
BIT_TOP_FRONT_RIGHT,
BIT_TOP_BACK_LEFT,
BIT_TOP_BACK_CENTER,
BIT_TOP_BACK_RIGHT,
_BIT_MAX
};
static const ca_channel_position_t channel_table[_BIT_MAX] = {
[BIT_FRONT_LEFT] = CA_CHANNEL_FRONT_LEFT,
[BIT_FRONT_RIGHT] = CA_CHANNEL_FRONT_RIGHT,
[BIT_FRONT_CENTER] = CA_CHANNEL_FRONT_CENTER,
[BIT_LOW_FREQUENCY] = CA_CHANNEL_LFE,
[BIT_BACK_LEFT] = CA_CHANNEL_REAR_LEFT,
[BIT_BACK_RIGHT] = CA_CHANNEL_REAR_RIGHT,
[BIT_FRONT_LEFT_OF_CENTER] = CA_CHANNEL_FRONT_LEFT_OF_CENTER,
[BIT_FRONT_RIGHT_OF_CENTER] = CA_CHANNEL_FRONT_RIGHT_OF_CENTER,
[BIT_BACK_CENTER] = CA_CHANNEL_REAR_CENTER,
[BIT_SIDE_LEFT] = CA_CHANNEL_SIDE_LEFT,
[BIT_SIDE_RIGHT] = CA_CHANNEL_SIDE_RIGHT,
[BIT_TOP_CENTER] = CA_CHANNEL_TOP_CENTER,
[BIT_TOP_FRONT_LEFT] = CA_CHANNEL_TOP_FRONT_LEFT,
[BIT_TOP_FRONT_CENTER] = CA_CHANNEL_TOP_FRONT_CENTER,
[BIT_TOP_FRONT_RIGHT] = CA_CHANNEL_TOP_FRONT_RIGHT,
[BIT_TOP_BACK_LEFT] = CA_CHANNEL_TOP_REAR_LEFT,
[BIT_TOP_BACK_CENTER] = CA_CHANNEL_TOP_REAR_CENTER,
[BIT_TOP_BACK_RIGHT] = CA_CHANNEL_TOP_REAR_RIGHT
};
struct ca_wav {
FILE *file;
off_t data_size;
unsigned nchannels;
unsigned rate;
unsigned depth;
uint32_t channel_mask;
ca_channel_position_t channel_map[_BIT_MAX];
};
#define CHUNK_ID_DATA 0x61746164U
#define CHUNK_ID_FMT 0x20746d66U
static const uint8_t pcm_guid[16] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
};
static int skip_to_chunk(ca_wav *w, uint32_t id, uint32_t *size) {
ca_return_val_if_fail(w, CA_ERROR_INVALID);
ca_return_val_if_fail(size, CA_ERROR_INVALID);
for (;;) {
uint32_t chunk[2];
uint32_t s;
if (fread(chunk, sizeof(uint32_t), CA_ELEMENTSOF(chunk), w->file) != CA_ELEMENTSOF(chunk))
goto fail_io;
s = CA_UINT32_FROM_LE(chunk[1]);
if (s <= 0 || s >= FILE_SIZE_MAX)
return CA_ERROR_TOOBIG;
if (CA_UINT32_FROM_LE(chunk[0]) == id) {
*size = s;
break;
}
if (fseek(w->file, (long) s, SEEK_CUR) < 0)
return CA_ERROR_SYSTEM;
}
return CA_SUCCESS;
fail_io:
if (feof(w->file))
return CA_ERROR_CORRUPT;
else if (ferror(w->file))
return CA_ERROR_SYSTEM;
ca_assert_not_reached();
}
int ca_wav_open(ca_wav **_w, FILE *f) {
uint32_t header[3], fmt_chunk[10];
int ret;
ca_wav *w;
uint32_t file_size, fmt_size, data_size;
ca_bool_t extensible;
uint32_t format;
ca_return_val_if_fail(_w, CA_ERROR_INVALID);
ca_return_val_if_fail(f, CA_ERROR_INVALID);
if (!(w = ca_new(ca_wav, 1)))
return CA_ERROR_OOM;
w->file = f;
if (fread(header, sizeof(uint32_t), CA_ELEMENTSOF(header), f) != CA_ELEMENTSOF(header))
goto fail_io;
if (CA_UINT32_FROM_LE(header[0]) != 0x46464952U ||
CA_UINT32_FROM_LE(header[2]) != 0x45564157U) {
ret = CA_ERROR_CORRUPT;
goto fail;
}
file_size = CA_UINT32_FROM_LE(header[1]);
if (file_size <= 0 || file_size >= FILE_SIZE_MAX) {
ret = CA_ERROR_TOOBIG;
goto fail;
}
/* Skip to the fmt chunk */
if ((ret = skip_to_chunk(w, CHUNK_ID_FMT, &fmt_size)) < 0)
goto fail;
switch (fmt_size) {
case 14: /* WAVEFORMAT */
case 16:
case 18: /* WAVEFORMATEX */
extensible = FALSE;
break;
case 40: /* WAVEFORMATEXTENSIBLE */
extensible = TRUE;
break;
default:
ret = CA_ERROR_NOTSUPPORTED;
goto fail;
}
if (fread(fmt_chunk, 1, fmt_size, f) != fmt_size)
goto fail_io;
/* PCM? or WAVEX? */
format = (CA_UINT32_FROM_LE(fmt_chunk[0]) & 0xFFFF);
if ((!extensible && format != 0x0001) ||
(extensible && format != 0xFFFE)) {
ret = CA_ERROR_NOTSUPPORTED;
goto fail;
}
if (extensible) {
if (memcmp(fmt_chunk + 6, pcm_guid, 16) != 0) {
ret = CA_ERROR_NOTSUPPORTED;
goto fail;
}
w->channel_mask = CA_UINT32_FROM_LE(fmt_chunk[5]);
} else
w->channel_mask = 0;
w->nchannels = CA_UINT32_FROM_LE(fmt_chunk[0]) >> 16;
w->rate = CA_UINT32_FROM_LE(fmt_chunk[1]);
w->depth = CA_UINT32_FROM_LE(fmt_chunk[3]) >> 16;
if (w->nchannels <= 0 || w->rate <= 0) {
ret = CA_ERROR_CORRUPT;
goto fail;
}
if (w->depth != 16 && w->depth != 8) {
ret = CA_ERROR_NOTSUPPORTED;
goto fail;
}
/* Skip to the data chunk */
if ((ret = skip_to_chunk(w, CHUNK_ID_DATA, &data_size)) < 0)
goto fail;
w->data_size = (off_t) data_size;
if ((w->data_size % (w->depth/8)) != 0) {
ret = CA_ERROR_CORRUPT;
goto fail;
}
*_w = w;
return CA_SUCCESS;
fail_io:
if (feof(f))
ret = CA_ERROR_CORRUPT;
else if (ferror(f))
ret = CA_ERROR_SYSTEM;
else
ca_assert_not_reached();
fail:
ca_free(w);
return ret;
}
void ca_wav_close(ca_wav *w) {
ca_assert(w);
fclose(w->file);
ca_free(w);
}
unsigned ca_wav_get_nchannels(ca_wav *w) {
ca_assert(w);
return w->nchannels;
}
unsigned ca_wav_get_rate(ca_wav *w) {
ca_assert(w);
return w->rate;
}
const ca_channel_position_t* ca_wav_get_channel_map(ca_wav *w) {
unsigned c;
ca_channel_position_t *p;
ca_assert(w);
if (!w->channel_mask)
return NULL;
p = w->channel_map;
for (c = 0; c < _BIT_MAX; c++)
if ((w->channel_mask & (1 << c)))
*(p++) = channel_table[c];
ca_assert(p <= w->channel_map + _BIT_MAX);
if (p != w->channel_map + w->nchannels)
return NULL;
return w->channel_map;
}
ca_sample_type_t ca_wav_get_sample_type(ca_wav *w) {
ca_assert(w);
return w->depth == 16 ?
#ifdef WORDS_BIGENDIAN
CA_SAMPLE_S16RE
#else
CA_SAMPLE_S16NE
#endif
: CA_SAMPLE_U8;
}
int ca_wav_read_s16le(ca_wav *w, int16_t *d, size_t *n) {
off_t remaining;
ca_return_val_if_fail(w, CA_ERROR_INVALID);
ca_return_val_if_fail(w->depth == 16, CA_ERROR_INVALID);
ca_return_val_if_fail(d, CA_ERROR_INVALID);
ca_return_val_if_fail(n, CA_ERROR_INVALID);
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
remaining = w->data_size / (off_t) sizeof(int16_t);
if ((off_t) *n > remaining)
*n = (size_t) remaining;
if (*n > 0) {
*n = fread(d, sizeof(int16_t), *n, w->file);
if (*n <= 0 && ferror(w->file))
return CA_ERROR_SYSTEM;
ca_assert(w->data_size >= (off_t) *n * (off_t) sizeof(int16_t));
w->data_size -= (off_t) *n * (off_t) sizeof(int16_t);
}
return CA_SUCCESS;
}
int ca_wav_read_u8(ca_wav *w, uint8_t *d, size_t *n) {
off_t remaining;
ca_return_val_if_fail(w, CA_ERROR_INVALID);
ca_return_val_if_fail(w->depth == 8, CA_ERROR_INVALID);
ca_return_val_if_fail(d, CA_ERROR_INVALID);
ca_return_val_if_fail(n, CA_ERROR_INVALID);
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
remaining = w->data_size / (off_t) sizeof(uint8_t);
if ((off_t) *n > remaining)
*n = (size_t) remaining;
if (*n > 0) {
*n = fread(d, sizeof(uint8_t), *n, w->file);
if (*n <= 0 && ferror(w->file))
return CA_ERROR_SYSTEM;
ca_assert(w->data_size >= (off_t) *n * (off_t) sizeof(uint8_t));
w->data_size -= (off_t) *n * (off_t) sizeof(uint8_t);
}
return CA_SUCCESS;
}
off_t ca_wav_get_size(ca_wav *v) {
ca_return_val_if_fail(v, (off_t) -1);
return v->data_size;
}
07070100000046000081A4000000000000000000000001509D8F370000053C000000000000000000000000000000000000002200000000libcanberra-0.30+2/src/read-wav.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberrareadwavhfoo
#define foocanberrareadwavhfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <stdio.h>
#include "read-sound-file.h"
typedef struct ca_wav ca_wav;
int ca_wav_open(ca_wav **v, FILE *f);
void ca_wav_close(ca_wav *f);
unsigned ca_wav_get_nchannels(ca_wav *f);
unsigned ca_wav_get_rate(ca_wav *f);
ca_sample_type_t ca_wav_get_sample_type(ca_wav *f);
const ca_channel_position_t* ca_wav_get_channel_map(ca_wav *f);
int ca_wav_read_u8(ca_wav *f, uint8_t *d, size_t *n);
int ca_wav_read_s16le(ca_wav *f, int16_t *d, size_t *n);
off_t ca_wav_get_size(ca_wav *f);
#endif
07070100000047000081A4000000000000000000000001509D8F3700006E1F000000000000000000000000000000000000002A00000000libcanberra-0.30+2/src/sound-theme-spec.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <unistd.h>
#include <locale.h>
#include "sound-theme-spec.h"
#include "malloc.h"
#include "llist.h"
#include "cache.h"
#define DEFAULT_THEME "freedesktop"
#define FALLBACK_THEME "freedesktop"
#define DEFAULT_OUTPUT_PROFILE "stereo"
#define N_THEME_DIR_MAX 8
typedef struct ca_data_dir ca_data_dir;
struct ca_data_dir {
CA_LLIST_FIELDS(ca_data_dir);
char *theme_name;
char *dir_name;
char *output_profile;
};
struct ca_theme_data {
char *name;
CA_LLIST_HEAD(ca_data_dir, data_dirs);
ca_data_dir *last_dir;
unsigned n_theme_dir;
ca_bool_t loaded_fallback_theme;
};
int ca_get_data_home(char **e) {
const char *env, *subdir;
char *r;
ca_return_val_if_fail(e, CA_ERROR_INVALID);
if ((env = getenv("XDG_DATA_HOME")) && *env == '/')
subdir = "";
else if ((env = getenv("HOME")) && *env == '/')
subdir = "/.local/share";
else {
*e = NULL;
return CA_SUCCESS;
}
if (!(r = ca_new(char, strlen(env) + strlen(subdir) + 1)))
return CA_ERROR_OOM;
sprintf(r, "%s%s", env, subdir);
*e = r;
return CA_SUCCESS;
}
static ca_bool_t data_dir_matches(ca_data_dir *d, const char*output_profile) {
ca_assert(d);
ca_assert(output_profile);
/* We might want to add more elaborate matching here eventually */
if (!d->output_profile)
return TRUE;
return ca_streq(d->output_profile, output_profile);
}
static ca_data_dir* find_data_dir(ca_theme_data *t, const char *theme_name, const char *dir_name) {
ca_data_dir *d;
ca_assert(t);
ca_assert(theme_name);
ca_assert(dir_name);
for (d = t->data_dirs; d; d = d->next)
if (ca_streq(d->theme_name, theme_name) &&
ca_streq(d->dir_name, dir_name))
return d;
return NULL;
}
static int add_data_dir(ca_theme_data *t, const char *theme_name, const char *dir_name) {
ca_data_dir *d;
ca_return_val_if_fail(t, CA_ERROR_INVALID);
ca_return_val_if_fail(theme_name, CA_ERROR_INVALID);
ca_return_val_if_fail(dir_name, CA_ERROR_INVALID);
if (find_data_dir(t, theme_name, dir_name))
return CA_SUCCESS;
if (!(d = ca_new0(ca_data_dir, 1)))
return CA_ERROR_OOM;
if (!(d->theme_name = ca_strdup(theme_name))) {
ca_free(d);
return CA_ERROR_OOM;
}
if (!(d->dir_name = ca_strdup(dir_name))) {
ca_free(d->theme_name);
ca_free(d);
return CA_ERROR_OOM;
}
CA_LLIST_INSERT_AFTER(ca_data_dir, t->data_dirs, t->last_dir, d);
t->last_dir = d;
return CA_SUCCESS;
}
static int load_theme_dir(ca_theme_data *t, const char *name);
static int load_theme_path(ca_theme_data *t, const char *prefix, const char *name) {
char *fn, *inherits = NULL;
FILE *f;
ca_bool_t in_sound_theme_section = FALSE;
ca_data_dir *current_data_dir = NULL;
int ret;
ca_return_val_if_fail(t, CA_ERROR_INVALID);
ca_return_val_if_fail(prefix, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
if (!(fn = ca_new(char, strlen(prefix) + sizeof("/sounds/")-1 + strlen(name) + sizeof("/index.theme"))))
return CA_ERROR_OOM;
sprintf(fn, "%s/sounds/%s/index.theme", prefix, name);
f = fopen(fn, "r");
ca_free(fn);
if (!f) {
if (errno == ENOENT)
return CA_ERROR_NOTFOUND;
return CA_ERROR_SYSTEM;
}
for (;;) {
char ln[1024];
if (!(fgets(ln, sizeof(ln), f))) {
if (feof(f))
break;
ca_assert(ferror(f));
ret = CA_ERROR_SYSTEM;
goto fail;
}
ln[strcspn(ln, "\n\r#")] = 0;
if (!ln[0])
continue;
if (ca_streq(ln, "[Sound Theme]")) {
in_sound_theme_section = TRUE;
current_data_dir = NULL;
continue;
}
if (ln[0] == '[' && ln[strlen(ln)-1] == ']') {
char *d;
if (!(d = ca_strndup(ln+1, strlen(ln)-2))) {
ret = CA_ERROR_OOM;
goto fail;
}
current_data_dir = find_data_dir(t, name, d);
ca_free(d);
in_sound_theme_section = FALSE;
continue;
}
ca_assert(!in_sound_theme_section || !current_data_dir);
ca_assert(!current_data_dir || !in_sound_theme_section);
if (in_sound_theme_section) {
if (!strncmp(ln, "Inherits=", 9)) {
if (inherits) {
ret = CA_ERROR_CORRUPT;
goto fail;
}
if (!(inherits = ca_strdup(ln + 9))) {
ret = CA_ERROR_OOM;
goto fail;
}
continue;
}
if (!strncmp(ln, "Directories=", 12)) {
char *d;
d = ln+12;
for (;;) {
size_t k = strcspn(d, ", ");
if (k > 0) {
char *p;
if (!(p = ca_strndup(d, k))) {
ret = CA_ERROR_OOM;
goto fail;
}
ret = add_data_dir(t, name, p);
ca_free(p);
if (ret != CA_SUCCESS)
goto fail;
}
if (d[k] == 0)
break;
d += k+1;
}
continue;
}
}
if (current_data_dir) {
if (!strncmp(ln, "OutputProfile=", 14)) {
if (!current_data_dir->output_profile) {
if (!(current_data_dir->output_profile = ca_strdup(ln+14))) {
ret = CA_ERROR_OOM;
goto fail;
}
} else if (!ca_streq(current_data_dir->output_profile, ln+14)) {
ret = CA_ERROR_CORRUPT;
goto fail;
}
continue;
}
}
}
t->n_theme_dir ++;
if (inherits) {
char *i = inherits;
for (;;) {
size_t k = strcspn(i, ", ");
if (k > 0) {
char *p;
if (!(p = ca_strndup(i, k))) {
ret = CA_ERROR_OOM;
goto fail;
}
ret = load_theme_dir(t, p);
ca_free(p);
if (ret != CA_SUCCESS)
goto fail;
}
if (i[k] == 0)
break;
i += k+1;
}
}
ret = CA_SUCCESS;
fail:
ca_free(inherits);
fclose(f);
return ret;
}
const char *ca_get_data_dirs(void) {
const char *g;
if (!(g = getenv("XDG_DATA_DIRS")) || *g == 0)
return "/usr/local/share:/usr/share";
return g;
}
static int load_theme_dir(ca_theme_data *t, const char *name) {
int ret;
char *e;
const char *g;
ca_return_val_if_fail(t, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
ca_return_val_if_fail(t->n_theme_dir < N_THEME_DIR_MAX, CA_ERROR_CORRUPT);
if (ca_streq(name, FALLBACK_THEME))
t->loaded_fallback_theme = TRUE;
if ((ret = ca_get_data_home(&e)) < 0)
return ret;
if (e) {
ret = load_theme_path(t, e, name);
ca_free(e);
if (ret != CA_ERROR_NOTFOUND)
return ret;
}
g = ca_get_data_dirs();
for (;;) {
size_t k;
k = strcspn(g, ":");
if (g[0] == '/' && k > 0) {
char *p;
if (!(p = ca_strndup(g, k)))
return CA_ERROR_OOM;
ret = load_theme_path(t, p, name);
ca_free(p);
if (ret != CA_ERROR_NOTFOUND)
return ret;
}
if (g[k] == 0)
break;
g += k+1;
}
return CA_ERROR_NOTFOUND;
}
static int load_theme_data(ca_theme_data **_t, const char *name) {
ca_theme_data *t;
int ret;
ca_return_val_if_fail(_t, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
if (*_t)
if (ca_streq((*_t)->name, name))
return CA_SUCCESS;
if (!(t = ca_new0(ca_theme_data, 1)))
return CA_ERROR_OOM;
if (!(t->name = ca_strdup(name))) {
ret = CA_ERROR_OOM;
goto fail;
}
if ((ret = load_theme_dir(t, name)) < 0)
goto fail;
/* The fallback theme may intentionally not exist so ignore failure */
if (!t->loaded_fallback_theme)
load_theme_dir(t, FALLBACK_THEME);
if (*_t)
ca_theme_data_free(*_t);
*_t = t;
return CA_SUCCESS;
fail:
if (t)
ca_theme_data_free(t);
return ret;
}
static int find_sound_for_suffix(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme_name,
const char *name,
const char *path,
const char *suffix,
const char *locale,
const char *subdir) {
char *fn;
int ret;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
ca_return_val_if_fail(path, CA_ERROR_INVALID);
ca_return_val_if_fail(path[0] == '/', CA_ERROR_INVALID);
if (!(fn = ca_sprintf_malloc("%s%s%s%s%s%s%s/%s%s",
path,
theme_name ? "/" : "",
theme_name ? theme_name : "",
subdir ? "/" : "",
subdir ? subdir : "",
locale ? "/" : "",
locale ? locale : "",
name, suffix)))
return CA_ERROR_OOM;
if (ca_streq(suffix, ".disabled")) {
if (access(fn, F_OK) == 0)
ret = CA_ERROR_DISABLED;
else
ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
} else
ret = sfopen(f, fn);
if (ret == CA_SUCCESS && sound_path)
*sound_path = fn;
else
ca_free(fn);
return ret;
}
static int find_sound_in_locale(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme_name,
const char *name,
const char *path,
const char *locale,
const char *subdir) {
int ret;
char *p;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
ca_return_val_if_fail(path, CA_ERROR_INVALID);
ca_return_val_if_fail(path[0] == '/', CA_ERROR_INVALID);
if (!(p = ca_new(char, strlen(path) + sizeof("/sounds"))))
return CA_ERROR_OOM;
sprintf(p, "%s/sounds", path);
if ((ret = find_sound_for_suffix(f, sfopen, sound_path, theme_name, name, p, ".disabled", locale, subdir)) == CA_ERROR_NOTFOUND)
if ((ret = find_sound_for_suffix(f, sfopen, sound_path,theme_name, name, p, ".oga", locale, subdir)) == CA_ERROR_NOTFOUND)
if ((ret = find_sound_for_suffix(f, sfopen, sound_path,theme_name, name, p, ".ogg", locale, subdir)) == CA_ERROR_NOTFOUND)
ret = find_sound_for_suffix(f, sfopen, sound_path,theme_name, name, p, ".wav", locale, subdir);
ca_free(p);
return ret;
}
static int find_sound_for_locale(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme_name,
const char *name,
const char *path,
const char *locale,
const char *subdir) {
const char *e;
int ret;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
ca_return_val_if_fail(path, CA_ERROR_INVALID);
ca_return_val_if_fail(locale, CA_ERROR_INVALID);
/* First, try the locale def itself */
if ((ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, locale, subdir)) != CA_ERROR_NOTFOUND)
return ret;
/* Then, try to truncate at the @ */
if ((e = strchr(locale, '@'))) {
char *t;
if (!(t = ca_strndup(locale, (size_t) (e - locale))))
return CA_ERROR_OOM;
ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, t, subdir);
ca_free(t);
if (ret != CA_ERROR_NOTFOUND)
return ret;
}
/* Followed by truncating at the _ */
if ((e = strchr(locale, '_'))) {
char *t;
if (!(t = ca_strndup(locale, (size_t) (e - locale))))
return CA_ERROR_OOM;
ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, t, subdir);
ca_free(t);
if (ret != CA_ERROR_NOTFOUND)
return ret;
}
/* Then, try "C" as fallback locale */
if (strcmp(locale, "C"))
if ((ret = find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, "C", subdir)) != CA_ERROR_NOTFOUND)
return ret;
/* Try without locale */
return find_sound_in_locale(f, sfopen, sound_path, theme_name, name, path, NULL, subdir);
}
static int find_sound_for_name(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme_name,
const char *name,
const char *path,
const char *locale,
const char *subdir) {
int ret;
const char *k;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
if ((ret = find_sound_for_locale(f, sfopen, sound_path, theme_name, name, path, locale, subdir)) != CA_ERROR_NOTFOUND)
return ret;
k = strchr(name, 0);
for (;;) {
char *n;
do {
k--;
if (k <= name)
return CA_ERROR_NOTFOUND;
} while (*k != '-');
if (!(n = ca_strndup(name, (size_t) (k-name))))
return CA_ERROR_OOM;
if ((ret = find_sound_for_locale(f, sfopen, sound_path, theme_name, n, path, locale, subdir)) != CA_ERROR_NOTFOUND) {
ca_free(n);
return ret;
}
ca_free(n);
}
}
static int find_sound_in_subdir(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
const char *theme_name,
const char *name,
const char *locale,
const char *subdir) {
int ret;
char *e = NULL;
const char *g;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
if ((ret = ca_get_data_home(&e)) < 0)
return ret;
if (e) {
ret = find_sound_for_name(f, sfopen, sound_path, theme_name, name, e, locale, subdir);
ca_free(e);
if (ret != CA_ERROR_NOTFOUND)
return ret;
}
g = ca_get_data_dirs();
for (;;) {
size_t k;
k = strcspn(g, ":");
if (g[0] == '/' && k > 0) {
char *p;
if (!(p = ca_strndup(g, k)))
return CA_ERROR_OOM;
ret = find_sound_for_name(f, sfopen, sound_path, theme_name, name, p, locale, subdir);
ca_free(p);
if (ret != CA_ERROR_NOTFOUND)
return ret;
}
if (g[k] == 0)
break;
g += k+1;
}
return CA_ERROR_NOTFOUND;
}
static int find_sound_in_profile(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
ca_theme_data *t,
const char *name,
const char *locale,
const char *profile) {
ca_data_dir *d;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(t, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
for (d = t->data_dirs; d; d = d->next)
if (data_dir_matches(d, profile)) {
int ret;
if ((ret = find_sound_in_subdir(f, sfopen, sound_path, d->theme_name, name, locale, d->dir_name)) != CA_ERROR_NOTFOUND)
return ret;
}
return CA_ERROR_NOTFOUND;
}
static int find_sound_in_theme(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
ca_theme_data *t,
const char *name,
const char *locale,
const char *profile) {
int ret;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(name, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(profile, CA_ERROR_INVALID);
if (t) {
/* First, try the profile def itself */
if ((ret = find_sound_in_profile(f, sfopen, sound_path, t, name, locale, profile)) != CA_ERROR_NOTFOUND)
return ret;
/* Then, fall back to stereo */
if (!ca_streq(profile, DEFAULT_OUTPUT_PROFILE))
if ((ret = find_sound_in_profile(f, sfopen, sound_path, t, name, locale, DEFAULT_OUTPUT_PROFILE)) != CA_ERROR_NOTFOUND)
return ret;
}
/* And fall back to no profile */
return find_sound_in_subdir(f, sfopen, sound_path, t ? t->name : NULL, name, locale, NULL);
}
static int find_sound_for_theme(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
ca_theme_data **t,
const char *theme,
const char *name,
const char *locale,
const char *profile) {
int ret;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(t, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
ca_return_val_if_fail(theme, CA_ERROR_INVALID);
ca_return_val_if_fail(name && *name, CA_ERROR_INVALID);
ca_return_val_if_fail(locale, CA_ERROR_INVALID);
ca_return_val_if_fail(profile, CA_ERROR_INVALID);
/* First, try in the theme itself, and if that fails the fallback theme */
if ((ret = load_theme_data(t, theme)) == CA_ERROR_NOTFOUND)
if (!ca_streq(theme, FALLBACK_THEME))
ret = load_theme_data(t, FALLBACK_THEME);
if (ret == CA_SUCCESS)
if ((ret = find_sound_in_theme(f, sfopen, sound_path, *t, name, locale, profile)) != CA_ERROR_NOTFOUND)
return ret;
/* Then, fall back to "unthemed" files */
return find_sound_in_theme(f, sfopen, sound_path, NULL, name, locale, profile);
}
int ca_lookup_sound_with_callback(
ca_sound_file **f,
ca_sound_file_open_callback_t sfopen,
char **sound_path,
ca_theme_data **t,
ca_proplist *cp,
ca_proplist *sp) {
int ret = CA_ERROR_INVALID;
const char *name, *fname;
ca_return_val_if_fail(f, CA_ERROR_INVALID);
ca_return_val_if_fail(t, CA_ERROR_INVALID);
ca_return_val_if_fail(cp, CA_ERROR_INVALID);
ca_return_val_if_fail(sp, CA_ERROR_INVALID);
ca_return_val_if_fail(sfopen, CA_ERROR_INVALID);
*f = NULL;
if (sound_path)
*sound_path = NULL;
ca_mutex_lock(cp->mutex);
ca_mutex_lock(sp->mutex);
if ((name = ca_proplist_gets_unlocked(sp, CA_PROP_EVENT_ID))) {
const char *theme, *locale, *profile;
if (!(theme = ca_proplist_gets_unlocked(sp, CA_PROP_CANBERRA_XDG_THEME_NAME)))
if (!(theme = ca_proplist_gets_unlocked(cp, CA_PROP_CANBERRA_XDG_THEME_NAME)))
theme = DEFAULT_THEME;
if (!(locale = ca_proplist_gets_unlocked(sp, CA_PROP_MEDIA_LANGUAGE)))
if (!(locale = ca_proplist_gets_unlocked(sp, CA_PROP_APPLICATION_LANGUAGE)))
if (!(locale = ca_proplist_gets_unlocked(cp, CA_PROP_MEDIA_LANGUAGE)))
if (!(locale = ca_proplist_gets_unlocked(cp, CA_PROP_APPLICATION_LANGUAGE)))
if (!(locale = setlocale(LC_MESSAGES, NULL)))
locale = "C";
if (!(profile = ca_proplist_gets_unlocked(sp, CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE)))
if (!(profile = ca_proplist_gets_unlocked(cp, CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE)))
profile = DEFAULT_OUTPUT_PROFILE;
#ifdef HAVE_CACHE
if ((ret = ca_cache_lookup_sound(f, sfopen, sound_path, theme, name, locale, profile)) >= 0) {
/* This entry is available in the cache, let's transform
* negative cache entries to CA_ERROR_NOTFOUND */
if (!*f)
ret = CA_ERROR_NOTFOUND;
} else {
char *spath = NULL;
/* Either this entry was not available in the database,
* neither positive nor negative, or the database was
* corrupt, or it was out-of-date. In all cases try to
* find the entry manually. */
if ((ret = find_sound_for_theme(f, sfopen, sound_path ? sound_path : &spath, t, theme, name, locale, profile)) >= 0)
/* Ok, we found it. Let's update the cache */
ca_cache_store_sound(theme, name, locale, profile, sound_path ? *sound_path : spath);
else if (ret == CA_ERROR_NOTFOUND)
/* Doesn't seem to be around, let's create a negative cache entry */
ca_cache_store_sound(theme, name, locale, profile, NULL);
ca_free(spath);
}
#else
ret = find_sound_for_theme(f, sfopen, sound_path, t, theme, name, locale, profile);
#endif
}
if (ret == CA_ERROR_NOTFOUND || !name) {
if ((fname = ca_proplist_gets_unlocked(sp, CA_PROP_MEDIA_FILENAME)))
ret = sfopen(f, fname);
}
ca_mutex_unlock(cp->mutex);
ca_mutex_unlock(sp->mutex);
return ret;
}
int ca_lookup_sound(
ca_sound_file **f,
char **sound_path,
ca_theme_data **t,
ca_proplist *cp,
ca_proplist *sp) {
return ca_lookup_sound_with_callback(f, ca_sound_file_open, sound_path, t, cp, sp);
}
void ca_theme_data_free(ca_theme_data *t) {
ca_assert(t);
while (t->data_dirs) {
ca_data_dir *d = t->data_dirs;
CA_LLIST_REMOVE(ca_data_dir, t->data_dirs, d);
ca_free(d->theme_name);
ca_free(d->dir_name);
ca_free(d->output_profile);
ca_free(d);
}
ca_free(t->name);
ca_free(t);
}
07070100000048000081A4000000000000000000000001509D8F3700000595000000000000000000000000000000000000002A00000000libcanberra-0.30+2/src/sound-theme-spec.h/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foocanberrasoundthemespechfoo
#define foocanberrasoundthemespechfoo
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#include "read-sound-file.h"
#include "proplist.h"
typedef struct ca_theme_data ca_theme_data;
typedef int (*ca_sound_file_open_callback_t)(ca_sound_file **f, const char *fn);
int ca_lookup_sound(ca_sound_file **f, char **sound_path, ca_theme_data **t, ca_proplist *cp, ca_proplist *sp);
int ca_lookup_sound_with_callback(ca_sound_file **f, ca_sound_file_open_callback_t sfopen, char **sound_path, ca_theme_data **t, ca_proplist *cp, ca_proplist *sp);
void ca_theme_data_free(ca_theme_data *t);
int ca_get_data_home(char **e);
const char *ca_get_data_dirs(void);
#endif
07070100000049000081A4000000000000000000000001509D8F3700000F99000000000000000000000000000000000000002700000000libcanberra-0.30+2/src/test-canberra.c/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
This file is part of libcanberra.
Copyright 2008 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include "canberra.h"
static void callback(ca_context *c, uint32_t id, int error, void *userdata) {
fprintf(stderr, "callback called for id %u, error '%s', userdata=%p\n", id, ca_strerror(error), userdata);
}
int main(int argc, char *argv[]) {
ca_context *c;
ca_proplist *p;
int ret;
setlocale(LC_ALL, "");
ret = ca_context_create(&c);
fprintf(stderr, "create: %s\n", ca_strerror(ret));
/* Initialize a few meta variables for the following play()
* calls. They stay valid until they are overwritten with
* ca_context_change_props() again. */
ret = ca_context_change_props(c,
CA_PROP_APPLICATION_NAME, "An example",
CA_PROP_APPLICATION_ID, "org.freedesktop.libcanberra.Test",
CA_PROP_WINDOW_X11_SCREEN, getenv("DISPLAY"),
NULL);
fprintf(stderr, "change_props: %s\n", ca_strerror(ret));
ret = ca_context_open(c);
fprintf(stderr, "open: %s\n", ca_strerror(ret));
/* Now trigger a sound event, the quick version */
ret = ca_context_play(c, 0,
CA_PROP_EVENT_ID, "desktop-login",
CA_PROP_MEDIA_FILENAME, "/usr/share/sounds/bar.wav",
CA_PROP_MEDIA_NAME, "User has logged off from session",
CA_PROP_MEDIA_LANGUAGE, "en_EN",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
fprintf(stderr, "play: %s\n", ca_strerror(ret));
/* Now trigger a sound event, the complex version */
ca_proplist_create(&p);
ca_proplist_sets(p, CA_PROP_EVENT_ID, "desktop-logout");
ca_proplist_sets(p, CA_PROP_MEDIA_FILENAME, "/usr/share/sounds/uxknkurz.wav");
ca_proplist_sets(p, CA_PROP_MEDIA_NAME, "New email received");
ca_proplist_setf(p, "test.foo", "%u", 4711);
ret = ca_context_play_full(c, 1, p, callback, (void*) 0x4711);
ca_proplist_destroy(p);
fprintf(stderr, "play_full: %s\n", ca_strerror(ret));
/* Now trigger a sound event, by filename */
ret = ca_context_play(c, 2,
CA_PROP_MEDIA_FILENAME, "/usr/share/sounds/freedesktop/stereo/audio-channel-front-left.ogg",
CA_PROP_MEDIA_NAME, "Front Left",
CA_PROP_MEDIA_LANGUAGE, "en_EN",
NULL);
fprintf(stderr, "play (by filename): %s\n", ca_strerror(ret));
fprintf(stderr, "Sleep half a second ...\n");
usleep(500000);
/* Stop one sound */
/* ret = ca_context_cancel(c, 0); */
/* fprintf(stderr, "cancel: %s\n", ca_strerror(ret)); */
fprintf(stderr, "Sleep 2s ...\n");
sleep(2);
/* .. */
ret = ca_context_destroy(c);
fprintf(stderr, "destroy: %s\n", ca_strerror(ret));
return 0;
}
0707010000004A000081A4000000000000000000000001509D8F3700000066000000000000000000000000000000000000001800000000libcanberra-0.30+2/todo* ca_context_left_to_play()
* ca_context_check() or DRY_RUN
* queuing, looping, prefixing, postfixing
0707010000004B000041ED000000000000000000000002509D8F3700000000000000000000000000000000000000000000001800000000libcanberra-0.30+2/vala0707010000004C000081A4000000000000000000000001509D8F370000055D000000000000000000000000000000000000002D00000000libcanberra-0.30+2/vala/libcanberra-gtk.vapi/***
This file is part of libcanberra.
Copyright 2009 Lennart Poettering
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
using Canberra;
using Gdk;
using Gtk;
[CCode (cprefix = "CA_GTK_", lower_case_cprefix = "ca_gtk_", cheader_filename = "canberra-gtk.h")]
namespace CanberraGtk {
public unowned Context? context_get();
public unowned Context? context_get_for_screen(Gdk.Screen? screen);
public int proplist_set_for_widget(Proplist p, Gtk.Widget w);
public int play_for_widget(Gtk.Widget w, uint32 id, ...);
public int proplist_set_for_event(Proplist p, Gdk.Event e);
public int play_for_event(Gdk.Event e, uint32 id, ...);
public void widget_disable_sounds(Gtk.Widget w, bool enable = false);
}
0707010000004D000081A4000000000000000000000001509D8F3700001539000000000000000000000000000000000000002900000000libcanberra-0.30+2/vala/libcanberra.vapi/***
This file is part of libcanberra.
Copyright (C) 2009 Michael 'Mickey' Lauer <mlauer vanille-media de>
libcanberra 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.
libcanberra 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 libcanberra. If not, see
<http://www.gnu.org/licenses/>.
***/
[CCode (cprefix = "CA_", lower_case_cprefix = "ca_", cheader_filename = "canberra.h")]
namespace Canberra {
public const int MAJOR;
public const int MINOR;
[CCode (cname="CA_CHECK_VERSION")]
public bool CHECK_VERSION(int major, int minor);
public const string PROP_MEDIA_NAME;
public const string PROP_MEDIA_TITLE;
public const string PROP_MEDIA_ARTIST;
public const string PROP_MEDIA_LANGUAGE;
public const string PROP_MEDIA_FILENAME;
public const string PROP_MEDIA_ICON;
public const string PROP_MEDIA_ICON_NAME;
public const string PROP_MEDIA_ROLE;
public const string PROP_EVENT_ID;
public const string PROP_EVENT_DESCRIPTION;
public const string PROP_EVENT_MOUSE_X;
public const string PROP_EVENT_MOUSE_Y;
public const string PROP_EVENT_MOUSE_HPOS;
public const string PROP_EVENT_MOUSE_VPOS;
public const string PROP_EVENT_MOUSE_BUTTON;
public const string PROP_WINDOW_NAME;
public const string PROP_WINDOW_ID;
public const string PROP_WINDOW_ICON;
public const string PROP_WINDOW_ICON_NAME;
public const string PROP_WINDOW_X;
public const string PROP_WINDOW_Y;
public const string PROP_WINDOW_WIDTH;
public const string PROP_WINDOW_HEIGHT;
public const string PROP_WINDOW_HPOS;
public const string PROP_WINDOW_VPOS;
public const string PROP_WINDOW_DESKTOP;
public const string PROP_WINDOW_X11_DISPLAY;
public const string PROP_WINDOW_X11_SCREEN;
public const string PROP_WINDOW_X11_MONITOR;
public const string PROP_WINDOW_X11_XID;
public const string PROP_APPLICATION_NAME;
public const string PROP_APPLICATION_ID;
public const string PROP_APPLICATION_VERSION;
public const string PROP_APPLICATION_ICON;
public const string PROP_APPLICATION_ICON_NAME;
public const string PROP_APPLICATION_LANGUAGE;
public const string PROP_APPLICATION_PROCESS_ID;
public const string PROP_APPLICATION_PROCESS_BINARY;
public const string PROP_APPLICATION_PROCESS_USER;
public const string PROP_APPLICATION_PROCESS_HOST;
public const string PROP_CANBERRA_CACHE_CONTROL;
public const string PROP_CANBERRA_VOLUME;
public const string PROP_CANBERRA_XDG_THEME_NAME;
public const string PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE;
public const string PROP_CANBERRA_ENABLE;
public const string PROP_CANBERRA_FORCE_CHANNEL;
[CCode (cname = "CA_SUCCESS")]
public const int SUCCESS;
[CCode (cname = "int", cprefix = "CA_ERROR_")]
public enum Error {
NOTSUPPORTED,
INVALID,
STATE,
OOM,
NODRIVER,
SYSTEM,
CORRUPT,
TOOBIG,
NOTFOUND,
DESTROYED,
CANCELED,
NOTAVAILABLE,
ACCESS,
IO,
INTERNAL,
DISABLED,
FORKED,
DISCONNECTED,
[CCode (cname = "_CA_ERROR_MAX")]
_MAX
}
public unowned string? strerror(int code);
public delegate void FinishCallback(Context c, uint32 id, int code);
[Compact]
[CCode (cname = "ca_proplist", free_function = "ca_proplist_destroy")]
public class Proplist {
public static int create(out Proplist p);
public int sets(string key, string value);
[PrintfFormat]
public int setf(string key, string format, ...);
public int set(string key, void* data, size_t nbytes);
}
[Compact]
[CCode (cname = "ca_context", free_function = "ca_context_destroy")]
public class Context {
public static int create(out Context context);
public int set_driver(string? driver = null);
public int change_device(string? device = null);
public int open();
public int change_props(...);
public int change_props_full(Proplist p);
public int play_full(uint32 id, Proplist p, FinishCallback? cb = null);
public int play(uint32 id, ...);
public int cache_full(Proplist p);
public int cache(...);
public int cancel(uint32 id);
public int playing(uint32 id, out bool playing);
}
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!949 blocks