[modules] Initial version of droid-{card,sink,source}.
This commit is contained in:
parent
09aabcb1a0
commit
2b04d8be27
24 changed files with 5128 additions and 0 deletions
510
COPYING
Normal file
510
COPYING
Normal file
|
|
@ -0,0 +1,510 @@
|
||||||
|
|
||||||
|
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!
|
||||||
|
|
||||||
|
|
||||||
3
Makefile.am
Normal file
3
Makefile.am
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
SUBDIRS = src
|
||||||
|
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
14
bootstrap.sh
Executable file
14
bootstrap.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
autoreconf -vfi
|
||||||
|
|
||||||
|
if type -p colorgcc > /dev/null ; then
|
||||||
|
export CC=colorgcc
|
||||||
|
fi
|
||||||
|
|
||||||
|
export CFLAGS=${CFLAGS-"-g -O0"}
|
||||||
|
|
||||||
|
if test "x$NOCONFIGURE" = "x"; then
|
||||||
|
./configure --enable-maintainer-mode --disable-processing "$@"
|
||||||
|
make clean
|
||||||
|
fi
|
||||||
248
configure.ac
Normal file
248
configure.ac
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
AC_PREREQ(2.60)
|
||||||
|
|
||||||
|
m4_define(PA_MAJOR, [2])
|
||||||
|
m4_define(PA_MINOR, [1])
|
||||||
|
m4_define(NEMO_MICRO, [0])
|
||||||
|
|
||||||
|
AC_INIT([pulseaudio-modules-droid], [PA_MAJOR.PA_MINOR.NEMO_MICRO], [mer-general@lists.merproject.org])
|
||||||
|
AC_CONFIG_HEADER([config.h])
|
||||||
|
AM_INIT_AUTOMAKE([foreign -Wall silent-rules])
|
||||||
|
AC_CONFIG_MACRO_DIR(m4)
|
||||||
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CC_C99
|
||||||
|
AM_PROG_CC_C_O
|
||||||
|
AC_PROG_GCC_TRADITIONAL
|
||||||
|
|
||||||
|
AC_SUBST(PA_MAJORMINOR, PA_MAJOR.PA_MINOR)
|
||||||
|
|
||||||
|
DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wno-long-long -Winline -Wvla -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wpacked -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wold-style-definition -Wpointer-arith -Winit-self -Wfloat-equal -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wstrict-aliasing=2 -Wwrite-strings -Wno-unused-parameter -ffast-math -Wp,-D_FORTIFY_SOURCE=2 -fno-common -fdiagnostics-show-option" # PulseAudio 0.9.15 usess same + -Wcast-align -Wdeclaration-after-statement
|
||||||
|
|
||||||
|
for flag in $DESIRED_FLAGS ; do
|
||||||
|
CC_CHECK_CFLAGS([$flag], [CFLAGS="$CFLAGS $flag"])
|
||||||
|
done
|
||||||
|
|
||||||
|
# FIXME: we should push that as .m4 macro installed by pulseaudio-dev package
|
||||||
|
# Native atomic operation support
|
||||||
|
AC_ARG_ENABLE([atomic-arm-linux-helpers],
|
||||||
|
AS_HELP_STRING([--disable-atomic-arm-linux-helpers],[use inline asm or libatomic_ops instead]),
|
||||||
|
[
|
||||||
|
case "${enableval}" in
|
||||||
|
yes) atomic_arm_linux_helpers=yes ;;
|
||||||
|
no) atomic_arm_linux_helpers=no ;;
|
||||||
|
*) AC_MSG_ERROR(bad value ${enableval} for --disable-atomic-arm-linux-helpers) ;;
|
||||||
|
esac
|
||||||
|
],
|
||||||
|
[atomic_arm_linux_helpers=auto])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([atomic-arm-memory-barrier],
|
||||||
|
AS_HELP_STRING([--enable-atomic-arm-memory-barrier],[only really needed in SMP arm systems]),
|
||||||
|
[
|
||||||
|
case "${enableval}" in
|
||||||
|
yes) AC_DEFINE_UNQUOTED(ATOMIC_ARM_MEMORY_BARRIER_ENABLED, 1, [Enable memory barriers]) ;;
|
||||||
|
no) ;;
|
||||||
|
*) AC_MSG_ERROR(bad value ${enableval} for --disable-atomic-arm-linux-helpers) ;;
|
||||||
|
esac
|
||||||
|
],)
|
||||||
|
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([target operating system])
|
||||||
|
|
||||||
|
case $host in
|
||||||
|
*-*-linux*)
|
||||||
|
AC_MSG_RESULT([linux])
|
||||||
|
pulse_target_os=linux
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_RESULT([unknown])
|
||||||
|
pulse_target_os=unknown
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# If everything else fails use libatomic_ops
|
||||||
|
need_libatomic_ops=yes
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether $CC knows __sync_bool_compare_and_swap()])
|
||||||
|
AC_LANG_CONFTEST([int main() { int a = 4; __sync_bool_compare_and_swap(&a, 4, 5); }])
|
||||||
|
$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null
|
||||||
|
ret=$?
|
||||||
|
rm -f conftest.o conftest
|
||||||
|
if test $ret -eq 0 ; then
|
||||||
|
AC_DEFINE([HAVE_ATOMIC_BUILTINS], 1, [Have __sync_bool_compare_and_swap() and friends.])
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
need_libatomic_ops=no
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
# HW specific atomic ops stuff
|
||||||
|
AC_MSG_CHECKING([architecture for native atomic operations])
|
||||||
|
case $host_cpu in
|
||||||
|
arm*)
|
||||||
|
AC_MSG_RESULT([arm])
|
||||||
|
AC_MSG_CHECKING([compiler support for arm inline asm atomic operations])
|
||||||
|
AC_LANG_CONFTEST([[int main()
|
||||||
|
{
|
||||||
|
volatile int a=0;
|
||||||
|
int o=0, n=1, r;
|
||||||
|
asm volatile ("ldrex %0, [%1]\n"
|
||||||
|
"subs %0, %0, %2\n"
|
||||||
|
"strexeq %0, %3, [%1]\n"
|
||||||
|
: "=&r" (r)
|
||||||
|
: "r" (&a), "Ir" (o), "r" (n)
|
||||||
|
: "cc");
|
||||||
|
return (a==1 ? 0 : -1);
|
||||||
|
}]])
|
||||||
|
$CC conftest.c $CFLAGS -o conftest > /dev/null 2>&1
|
||||||
|
ret=$?
|
||||||
|
rm -f conftest.o conftest
|
||||||
|
if test $ret -eq 0 ; then
|
||||||
|
AC_DEFINE([ATOMIC_ARM_INLINE_ASM], 1, [Have ARMv6 instructions.])
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
need_libatomic_ops=no
|
||||||
|
else
|
||||||
|
# We really want inline asm atomic operations!!
|
||||||
|
echo "ERROR No ARMv6 instructions available check your compiler!!!"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether we can use Linux kernel helpers])
|
||||||
|
# The Linux kernel helper functions have been there since 2.6.16. However
|
||||||
|
# compile time checking for kernel version in cross compile environment
|
||||||
|
# (which is usually the case for arm cpu) is tricky (or impossible).
|
||||||
|
if test "x$pulse_target_os" = "xlinux" && test "x$atomic_arm_linux_helpers" != "xno"; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE_UNQUOTED(ATOMIC_ARM_LINUX_HELPERS, 1, [special arm linux implementation])
|
||||||
|
need_libatomic_ops=no
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_RESULT([unknown])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether we need libatomic_ops])
|
||||||
|
if test "x$need_libatomic_ops" = "xyes"; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_CHECK_HEADERS([atomic_ops.h], [], [
|
||||||
|
AC_MSG_ERROR([*** libatomic-ops headers not found])
|
||||||
|
])
|
||||||
|
|
||||||
|
# Win32 does not need the lib and breaks horribly if we try to include it
|
||||||
|
if test "x$os_is_win32" != "x1" ; then
|
||||||
|
LIBS="$LIBS -latomic_ops"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
|
CC_CHECK_TLS
|
||||||
|
|
||||||
|
AC_CACHE_CHECK([whether $CC knows _Bool],
|
||||||
|
pulseaudio_cv__Bool,
|
||||||
|
[AC_COMPILE_IFELSE(
|
||||||
|
AC_LANG_PROGRAM([], [[_Bool b;]]),
|
||||||
|
[pulseaudio_cv__Bool=yes],
|
||||||
|
[pulseaudio_cv__Bool=no])
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_IF([test "$pulseaudio_cv__Bool" = "yes"], [
|
||||||
|
AC_DEFINE([HAVE_STD_BOOL], 1, [Have _Bool.])
|
||||||
|
])
|
||||||
|
|
||||||
|
#### libtool stuff (FIXME: when sbox will have 2.2 )####
|
||||||
|
#LT_PREREQ(2.2)
|
||||||
|
#LT_INIT([dlopen win32-dll disable-static])
|
||||||
|
AC_PROG_LIBTOOL
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 2.1 pulsecore >= 2.1 ])
|
||||||
|
AC_SUBST(PULSEAUDIO_CFLAGS)
|
||||||
|
AC_SUBST(PULSEAUDIO_LIBS)
|
||||||
|
|
||||||
|
pulseaudiodir=`pkg-config --variable=prefix pulsecore`
|
||||||
|
|
||||||
|
#PKG_CHECK_MODULES([DROIDHEADERS], [android-headers >= 0.0.6])
|
||||||
|
# android-headers.pc has broken version field
|
||||||
|
PKG_CHECK_MODULES([DROIDHEADERS], [android-headers])
|
||||||
|
AC_SUBST(DROIDHEADERS_CFLAGS)
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES([HYBRIS], [libhardware >= 0.1.0])
|
||||||
|
AC_SUBST(HYBRIS_CFLAGS)
|
||||||
|
AC_SUBST(HYBRIS_LIBS)
|
||||||
|
|
||||||
|
AC_ARG_WITH([module-dir],
|
||||||
|
AS_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${pulseaudiodir}/lib/pulse-${PA_MAJORMINOR}/modules/]),
|
||||||
|
[modlibexecdir=$withval], [modlibexecdir="${pulseaudiodir}/lib/pulse-${PA_MAJORMINOR}/modules"])
|
||||||
|
|
||||||
|
AC_SUBST(modlibexecdir)
|
||||||
|
|
||||||
|
############################################
|
||||||
|
# Processing
|
||||||
|
AC_ARG_ENABLE([processing],
|
||||||
|
AS_HELP_STRING([--disable-processing],[Disable optional processing support]),
|
||||||
|
[
|
||||||
|
case "${enableval}" in
|
||||||
|
yes) processing=yes ;;
|
||||||
|
no) processing=no ;;
|
||||||
|
*) AC_MSG_ERROR(bad value ${enableval} for --disable-processing) ;;
|
||||||
|
esac
|
||||||
|
],
|
||||||
|
[processing=yes])
|
||||||
|
|
||||||
|
|
||||||
|
############################################
|
||||||
|
# x86
|
||||||
|
AC_MSG_CHECKING([Use x86 libraries])
|
||||||
|
case $host_cpu in
|
||||||
|
arm*) x86=no; AC_MSG_RESULT([no]) ;;
|
||||||
|
*) x86=yes; AC_MSG_RESULT([yes]) ;;
|
||||||
|
esac
|
||||||
|
AM_CONDITIONAL([X86], [test "x$x86" = xyes])
|
||||||
|
ENABLE_X86=no
|
||||||
|
if test "x$x86" = xyes ; then
|
||||||
|
AC_DEFINE([X86], 1, [x86 libraries used.])
|
||||||
|
ENABLE_X86=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([If we are using hardfp tool chain])
|
||||||
|
case `echo | gcc -v -xc -o - - 2>&1 | grep COLLECT_GCC_OPTIONS | tail -1` in
|
||||||
|
*float-abi=hard*) hardfp=yes; AC_MSG_RESULT([yes]) ;;
|
||||||
|
*) hardfp=no; AC_MSG_RESULT([no]) ;;
|
||||||
|
esac
|
||||||
|
AM_CONDITIONAL([ARM_HARDFP], [test "x$hardfp" = xyes])
|
||||||
|
ENABLE_ARM_HARDFP=no
|
||||||
|
if test "x$hardfp" = xyes ; then
|
||||||
|
AC_DEFINE([ARM_HARDFP], 1, [ARM Hard FP toolchain used.])
|
||||||
|
ENABLE_ARM_HARDFP=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
src/Makefile
|
||||||
|
src/droid/Makefile
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_OUTPUT
|
||||||
|
|
||||||
|
echo "
|
||||||
|
|
||||||
|
---{ $PACKAGE_NAME $VERSION }---
|
||||||
|
|
||||||
|
compiler: ${CC}
|
||||||
|
CFLAGS: ${CFLAGS}
|
||||||
|
|
||||||
|
prefix: ${prefix}
|
||||||
|
PulseAudio prefix: ${pulseaudiodir}
|
||||||
|
modules directory: ${modlibexecdir}
|
||||||
|
|
||||||
|
Enable x86 libraries ${ENABLE_X86}
|
||||||
|
"
|
||||||
5
m4/.gitignore
vendored
Normal file
5
m4/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
libtool.m4
|
||||||
|
ltoptions.m4
|
||||||
|
ltsugar.m4
|
||||||
|
ltversion.m4
|
||||||
|
lt~obsolete.m4
|
||||||
258
m4/attributes.m4
Normal file
258
m4/attributes.m4
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
dnl Macros to check the presence of generic (non-typed) symbols.
|
||||||
|
dnl Copyright (c) 2006-2007 Diego Pettenò <flameeyes@gmail.com>
|
||||||
|
dnl Copyright (c) 2006-2007 xine project
|
||||||
|
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.
|
||||||
|
|
||||||
|
AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [
|
||||||
|
AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]),
|
||||||
|
[ac_save_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $1"
|
||||||
|
AC_COMPILE_IFELSE([int a;],
|
||||||
|
[eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"],
|
||||||
|
[eval "AS_TR_SH([cc_cv_cflags_$1])='no'"])
|
||||||
|
CFLAGS="$ac_save_CFLAGS"
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
|
||||||
|
[$2], [$3])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([CC_CHECK_CFLAGS], [
|
||||||
|
AC_CACHE_CHECK([if $CC supports $1 flag],
|
||||||
|
AS_TR_SH([cc_cv_cflags_$1]),
|
||||||
|
CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
|
||||||
|
)
|
||||||
|
|
||||||
|
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
|
||||||
|
[$2], [$3])
|
||||||
|
])
|
||||||
|
|
||||||
|
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 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([$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(
|
||||||
|
[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([
|
||||||
|
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
|
||||||
|
])
|
||||||
17
m4/tls.m4
Normal file
17
m4/tls.m4
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
AC_DEFUN([CC_CHECK_TLS], [
|
||||||
|
AC_CACHE_CHECK([whether $CC knows __thread for Thread-Local Storage],
|
||||||
|
cc_cv_tls___thread,
|
||||||
|
[AC_COMPILE_IFELSE(
|
||||||
|
AC_LANG_PROGRAM(
|
||||||
|
[[static __thread int a = 6;]],
|
||||||
|
[[a = 5;]]),
|
||||||
|
[cc_cv_tls___thread=yes],
|
||||||
|
[cc_cv_tls___thread=no])
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_IF([test "x$cc_cv_tls___thread" = "xyes"],
|
||||||
|
[AC_DEFINE([SUPPORT_TLS___THREAD], 1,
|
||||||
|
[Define this if the compiler supports __thread for Thread-Local Storage])
|
||||||
|
$1],
|
||||||
|
[$2])
|
||||||
|
])
|
||||||
5
src/.gitignore
vendored
Normal file
5
src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.deps
|
||||||
|
.libs
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
1
src/Makefile.am
Normal file
1
src/Makefile.am
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
SUBDIRS = droid
|
||||||
49
src/droid/Makefile.am
Normal file
49
src/droid/Makefile.am
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
AM_LIBADD = \
|
||||||
|
$(PULSEAUDIO_LIBS) \
|
||||||
|
$(HYBRIS_LIBS)
|
||||||
|
AM_CFLAGS = \
|
||||||
|
$(PULSEAUDIO_CFLAGS) \
|
||||||
|
$(DROIDHEADERS_CFLAGS) \
|
||||||
|
$(HYBRIS_CFLAGS) \
|
||||||
|
-I$(top_srcdir)/src/droid
|
||||||
|
|
||||||
|
|
||||||
|
modlibexec_LTLIBRARIES = \
|
||||||
|
libdroid-util.la \
|
||||||
|
libdroid-sink.la \
|
||||||
|
libdroid-source.la \
|
||||||
|
module-droid-sink.la \
|
||||||
|
module-droid-source.la \
|
||||||
|
module-droid-card.la
|
||||||
|
|
||||||
|
noinst_HEADERS = module-droid-sink-symdef.h module-droid-card-symdef.h
|
||||||
|
|
||||||
|
libdroid_util_la_SOURCES = droid-util.c droid-util.h
|
||||||
|
libdroid_util_la_LDFLAGS = -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
|
||||||
|
libdroid_util_la_LIBADD = $(AM_LIBADD)
|
||||||
|
libdroid_util_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
|
||||||
|
libdroid_sink_la_SOURCES = droid-sink.c droid-sink.h
|
||||||
|
libdroid_sink_la_LDFLAGS = -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
|
||||||
|
libdroid_sink_la_LIBADD = $(AM_LIBADD) libdroid-util.la
|
||||||
|
libdroid_sink_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
|
||||||
|
libdroid_source_la_SOURCES = droid-source.c droid-source.h
|
||||||
|
libdroid_source_la_LDFLAGS = -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
|
||||||
|
libdroid_source_la_LIBADD = $(AM_LIBADD) libdroid-util.la
|
||||||
|
libdroid_source_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
|
||||||
|
module_droid_sink_la_SOURCES = module-droid-sink.c
|
||||||
|
module_droid_sink_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
|
||||||
|
module_droid_sink_la_LIBADD = $(AM_LIBADD) -lm libdroid-util.la libdroid-sink.la
|
||||||
|
module_droid_sink_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
|
||||||
|
module_droid_source_la_SOURCES = module-droid-source.c
|
||||||
|
module_droid_source_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
|
||||||
|
module_droid_source_la_LIBADD = $(AM_LIBADD) -lm libdroid-util.la libdroid-source.la
|
||||||
|
module_droid_source_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
|
||||||
|
module_droid_card_la_SOURCES = module-droid-card.c
|
||||||
|
module_droid_card_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
|
||||||
|
module_droid_card_la_LIBADD = $(AM_LIBADD) -lm libdroid-util.la libdroid-sink.la libdroid-source.la
|
||||||
|
module_droid_card_la_CFLAGS = $(AM_CFLAGS)
|
||||||
745
src/droid/droid-sink.c
Normal file
745
src/droid/droid-sink.c
Normal file
|
|
@ -0,0 +1,745 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#define __STDC_FORMAT_MACROS
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/rtclock.h>
|
||||||
|
#include <pulse/timeval.h>
|
||||||
|
#include <pulse/volume.h>
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/memchunk.h>
|
||||||
|
#include <pulsecore/sink.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/core-rtclock.h>
|
||||||
|
#include <pulsecore/core-util.h>
|
||||||
|
#include <pulsecore/sample-util.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
#include <pulsecore/thread.h>
|
||||||
|
#include <pulsecore/thread-mq.h>
|
||||||
|
#include <pulsecore/rtpoll.h>
|
||||||
|
#include <pulsecore/time-smoother.h>
|
||||||
|
|
||||||
|
#include "droid-sink.h"
|
||||||
|
#include "droid-util.h"
|
||||||
|
|
||||||
|
struct userdata {
|
||||||
|
pa_core *core;
|
||||||
|
pa_module *module;
|
||||||
|
pa_card *card;
|
||||||
|
pa_sink *sink;
|
||||||
|
|
||||||
|
pa_thread *thread;
|
||||||
|
pa_thread_mq thread_mq;
|
||||||
|
pa_rtpoll *rtpoll;
|
||||||
|
|
||||||
|
pa_bool_t deferred_volume; /* TODO */
|
||||||
|
|
||||||
|
pa_memblockq *memblockq;
|
||||||
|
pa_memchunk silence;
|
||||||
|
size_t buffer_count;
|
||||||
|
size_t buffer_size;
|
||||||
|
pa_usec_t buffer_latency;
|
||||||
|
pa_usec_t timestamp;
|
||||||
|
|
||||||
|
audio_devices_t primary_devices;
|
||||||
|
audio_devices_t enabled_devices;
|
||||||
|
|
||||||
|
pa_droid_config_audio *config; /* Only used when used without card */
|
||||||
|
pa_droid_hw_module *hw_module;
|
||||||
|
struct audio_stream_out *stream_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_MODULE_ID "primary"
|
||||||
|
|
||||||
|
static void userdata_free(struct userdata *u);
|
||||||
|
|
||||||
|
static pa_bool_t do_routing(struct userdata *u, audio_devices_t devices) {
|
||||||
|
char tmp[32];
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->stream_out);
|
||||||
|
|
||||||
|
if (u->primary_devices == devices) {
|
||||||
|
pa_log_debug("No change in enabled devices.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->enabled_devices &= ~u->primary_devices;
|
||||||
|
u->primary_devices = devices;
|
||||||
|
u->enabled_devices |= u->primary_devices;
|
||||||
|
|
||||||
|
pa_snprintf(tmp, sizeof(tmp), "routing=%u;", u->enabled_devices);
|
||||||
|
pa_log_debug("set_parameters(): %s", tmp);
|
||||||
|
u->stream_out->common.set_parameters(&u->stream_out->common, tmp);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pa_bool_t parse_device_list(const char *str, audio_devices_t *dst) {
|
||||||
|
pa_assert(str);
|
||||||
|
pa_assert(dst);
|
||||||
|
|
||||||
|
char *dev;
|
||||||
|
const char *state = NULL;
|
||||||
|
|
||||||
|
*dst = 0;
|
||||||
|
|
||||||
|
while ((dev = pa_split(str, "|", &state))) {
|
||||||
|
audio_devices_t d;
|
||||||
|
|
||||||
|
if (!pa_string_convert_output_device_str_to_num(dev, &d)) {
|
||||||
|
pa_log_warn("Unknown device %s", dev);
|
||||||
|
pa_xfree(dev);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst |= d;
|
||||||
|
|
||||||
|
pa_xfree(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int thread_write(struct userdata *u) {
|
||||||
|
pa_memchunk c;
|
||||||
|
const void *p;
|
||||||
|
ssize_t wrote;
|
||||||
|
|
||||||
|
pa_memblockq_peek_fixed_size(u->memblockq, u->buffer_size, &c);
|
||||||
|
|
||||||
|
/* We should be able to write everything in one go as long as memblock size
|
||||||
|
* is multiples of buffer_size. */
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
p = pa_memblock_acquire(c.memblock);
|
||||||
|
wrote = u->stream_out->write(u->stream_out, (const uint8_t*) p + c.index, c.length);
|
||||||
|
pa_memblock_release(c.memblock);
|
||||||
|
|
||||||
|
if (wrote < 0) {
|
||||||
|
pa_memblockq_drop(u->memblockq, c.length);
|
||||||
|
pa_memblock_unref(c.memblock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wrote < (ssize_t) c.length) {
|
||||||
|
c.index += wrote;
|
||||||
|
c.length -= wrote;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_memblockq_drop(u->memblockq, c.length);
|
||||||
|
pa_memblock_unref(c.memblock);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static void thread_render(struct userdata *u) {
|
||||||
|
size_t length;
|
||||||
|
size_t missing;
|
||||||
|
|
||||||
|
length = pa_memblockq_get_length(u->memblockq);
|
||||||
|
missing = u->buffer_size * u->buffer_count - length;
|
||||||
|
|
||||||
|
if (missing > 0) {
|
||||||
|
pa_memchunk c;
|
||||||
|
pa_sink_render_full(u->sink, missing, &c);
|
||||||
|
pa_memblockq_push_align(u->memblockq, &c);
|
||||||
|
pa_memblock_unref(c.memblock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_rewind(struct userdata *u) {
|
||||||
|
size_t rewind_nbytes;
|
||||||
|
size_t max_rewind_nbytes;
|
||||||
|
size_t queue_length;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
if (u->sink->thread_info.rewind_nbytes == 0) {
|
||||||
|
pa_sink_process_rewind(u->sink, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind_nbytes = u->sink->thread_info.rewind_nbytes;
|
||||||
|
u->sink->thread_info.rewind_nbytes = 0;
|
||||||
|
|
||||||
|
pa_assert(rewind_nbytes > 0);
|
||||||
|
pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
|
||||||
|
|
||||||
|
queue_length = pa_memblockq_get_length(u->memblockq);
|
||||||
|
if (queue_length <= u->buffer_size)
|
||||||
|
goto do_nothing;
|
||||||
|
max_rewind_nbytes = queue_length - u->buffer_size;
|
||||||
|
if (max_rewind_nbytes == 0)
|
||||||
|
goto do_nothing;
|
||||||
|
|
||||||
|
if (rewind_nbytes > max_rewind_nbytes)
|
||||||
|
rewind_nbytes = max_rewind_nbytes;
|
||||||
|
|
||||||
|
pa_memblockq_drop(u->memblockq, rewind_nbytes);
|
||||||
|
|
||||||
|
pa_sink_process_rewind(u->sink, rewind_nbytes);
|
||||||
|
|
||||||
|
pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
|
||||||
|
return;
|
||||||
|
|
||||||
|
do_nothing:
|
||||||
|
pa_log_debug("Rewound 0 bytes.");
|
||||||
|
pa_sink_process_rewind(u->sink, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void thread_func(void *userdata) {
|
||||||
|
struct userdata *u = userdata;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
pa_log_debug("Thread starting up.");
|
||||||
|
|
||||||
|
if (u->core->realtime_scheduling)
|
||||||
|
pa_make_realtime(u->core->realtime_priority);
|
||||||
|
|
||||||
|
pa_thread_mq_install(&u->thread_mq);
|
||||||
|
|
||||||
|
u->timestamp = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
|
||||||
|
|
||||||
|
u->timestamp = pa_rtclock_now();
|
||||||
|
|
||||||
|
if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
|
||||||
|
process_rewind(u);
|
||||||
|
else
|
||||||
|
thread_render(u);
|
||||||
|
|
||||||
|
if (pa_rtpoll_timer_elapsed(u->rtpoll)) {
|
||||||
|
pa_usec_t now, sleept;
|
||||||
|
|
||||||
|
thread_write(u);
|
||||||
|
|
||||||
|
now = pa_rtclock_now();
|
||||||
|
|
||||||
|
if (now - u->timestamp > u->buffer_latency / 2)
|
||||||
|
sleept = 0;
|
||||||
|
else
|
||||||
|
sleept = u->buffer_latency / 2 - (now - u->timestamp) ;
|
||||||
|
|
||||||
|
pa_rtpoll_set_timer_relative(u->rtpoll, sleept);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
pa_rtpoll_set_timer_disabled(u->rtpoll);
|
||||||
|
|
||||||
|
/* Sleep */
|
||||||
|
if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* If this was no regular exit from the loop we have to continue
|
||||||
|
* processing messages until we received PA_MESSAGE_SHUTDOWN */
|
||||||
|
pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
|
||||||
|
pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
pa_log_debug("Thread shutting down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called from IO context */
|
||||||
|
static int suspend(struct userdata *u) {
|
||||||
|
int ret;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->sink);
|
||||||
|
pa_assert(u->stream_out);
|
||||||
|
|
||||||
|
ret = u->stream_out->common.standby(&u->stream_out->common);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
pa_sink_set_max_request_within_thread(u->sink, 0);
|
||||||
|
pa_log_info("Device suspended.");
|
||||||
|
} else
|
||||||
|
pa_log("Couldn't set standby, err %d", ret);
|
||||||
|
|
||||||
|
/* Clear memblockq */
|
||||||
|
if ((length = pa_memblockq_get_length(u->memblockq)) > 0)
|
||||||
|
pa_memblockq_drop(u->memblockq, length);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unsuspend(struct userdata *u) {
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->sink);
|
||||||
|
|
||||||
|
/* HAL resumes automagically when writing to standby stream, but let's set max request */
|
||||||
|
pa_sink_set_max_request_within_thread(u->sink, u->buffer_size);
|
||||||
|
|
||||||
|
pa_log_info("Resuming...");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called from IO context */
|
||||||
|
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
|
||||||
|
struct userdata *u = PA_SINK(o)->userdata;
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case PA_SINK_MESSAGE_GET_LATENCY: {
|
||||||
|
pa_usec_t r = 0;
|
||||||
|
|
||||||
|
/* HAL reports milliseconds */
|
||||||
|
if (u->stream_out)
|
||||||
|
r = u->stream_out->get_latency(u->stream_out) * PA_USEC_PER_MSEC * u->buffer_count;
|
||||||
|
|
||||||
|
*((pa_usec_t*) data) = r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PA_SINK_MESSAGE_SET_STATE: {
|
||||||
|
switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
|
||||||
|
case PA_SINK_SUSPENDED: {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
|
||||||
|
|
||||||
|
if ((r = suspend(u)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PA_SINK_IDLE:
|
||||||
|
/* Fall through */
|
||||||
|
case PA_SINK_RUNNING: {
|
||||||
|
int r;
|
||||||
|
u->timestamp = 0;
|
||||||
|
|
||||||
|
if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
|
||||||
|
if ((r = unsuspend(u)) < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_rtpoll_set_timer_absolute(u->rtpoll, pa_rtclock_now());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not needed */
|
||||||
|
case PA_SINK_UNLINKED:
|
||||||
|
case PA_SINK_INIT:
|
||||||
|
case PA_SINK_INVALID_STATE:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pa_sink_process_msg(o, code, data, offset, chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
|
||||||
|
struct userdata *u = s->userdata;
|
||||||
|
pa_droid_port_data *data;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(p);
|
||||||
|
|
||||||
|
data = PA_DEVICE_PORT_DATA(p);
|
||||||
|
|
||||||
|
pa_log_debug("Sink set port %u", data->device);
|
||||||
|
|
||||||
|
do_routing(u, data->device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sink_set_volume_cb(pa_sink *s) {
|
||||||
|
struct userdata *u = s->userdata;
|
||||||
|
pa_cvolume r;
|
||||||
|
|
||||||
|
/* Shift up by the base volume */
|
||||||
|
pa_sw_cvolume_divide_scalar(&r, &s->real_volume, s->base_volume);
|
||||||
|
|
||||||
|
if (r.channels == 1) {
|
||||||
|
float val = pa_sw_volume_to_linear(r.values[0]);
|
||||||
|
pa_log_debug("Set hw volume %f", val);
|
||||||
|
if (u->stream_out->set_volume(u->stream_out, val, val) < 0)
|
||||||
|
return;
|
||||||
|
} else if (r.channels == 2) {
|
||||||
|
float val[2];
|
||||||
|
for (unsigned i = 0; i < 2; i++)
|
||||||
|
val[i] = pa_sw_volume_to_linear(r.values[i]);
|
||||||
|
pa_log_debug("Set hw volume %f : %f", val[0], val[1]);
|
||||||
|
if (u->stream_out->set_volume(u->stream_out, val[0], val[1]) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_volumes(struct userdata *u) {
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (u->stream_out->set_volume) {
|
||||||
|
pa_log_debug("Probe hw volume support for %s", u->sink->name);
|
||||||
|
ret = u->stream_out->set_volume(u->stream_out, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use hardware volume */
|
||||||
|
if (ret == 0) {
|
||||||
|
pa_log_debug("Using hardware volume control for %s", u->sink->name);
|
||||||
|
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
||||||
|
} else {
|
||||||
|
pa_log_debug("Using software volume control for %s", u->sink->name);
|
||||||
|
pa_sink_set_set_volume_callback(u->sink, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_sink_name(pa_modargs *ma, pa_sink_new_data *data, const char *module_id) {
|
||||||
|
const char *tmp;
|
||||||
|
|
||||||
|
pa_assert(ma);
|
||||||
|
pa_assert(data);
|
||||||
|
pa_assert(module_id);
|
||||||
|
|
||||||
|
if ((tmp = pa_modargs_get_value(ma, "sink_name", NULL))) {
|
||||||
|
pa_sink_new_data_set_name(data, tmp);
|
||||||
|
data->namereg_fail = TRUE;
|
||||||
|
} else {
|
||||||
|
char *tt = pa_sprintf_malloc("sink.%s", module_id);
|
||||||
|
pa_sink_new_data_set_name(data, tt);
|
||||||
|
pa_xfree(tt);
|
||||||
|
data->namereg_fail = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
|
pa_modargs *ma,
|
||||||
|
const char *driver,
|
||||||
|
pa_droid_hw_module *hw_module,
|
||||||
|
audio_output_flags_t flags,
|
||||||
|
pa_droid_mapping *am,
|
||||||
|
pa_card *card) {
|
||||||
|
|
||||||
|
struct userdata *u = NULL;
|
||||||
|
pa_bool_t deferred_volume = FALSE;
|
||||||
|
char *thread_name = NULL;
|
||||||
|
pa_sink_new_data data;
|
||||||
|
const char *module_id = NULL;
|
||||||
|
const char *tmp;
|
||||||
|
char *list = NULL;
|
||||||
|
uint32_t alternate_sample_rate;
|
||||||
|
uint32_t sample_rate;
|
||||||
|
audio_devices_t dev_out;
|
||||||
|
pa_sample_spec sample_spec;
|
||||||
|
pa_channel_map channel_map;
|
||||||
|
pa_bool_t namereg_fail = FALSE;
|
||||||
|
uint32_t total_latency;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
audio_format_t hal_audio_format = 0;
|
||||||
|
audio_channel_mask_t hal_channel_mask = 0;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
pa_assert(ma);
|
||||||
|
pa_assert(driver);
|
||||||
|
|
||||||
|
deferred_volume = m->core->deferred_volume;
|
||||||
|
if (pa_modargs_get_value_boolean(ma, "deferred_volume", &deferred_volume) < 0) {
|
||||||
|
pa_log("Failed to parse deferred_volume argument.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card && am)
|
||||||
|
module_id = am->output->module->name;
|
||||||
|
else
|
||||||
|
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||||
|
|
||||||
|
sample_spec = m->core->default_sample_spec;
|
||||||
|
channel_map = m->core->default_channel_map;
|
||||||
|
|
||||||
|
if (pa_modargs_get_sample_spec_and_channel_map(ma, &sample_spec, &channel_map, PA_CHANNEL_MAP_AIFF) < 0) {
|
||||||
|
pa_log("Failed to parse sample specification and channel map.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
alternate_sample_rate = m->core->alternate_sample_rate;
|
||||||
|
if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) {
|
||||||
|
pa_log("Failed to parse alternate sample rate.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u = pa_xnew0(struct userdata, 1);
|
||||||
|
u->core = m->core;
|
||||||
|
u->module = m;
|
||||||
|
u->card = card;
|
||||||
|
u->deferred_volume = deferred_volume;
|
||||||
|
u->rtpoll = pa_rtpoll_new();
|
||||||
|
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
|
||||||
|
|
||||||
|
if (hw_module) {
|
||||||
|
pa_assert(card);
|
||||||
|
u->hw_module = hw_module;
|
||||||
|
} else {
|
||||||
|
/* Sink wasn't created from inside card module, so we'll need to open
|
||||||
|
* hw module ourselves.
|
||||||
|
* TODO some way to share hw module between other sinks/sources since
|
||||||
|
* opening same module from different places likely isn't a good thing. */
|
||||||
|
|
||||||
|
if (!(u->config = pa_droid_config_load(ma)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (!(u->hw_module = pa_droid_hw_module_open(u->config, module_id, u)))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pa_convert_format(sample_spec.format, CONV_FROM_PA, &hal_audio_format)) {
|
||||||
|
pa_log("Sample spec format %u not supported.", sample_spec.format);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < channel_map.channels; i++) {
|
||||||
|
audio_channel_mask_t c;
|
||||||
|
if (!pa_convert_output_channel(channel_map.map[i], CONV_FROM_PA, &c)) {
|
||||||
|
pa_log("Failed to convert channel map.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
hal_channel_mask |= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct audio_config config_out = {
|
||||||
|
.sample_rate = sample_spec.rate,
|
||||||
|
.channel_mask = hal_channel_mask,
|
||||||
|
.format = hal_audio_format
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Default routing */
|
||||||
|
dev_out = AUDIO_DEVICE_OUT_DEFAULT;
|
||||||
|
|
||||||
|
if ((tmp = pa_modargs_get_value(ma, "output_devices", NULL))) {
|
||||||
|
audio_devices_t tmp_dev;
|
||||||
|
|
||||||
|
if (parse_device_list(tmp, &tmp_dev) && tmp_dev)
|
||||||
|
dev_out = tmp_dev;
|
||||||
|
|
||||||
|
pa_log_debug("Set initial devices %s", tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (am)
|
||||||
|
flags = am->output->flags;
|
||||||
|
|
||||||
|
ret = u->hw_module->device->open_output_stream(u->hw_module->device,
|
||||||
|
u->hw_module->stream_out_id++,
|
||||||
|
dev_out,
|
||||||
|
flags,
|
||||||
|
&config_out,
|
||||||
|
&u->stream_out);
|
||||||
|
|
||||||
|
if (!u->stream_out) {
|
||||||
|
pa_log("Failed to open output stream. (errno %d)", ret);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->buffer_size = u->stream_out->common.get_buffer_size(&u->stream_out->common);
|
||||||
|
u->buffer_latency = pa_bytes_to_usec(u->buffer_size, &sample_spec);
|
||||||
|
/* Disable internal rewinding for now. */
|
||||||
|
u->buffer_count = 1;
|
||||||
|
|
||||||
|
if ((sample_rate = u->stream_out->common.get_sample_rate(&u->stream_out->common)) != sample_spec.rate) {
|
||||||
|
pa_log_warn("Requested sample rate %u but got %u instead.", sample_spec.rate, sample_rate);
|
||||||
|
sample_spec.rate = sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_log_info("Created Android stream with device: %u flags: %u sample rate: %u channel mask: %u format: %u buffer size: %u",
|
||||||
|
dev_out,
|
||||||
|
flags,
|
||||||
|
sample_rate,
|
||||||
|
config_out.channel_mask,
|
||||||
|
config_out.format,
|
||||||
|
u->buffer_size);
|
||||||
|
|
||||||
|
|
||||||
|
pa_silence_memchunk_get(&u->core->silence_cache, u->core->mempool, &u->silence, &sample_spec, 0);
|
||||||
|
u->memblockq = pa_memblockq_new("droid-sink", 0, u->buffer_size * u->buffer_count, u->buffer_size * u->buffer_count, &sample_spec, 1, 0, 0, &u->silence);
|
||||||
|
|
||||||
|
pa_sink_new_data_init(&data);
|
||||||
|
data.driver = driver;
|
||||||
|
data.module = m;
|
||||||
|
data.card = card;
|
||||||
|
|
||||||
|
set_sink_name(ma, &data, module_id);
|
||||||
|
|
||||||
|
/* We need to give pa_modargs_get_value_boolean() a pointer to a local
|
||||||
|
* variable instead of using &data.namereg_fail directly, because
|
||||||
|
* data.namereg_fail is a bitfield and taking the address of a bitfield
|
||||||
|
* variable is impossible. */
|
||||||
|
namereg_fail = data.namereg_fail;
|
||||||
|
if (pa_modargs_get_value_boolean(ma, "namereg_fail", &namereg_fail) < 0) {
|
||||||
|
pa_log("Failed to parse namereg_fail argument.");
|
||||||
|
pa_sink_new_data_done(&data);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
data.namereg_fail = namereg_fail;
|
||||||
|
|
||||||
|
pa_sink_new_data_set_sample_spec(&data, &sample_spec);
|
||||||
|
pa_sink_new_data_set_channel_map(&data, &channel_map);
|
||||||
|
pa_sink_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!(list = pa_list_string_output_device(dev_out))) {
|
||||||
|
pa_log("Couldn't format device list string.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pa_proplist_sets(data.proplist, PROP_DROID_DEVICES, list);
|
||||||
|
pa_xfree(list);
|
||||||
|
|
||||||
|
if (flags) {
|
||||||
|
if (!(list = pa_list_string_flags(flags))) {
|
||||||
|
pa_log("Couldn't format flag list string.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
list = NULL;
|
||||||
|
|
||||||
|
pa_proplist_sets(data.proplist, PROP_DROID_FLAGS, list ? list : "");
|
||||||
|
pa_xfree(list);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (am)
|
||||||
|
pa_droid_add_ports(&data.ports, am, card);
|
||||||
|
|
||||||
|
u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE | PA_SINK_LATENCY | PA_SINK_FLAT_VOLUME);
|
||||||
|
pa_sink_new_data_done(&data);
|
||||||
|
|
||||||
|
if (!u->sink) {
|
||||||
|
pa_log("Failed to create sink.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->sink->userdata = u;
|
||||||
|
|
||||||
|
u->sink->parent.process_msg = sink_process_msg;
|
||||||
|
|
||||||
|
u->sink->set_port = sink_set_port_cb;
|
||||||
|
|
||||||
|
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
|
||||||
|
pa_sink_set_rtpoll(u->sink, u->rtpoll);
|
||||||
|
|
||||||
|
/* Rewind internal memblockq */
|
||||||
|
pa_sink_set_max_rewind(u->sink, u->buffer_size * (u->buffer_count - 1));
|
||||||
|
|
||||||
|
thread_name = pa_sprintf_malloc("droid-sink-%s", module_id);
|
||||||
|
if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) {
|
||||||
|
pa_log("Failed to create thread.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pa_xfree(thread_name);
|
||||||
|
thread_name = NULL;
|
||||||
|
|
||||||
|
/* Latency consists of HAL latency + our memblockq latency */
|
||||||
|
total_latency = u->stream_out->get_latency(u->stream_out) + (uint32_t) pa_bytes_to_usec(u->buffer_size * u->buffer_count, &sample_spec);
|
||||||
|
pa_sink_set_fixed_latency(u->sink, total_latency);
|
||||||
|
pa_log_debug("Set fixed latency %lu usec", (unsigned long) pa_bytes_to_usec(total_latency, &sample_spec));
|
||||||
|
pa_sink_set_max_request(u->sink, u->buffer_size * u->buffer_count);
|
||||||
|
|
||||||
|
if (u->sink->active_port)
|
||||||
|
sink_set_port_cb(u->sink, u->sink->active_port);
|
||||||
|
|
||||||
|
update_volumes(u);
|
||||||
|
|
||||||
|
pa_sink_put(u->sink);
|
||||||
|
|
||||||
|
return u->sink;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
pa_xfree(thread_name);
|
||||||
|
|
||||||
|
if (u)
|
||||||
|
userdata_free(u);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa_droid_sink_free(pa_sink *s) {
|
||||||
|
struct userdata *u;
|
||||||
|
|
||||||
|
pa_sink_assert_ref(s);
|
||||||
|
pa_assert_se(u = s->userdata);
|
||||||
|
|
||||||
|
userdata_free(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void userdata_free(struct userdata *u) {
|
||||||
|
|
||||||
|
if (u->sink)
|
||||||
|
pa_sink_unlink(u->sink);
|
||||||
|
|
||||||
|
if (u->thread) {
|
||||||
|
pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
|
||||||
|
pa_thread_free(u->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_thread_mq_done(&u->thread_mq);
|
||||||
|
|
||||||
|
if (u->sink)
|
||||||
|
pa_sink_unref(u->sink);
|
||||||
|
|
||||||
|
if (u->hw_module && u->stream_out)
|
||||||
|
u->hw_module->device->close_output_stream(u->hw_module->device, u->stream_out);
|
||||||
|
|
||||||
|
if (u->memblockq)
|
||||||
|
pa_memblockq_free(u->memblockq);
|
||||||
|
|
||||||
|
if (u->silence.memblock)
|
||||||
|
pa_memblock_unref(u->silence.memblock);
|
||||||
|
|
||||||
|
/* Stand-alone sink */
|
||||||
|
if (!u->card && u->hw_module)
|
||||||
|
pa_droid_hw_module_close(u->hw_module);
|
||||||
|
|
||||||
|
if (u->config)
|
||||||
|
pa_xfree(u->config);
|
||||||
|
|
||||||
|
pa_xfree(u);
|
||||||
|
}
|
||||||
55
src/droid/droid-sink.h
Normal file
55
src/droid/droid-sink.h
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef foodroidsinkfoo
|
||||||
|
#define foodroidsinkfoo
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/sink.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
#include <pulsecore/card.h>
|
||||||
|
|
||||||
|
#include "droid-util.h"
|
||||||
|
|
||||||
|
pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
|
pa_modargs *ma,
|
||||||
|
const char *driver,
|
||||||
|
pa_droid_hw_module *hw_module,
|
||||||
|
audio_output_flags_t flags,
|
||||||
|
pa_droid_mapping *am,
|
||||||
|
pa_card *card);
|
||||||
|
void pa_droid_sink_free(pa_sink *s);
|
||||||
|
|
||||||
|
#endif
|
||||||
539
src/droid/droid-source.c
Normal file
539
src/droid/droid-source.c
Normal file
|
|
@ -0,0 +1,539 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/rtclock.h>
|
||||||
|
#include <pulse/timeval.h>
|
||||||
|
#include <pulse/volume.h>
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/memchunk.h>
|
||||||
|
#include <pulsecore/source.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/core-rtclock.h>
|
||||||
|
#include <pulsecore/core-util.h>
|
||||||
|
#include <pulsecore/sample-util.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
#include <pulsecore/thread.h>
|
||||||
|
#include <pulsecore/thread-mq.h>
|
||||||
|
#include <pulsecore/rtpoll.h>
|
||||||
|
#include <pulsecore/time-smoother.h>
|
||||||
|
|
||||||
|
#include "droid-source.h"
|
||||||
|
#include "droid-util.h"
|
||||||
|
|
||||||
|
struct userdata {
|
||||||
|
pa_core *core;
|
||||||
|
pa_module *module;
|
||||||
|
pa_card *card;
|
||||||
|
pa_source *source;
|
||||||
|
|
||||||
|
pa_thread *thread;
|
||||||
|
pa_thread_mq thread_mq;
|
||||||
|
pa_rtpoll *rtpoll;
|
||||||
|
|
||||||
|
pa_memchunk memchunk;
|
||||||
|
audio_devices_t primary_devices;
|
||||||
|
audio_devices_t enabled_devices;
|
||||||
|
size_t buffer_size;
|
||||||
|
pa_usec_t timestamp;
|
||||||
|
|
||||||
|
pa_droid_config_audio *config; /* Only used when used without card */
|
||||||
|
pa_droid_hw_module *hw_module;
|
||||||
|
audio_stream_in_t *stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_MODULE_ID "primary"
|
||||||
|
|
||||||
|
static void userdata_free(struct userdata *u);
|
||||||
|
|
||||||
|
static pa_bool_t do_routing(struct userdata *u, audio_devices_t devices) {
|
||||||
|
char tmp[32];
|
||||||
|
char *devlist;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->stream);
|
||||||
|
|
||||||
|
if (u->primary_devices == devices) {
|
||||||
|
pa_log_debug("No change in enabled devices.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->enabled_devices &= ~u->primary_devices;
|
||||||
|
u->primary_devices = devices;
|
||||||
|
u->enabled_devices |= u->primary_devices;
|
||||||
|
|
||||||
|
devlist = pa_list_string_input_device(devices);
|
||||||
|
pa_snprintf(tmp, sizeof(tmp), "routing=%u", devices);
|
||||||
|
pa_log_debug("set_parameters(): %s (%s)", tmp, devlist);
|
||||||
|
pa_xfree(devlist);
|
||||||
|
u->stream->common.set_parameters(&u->stream->common, tmp);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pa_bool_t parse_device_list(const char *str, audio_devices_t *dst) {
|
||||||
|
pa_assert(str);
|
||||||
|
pa_assert(dst);
|
||||||
|
|
||||||
|
char *dev;
|
||||||
|
const char *state = NULL;
|
||||||
|
|
||||||
|
*dst = 0;
|
||||||
|
|
||||||
|
while ((dev = pa_split(str, "|", &state))) {
|
||||||
|
audio_devices_t d;
|
||||||
|
|
||||||
|
if (!pa_string_convert_input_device_str_to_num(dev, &d)) {
|
||||||
|
pa_log_warn("Unknown device %s", dev);
|
||||||
|
pa_xfree(dev);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst |= d;
|
||||||
|
|
||||||
|
pa_xfree(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int thread_read(struct userdata *u) {
|
||||||
|
void *p;
|
||||||
|
ssize_t readd;
|
||||||
|
pa_memchunk chunk;
|
||||||
|
|
||||||
|
chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) u->buffer_size);
|
||||||
|
|
||||||
|
p = pa_memblock_acquire(chunk.memblock);
|
||||||
|
readd = u->stream->read(u->stream, (uint8_t*) p, pa_memblock_get_length(chunk.memblock));
|
||||||
|
pa_memblock_release(chunk.memblock);
|
||||||
|
|
||||||
|
if (readd < 0) {
|
||||||
|
pa_log("Failed to read from stream. (err %i)", readd);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->timestamp += pa_bytes_to_usec(readd, &u->source->sample_spec);
|
||||||
|
|
||||||
|
chunk.index = 0;
|
||||||
|
chunk.length = readd;
|
||||||
|
|
||||||
|
if (chunk.length > 0)
|
||||||
|
pa_source_post(u->source, &chunk);
|
||||||
|
|
||||||
|
end:
|
||||||
|
pa_memblock_unref(chunk.memblock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void thread_func(void *userdata) {
|
||||||
|
struct userdata *u = userdata;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
pa_log_debug("Thread starting up.");
|
||||||
|
|
||||||
|
if (u->core->realtime_scheduling)
|
||||||
|
pa_make_realtime(u->core->realtime_priority);
|
||||||
|
|
||||||
|
pa_thread_mq_install(&u->thread_mq);
|
||||||
|
|
||||||
|
u->timestamp = pa_rtclock_now();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
|
||||||
|
thread_read(u);
|
||||||
|
|
||||||
|
pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
|
||||||
|
} else
|
||||||
|
pa_rtpoll_set_timer_disabled(u->rtpoll);
|
||||||
|
|
||||||
|
/* Sleep */
|
||||||
|
if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* If this was no regular exit from the loop we have to continue
|
||||||
|
* processing messages until we received PA_MESSAGE_SHUTDOWN */
|
||||||
|
pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
|
||||||
|
pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
pa_log_debug("Thread shutting down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called from IO context */
|
||||||
|
static int suspend(struct userdata *u) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->stream);
|
||||||
|
|
||||||
|
ret = u->stream->common.standby(&u->stream->common);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
pa_log_info("Device suspended.");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called from IO context */
|
||||||
|
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
|
||||||
|
struct userdata *u = PA_SOURCE(o)->userdata;
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case PA_SOURCE_MESSAGE_SET_STATE: {
|
||||||
|
switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
|
||||||
|
case PA_SOURCE_SUSPENDED: {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
|
||||||
|
|
||||||
|
if ((r = suspend(u)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PA_SOURCE_IDLE:
|
||||||
|
break;
|
||||||
|
case PA_SOURCE_RUNNING: {
|
||||||
|
pa_log_info("Resuming...");
|
||||||
|
u->timestamp = pa_rtclock_now();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not needed */
|
||||||
|
case PA_SOURCE_UNLINKED:
|
||||||
|
case PA_SOURCE_INIT:
|
||||||
|
case PA_SOURCE_INVALID_STATE:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pa_source_process_msg(o, code, data, offset, chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
||||||
|
struct userdata *u = s->userdata;
|
||||||
|
pa_droid_port_data *data;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(p);
|
||||||
|
|
||||||
|
data = PA_DEVICE_PORT_DATA(p);
|
||||||
|
|
||||||
|
pa_log_debug("Source set port %u", data->device);
|
||||||
|
|
||||||
|
do_routing(u, data->device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void source_set_name(pa_modargs *ma, pa_source_new_data *data, const char *module_id) {
|
||||||
|
const char *tmp;
|
||||||
|
|
||||||
|
pa_assert(ma);
|
||||||
|
pa_assert(data);
|
||||||
|
pa_assert(module_id);
|
||||||
|
|
||||||
|
if ((tmp = pa_modargs_get_value(ma, "source_name", NULL))) {
|
||||||
|
pa_source_new_data_set_name(data, tmp);
|
||||||
|
data->namereg_fail = TRUE;
|
||||||
|
} else {
|
||||||
|
char *tt = pa_sprintf_malloc("source.%s", module_id);
|
||||||
|
pa_source_new_data_set_name(data, tt);
|
||||||
|
pa_xfree(tt);
|
||||||
|
data->namereg_fail = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_source *pa_droid_source_new(pa_module *m,
|
||||||
|
pa_modargs *ma,
|
||||||
|
const char *driver,
|
||||||
|
pa_droid_hw_module *hw_module,
|
||||||
|
pa_droid_mapping *am,
|
||||||
|
pa_card *card) {
|
||||||
|
|
||||||
|
struct userdata *u = NULL;
|
||||||
|
char *thread_name = NULL;
|
||||||
|
pa_source_new_data data;
|
||||||
|
const char *module_id = NULL;
|
||||||
|
const char *tmp;
|
||||||
|
uint32_t sample_rate;
|
||||||
|
uint32_t alternate_sample_rate;
|
||||||
|
audio_devices_t dev_in;
|
||||||
|
pa_sample_spec sample_spec;
|
||||||
|
pa_channel_map channel_map;
|
||||||
|
pa_bool_t namereg_fail = FALSE;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
audio_format_t hal_audio_format = 0;
|
||||||
|
audio_channel_mask_t hal_channel_mask = 0;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
pa_assert(ma);
|
||||||
|
pa_assert(driver);
|
||||||
|
|
||||||
|
/* When running under card use hw module name for source by default. */
|
||||||
|
if (card && ma)
|
||||||
|
module_id = am->input->module->name;
|
||||||
|
else
|
||||||
|
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||||
|
|
||||||
|
sample_spec = m->core->default_sample_spec;
|
||||||
|
channel_map = m->core->default_channel_map;
|
||||||
|
|
||||||
|
if (pa_modargs_get_sample_spec_and_channel_map(ma, &sample_spec, &channel_map, PA_CHANNEL_MAP_AIFF) < 0) {
|
||||||
|
pa_log("Failed to parse sample specification and channel map.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
alternate_sample_rate = m->core->alternate_sample_rate;
|
||||||
|
if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) {
|
||||||
|
pa_log("Failed to parse alternate sample rate.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u = pa_xnew0(struct userdata, 1);
|
||||||
|
u->core = m->core;
|
||||||
|
u->module = m;
|
||||||
|
u->card = card;
|
||||||
|
u->rtpoll = pa_rtpoll_new();
|
||||||
|
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
|
||||||
|
|
||||||
|
if (hw_module) {
|
||||||
|
pa_assert(card);
|
||||||
|
u->hw_module = hw_module;
|
||||||
|
} else {
|
||||||
|
/* Stand-alone source */
|
||||||
|
|
||||||
|
if (!(u->config = pa_droid_config_load(ma)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (!(u->hw_module = pa_droid_hw_module_open(u->config, module_id, u)))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pa_convert_format(sample_spec.format, CONV_FROM_PA, &hal_audio_format)) {
|
||||||
|
pa_log("Sample spec format %u not supported.", sample_spec.format);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < channel_map.channels; i++) {
|
||||||
|
audio_channel_mask_t c;
|
||||||
|
if (!pa_convert_input_channel(channel_map.map[i], CONV_FROM_PA, &c)) {
|
||||||
|
pa_log("Failed to convert channel map.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
hal_channel_mask |= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct audio_config config_in = {
|
||||||
|
.sample_rate = sample_spec.rate,
|
||||||
|
.channel_mask = hal_channel_mask,
|
||||||
|
.format = hal_audio_format
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Default routing */
|
||||||
|
/* FIXME So while setting routing through stream with HALv2 API fails, creation of stream
|
||||||
|
* requires HALv2 style device to work properly. So until that oddity is resolved we always
|
||||||
|
* set AUDIO_DEVICE_IN_BUILTIN_MIC as initial device here. */
|
||||||
|
#if 0
|
||||||
|
pa_assert_se(pa_string_convert_input_device_str_to_num("AUDIO_DEVICE_IN_BUILTIN_MIC", &dev_in));
|
||||||
|
|
||||||
|
if ((tmp = pa_modargs_get_value(ma, "input_devices", NULL))) {
|
||||||
|
audio_devices_t tmp_dev;
|
||||||
|
|
||||||
|
if (parse_device_list(tmp, &tmp_dev) && tmp_dev)
|
||||||
|
dev_in = tmp_dev;
|
||||||
|
|
||||||
|
pa_log_debug("Set initial devices %s", tmp);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
pa_log_info("FIXME: Setting AUDIO_DEVICE_IN_BUILTIN_MIC as initial device.");
|
||||||
|
dev_in = AUDIO_DEVICE_IN_BUILTIN_MIC;
|
||||||
|
#endif
|
||||||
|
dev_in = AUDIO_DEVICE_IN_DEFAULT;
|
||||||
|
ret = u->hw_module->device->open_input_stream(u->hw_module->device,
|
||||||
|
u->hw_module->stream_in_id++,
|
||||||
|
dev_in,
|
||||||
|
&config_in,
|
||||||
|
&u->stream);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
pa_log("Failed to open input stream.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->buffer_size = u->stream->common.get_buffer_size(&u->stream->common);
|
||||||
|
|
||||||
|
if ((sample_rate = u->stream->common.get_sample_rate(&u->stream->common)) != sample_spec.rate) {
|
||||||
|
pa_log_warn("Requested sample rate %u but got %u instead.", sample_spec.rate, sample_rate);
|
||||||
|
sample_spec.rate = sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_log_info("Created Android stream with device: %u sample rate: %u channel mask: %u format: %u buffer size: %u",
|
||||||
|
dev_in,
|
||||||
|
sample_rate,
|
||||||
|
config_in.channel_mask,
|
||||||
|
config_in.format,
|
||||||
|
u->buffer_size);
|
||||||
|
|
||||||
|
|
||||||
|
pa_source_new_data_init(&data);
|
||||||
|
data.driver = driver;
|
||||||
|
data.module = m;
|
||||||
|
data.card = card;
|
||||||
|
|
||||||
|
source_set_name(ma, &data, module_id);
|
||||||
|
|
||||||
|
/* We need to give pa_modargs_get_value_boolean() a pointer to a local
|
||||||
|
* variable instead of using &data.namereg_fail directly, because
|
||||||
|
* data.namereg_fail is a bitfield and taking the address of a bitfield
|
||||||
|
* variable is impossible. */
|
||||||
|
namereg_fail = data.namereg_fail;
|
||||||
|
if (pa_modargs_get_value_boolean(ma, "namereg_fail", &namereg_fail) < 0) {
|
||||||
|
pa_log("Failed to parse namereg_fail argument.");
|
||||||
|
pa_source_new_data_done(&data);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
data.namereg_fail = namereg_fail;
|
||||||
|
|
||||||
|
pa_source_new_data_set_sample_spec(&data, &sample_spec);
|
||||||
|
pa_source_new_data_set_channel_map(&data, &channel_map);
|
||||||
|
pa_source_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
|
||||||
|
|
||||||
|
if (am)
|
||||||
|
pa_droid_add_ports(&data.ports, am, card);
|
||||||
|
|
||||||
|
u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE);
|
||||||
|
pa_source_new_data_done(&data);
|
||||||
|
|
||||||
|
if (!u->source) {
|
||||||
|
pa_log("Failed to create source.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->source->userdata = u;
|
||||||
|
|
||||||
|
u->source->parent.process_msg = source_process_msg;
|
||||||
|
|
||||||
|
u->source->set_port = source_set_port_cb;
|
||||||
|
|
||||||
|
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
|
||||||
|
pa_source_set_rtpoll(u->source, u->rtpoll);
|
||||||
|
|
||||||
|
/* Disable rewind for droid source */
|
||||||
|
pa_source_set_max_rewind(u->source, 0);
|
||||||
|
|
||||||
|
thread_name = pa_sprintf_malloc("droid-source-%s", module_id);
|
||||||
|
if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) {
|
||||||
|
pa_log("Failed to create thread.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pa_xfree(thread_name);
|
||||||
|
thread_name = NULL;
|
||||||
|
|
||||||
|
pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &sample_spec));
|
||||||
|
pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, &sample_spec));
|
||||||
|
|
||||||
|
if (u->source->active_port)
|
||||||
|
source_set_port_cb(u->source, u->source->active_port);
|
||||||
|
|
||||||
|
pa_source_put(u->source);
|
||||||
|
|
||||||
|
return u->source;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
pa_xfree(thread_name);
|
||||||
|
|
||||||
|
if (u)
|
||||||
|
userdata_free(u);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa_droid_source_free(pa_source *s) {
|
||||||
|
struct userdata *u;
|
||||||
|
|
||||||
|
pa_source_assert_ref(s);
|
||||||
|
pa_assert_se(u = s->userdata);
|
||||||
|
|
||||||
|
userdata_free(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void userdata_free(struct userdata *u) {
|
||||||
|
|
||||||
|
if (u->source)
|
||||||
|
pa_source_unlink(u->source);
|
||||||
|
|
||||||
|
if (u->thread) {
|
||||||
|
pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
|
||||||
|
pa_thread_free(u->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_thread_mq_done(&u->thread_mq);
|
||||||
|
|
||||||
|
if (u->source)
|
||||||
|
pa_source_unref(u->source);
|
||||||
|
|
||||||
|
if (u->memchunk.memblock)
|
||||||
|
pa_memblock_unref(u->memchunk.memblock);
|
||||||
|
|
||||||
|
if (u->hw_module && u->stream)
|
||||||
|
u->hw_module->device->close_input_stream(u->hw_module->device, u->stream);
|
||||||
|
|
||||||
|
// Stand alone source
|
||||||
|
if (!u->card && u->hw_module)
|
||||||
|
pa_droid_hw_module_close(u->hw_module);
|
||||||
|
|
||||||
|
if (u->config)
|
||||||
|
pa_xfree(u->config);
|
||||||
|
|
||||||
|
pa_xfree(u);
|
||||||
|
}
|
||||||
54
src/droid/droid-source.h
Normal file
54
src/droid/droid-source.h
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef foodroidsourcefoo
|
||||||
|
#define foodroidsourcefoo
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/source.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
#include <pulsecore/card.h>
|
||||||
|
|
||||||
|
#include "droid-util.h"
|
||||||
|
|
||||||
|
pa_source *pa_droid_source_new(pa_module *m,
|
||||||
|
pa_modargs *ma,
|
||||||
|
const char *driver,
|
||||||
|
pa_droid_hw_module *hw_module,
|
||||||
|
pa_droid_mapping *am,
|
||||||
|
pa_card *card);
|
||||||
|
void pa_droid_source_free(pa_source *s);
|
||||||
|
|
||||||
|
#endif
|
||||||
267
src/droid/droid-util-41qc.h
Normal file
267
src/droid/droid-util-41qc.h
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ANDROID_UTIL_V412_H_
|
||||||
|
#define _ANDROID_UTIL_V412_H_
|
||||||
|
|
||||||
|
// PulseAudio value - Android value
|
||||||
|
|
||||||
|
static uint32_t conversion_table_output_channel[][2] = {
|
||||||
|
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_OUT_MONO },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_OUT_FRONT_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_OUT_FRONT_RIGHT},
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_OUT_FRONT_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_SUBWOOFER, AUDIO_CHANNEL_OUT_LOW_FREQUENCY },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_LEFT, AUDIO_CHANNEL_OUT_BACK_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_RIGHT, AUDIO_CHANNEL_OUT_BACK_RIGHT },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_OUT_BACK_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_SIDE_LEFT, AUDIO_CHANNEL_OUT_SIDE_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_SIDE_RIGHT, AUDIO_CHANNEL_OUT_SIDE_RIGHT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_CENTER, AUDIO_CHANNEL_OUT_TOP_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_FRONT_LEFT, AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_FRONT_CENTER, AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_REAR_LEFT, AUDIO_CHANNEL_OUT_TOP_BACK_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_REAR_CENTER, AUDIO_CHANNEL_OUT_TOP_BACK_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_REAR_RIGHT, AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT }
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t conversion_table_input_channel[][2] = {
|
||||||
|
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_MONO },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT},
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_IN_FRONT },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_IN_BACK },
|
||||||
|
/* Following are missing suitable counterparts on PulseAudio side. */
|
||||||
|
{ AUDIO_CHANNEL_IN_LEFT_PROCESSED, AUDIO_CHANNEL_IN_LEFT_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_RIGHT_PROCESSED, AUDIO_CHANNEL_IN_RIGHT_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_FRONT_PROCESSED, AUDIO_CHANNEL_IN_FRONT_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_BACK_PROCESSED, AUDIO_CHANNEL_IN_BACK_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_PRESSURE, AUDIO_CHANNEL_IN_PRESSURE },
|
||||||
|
{ AUDIO_CHANNEL_IN_X_AXIS, AUDIO_CHANNEL_IN_X_AXIS },
|
||||||
|
{ AUDIO_CHANNEL_IN_Y_AXIS, AUDIO_CHANNEL_IN_Y_AXIS },
|
||||||
|
{ AUDIO_CHANNEL_IN_Z_AXIS, AUDIO_CHANNEL_IN_Z_AXIS },
|
||||||
|
{ AUDIO_CHANNEL_IN_VOICE_UPLINK, AUDIO_CHANNEL_IN_VOICE_UPLINK },
|
||||||
|
{ AUDIO_CHANNEL_IN_VOICE_DNLINK, AUDIO_CHANNEL_IN_VOICE_DNLINK }
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t conversion_table_format[][2] = {
|
||||||
|
{ PA_SAMPLE_U8, AUDIO_FORMAT_PCM_8_BIT },
|
||||||
|
{ PA_SAMPLE_S16LE, AUDIO_FORMAT_PCM_16_BIT },
|
||||||
|
{ PA_SAMPLE_S32LE, AUDIO_FORMAT_PCM_32_BIT },
|
||||||
|
{ PA_SAMPLE_S24LE, AUDIO_FORMAT_PCM_8_24_BIT }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string_conversion {
|
||||||
|
uint32_t value;
|
||||||
|
const char *str;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(STRING_ENTRY) || defined(STRING_ENTRY)
|
||||||
|
#error STRING_ENTRY already defined somewhere, fix this lib.
|
||||||
|
#endif
|
||||||
|
#define STRING_ENTRY(str) { str, #str }
|
||||||
|
/* Output devices */
|
||||||
|
static struct string_conversion string_conversion_table_output_device[] = {
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_EARPIECE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_SPEAKER),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_AUX_DIGITAL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_ACCESSORY),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_DEVICE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_FM),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_FM_TX),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ANC_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ANC_HEADPHONE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_PROXY),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_A2DP),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_SCO),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_USB),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct string_conversion string_conversion_table_output_device_fancy[] = {
|
||||||
|
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
|
||||||
|
{ AUDIO_DEVICE_OUT_SPEAKER, "output-speaker" },
|
||||||
|
{ AUDIO_DEVICE_OUT_WIRED_HEADSET, "output-wired_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "output-sco_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "output-sco_carkit" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "output-a2dp" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "output-a2dp_headphones" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "output-a2dp_speaker" },
|
||||||
|
{ AUDIO_DEVICE_OUT_AUX_DIGITAL, "output-aux_digital" },
|
||||||
|
{ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "output-analog_dock_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "output-digital_dock_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
|
||||||
|
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Input devices */
|
||||||
|
static struct string_conversion string_conversion_table_input_device[] = {
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_COMMUNICATION),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_AMBIENT),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_BUILTIN_MIC),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_WIRED_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_AUX_DIGITAL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_VOICE_CALL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_BACK_MIC),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_ANC_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_FM_RX),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_FM_RX_A2DP),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_PROXY),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct string_conversion string_conversion_table_input_device_fancy[] = {
|
||||||
|
{ AUDIO_DEVICE_IN_COMMUNICATION, "input-in_communication" },
|
||||||
|
{ AUDIO_DEVICE_IN_AMBIENT, "input-ambient" },
|
||||||
|
{ AUDIO_DEVICE_IN_BUILTIN_MIC, "input-builtin_mic" },
|
||||||
|
{ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "input-bluetooth_sco_headset" },
|
||||||
|
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
|
||||||
|
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
|
||||||
|
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
|
||||||
|
{ AUDIO_DEVICE_IN_BACK_MIC, "input-back_mic" },
|
||||||
|
{ AUDIO_DEVICE_IN_ANC_HEADSET, "input-anc_headset" },
|
||||||
|
{ AUDIO_DEVICE_IN_FM_RX, "input-fm_rx" },
|
||||||
|
{ AUDIO_DEVICE_IN_FM_RX_A2DP, "input-fm_rx_a2dp" },
|
||||||
|
{ AUDIO_DEVICE_IN_PROXY, "input-in_proxy" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flags */
|
||||||
|
static struct string_conversion string_conversion_table_flag[] = {
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_NONE),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DIRECT),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_PRIMARY),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_FAST),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
|
||||||
|
/* Qualcomm flags */
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_LPA),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_TUNNEL),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_VOIP_RX),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Channels */
|
||||||
|
static struct string_conversion string_conversion_table_output_channels[] = {
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_STEREO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_QUAD),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_SURROUND),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_5POINT1),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
static struct string_conversion string_conversion_table_input_channels[] = {
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_PRESSURE),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_X_AXIS),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_Y_AXIS),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_Z_AXIS),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_UPLINK),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_DNLINK),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_STEREO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_5POINT1),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_CALL_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_ALL),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Formats */
|
||||||
|
static struct string_conversion string_conversion_table_format[] = {
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_DEFAULT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_MP3),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AMR_NB),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AMR_WB),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AAC),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V1),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V2),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_VORBIS),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_EVRC),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_QCELP),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AC3),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AC3_PLUS),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_DTS),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_WMA),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_WMA_PRO),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AAC_ADIF),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_EVRCB),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_EVRCWB),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_EAC3),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_DTS_LBR),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AMR_WB_PLUS),
|
||||||
|
/* Currently we support only PCM formats, but keep all formats
|
||||||
|
* here so audio_policy.conf can be parsed. */
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_16_BIT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_8_BIT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_32_BIT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_8_24_BIT),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
#undef STRING_ENTRY
|
||||||
|
|
||||||
|
#endif
|
||||||
273
src/droid/droid-util-42.h
Normal file
273
src/droid/droid-util-42.h
Normal file
|
|
@ -0,0 +1,273 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ANDROID_UTIL_V42_H_
|
||||||
|
#define _ANDROID_UTIL_V42_H_
|
||||||
|
|
||||||
|
#define HAL_V2
|
||||||
|
|
||||||
|
// PulseAudio value - Android value
|
||||||
|
|
||||||
|
static uint32_t conversion_table_output_channel[][2] = {
|
||||||
|
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_OUT_MONO },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_OUT_FRONT_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_OUT_FRONT_RIGHT},
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_OUT_FRONT_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_SUBWOOFER, AUDIO_CHANNEL_OUT_LOW_FREQUENCY },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_LEFT, AUDIO_CHANNEL_OUT_BACK_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_RIGHT, AUDIO_CHANNEL_OUT_BACK_RIGHT },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_OUT_BACK_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_SIDE_LEFT, AUDIO_CHANNEL_OUT_SIDE_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_SIDE_RIGHT, AUDIO_CHANNEL_OUT_SIDE_RIGHT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_CENTER, AUDIO_CHANNEL_OUT_TOP_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_FRONT_LEFT, AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_FRONT_CENTER, AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_REAR_LEFT, AUDIO_CHANNEL_OUT_TOP_BACK_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_REAR_CENTER, AUDIO_CHANNEL_OUT_TOP_BACK_CENTER },
|
||||||
|
{ PA_CHANNEL_POSITION_TOP_REAR_RIGHT, AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT }
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t conversion_table_input_channel[][2] = {
|
||||||
|
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_MONO },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT },
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT},
|
||||||
|
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_IN_FRONT },
|
||||||
|
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_IN_BACK },
|
||||||
|
/* Following are missing suitable counterparts on PulseAudio side. */
|
||||||
|
{ AUDIO_CHANNEL_IN_LEFT_PROCESSED, AUDIO_CHANNEL_IN_LEFT_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_RIGHT_PROCESSED, AUDIO_CHANNEL_IN_RIGHT_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_FRONT_PROCESSED, AUDIO_CHANNEL_IN_FRONT_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_BACK_PROCESSED, AUDIO_CHANNEL_IN_BACK_PROCESSED },
|
||||||
|
{ AUDIO_CHANNEL_IN_PRESSURE, AUDIO_CHANNEL_IN_PRESSURE },
|
||||||
|
{ AUDIO_CHANNEL_IN_X_AXIS, AUDIO_CHANNEL_IN_X_AXIS },
|
||||||
|
{ AUDIO_CHANNEL_IN_Y_AXIS, AUDIO_CHANNEL_IN_Y_AXIS },
|
||||||
|
{ AUDIO_CHANNEL_IN_Z_AXIS, AUDIO_CHANNEL_IN_Z_AXIS },
|
||||||
|
{ AUDIO_CHANNEL_IN_VOICE_UPLINK, AUDIO_CHANNEL_IN_VOICE_UPLINK },
|
||||||
|
{ AUDIO_CHANNEL_IN_VOICE_DNLINK, AUDIO_CHANNEL_IN_VOICE_DNLINK }
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t conversion_table_format[][2] = {
|
||||||
|
{ PA_SAMPLE_U8, AUDIO_FORMAT_PCM_8_BIT },
|
||||||
|
{ PA_SAMPLE_S16LE, AUDIO_FORMAT_PCM_16_BIT },
|
||||||
|
{ PA_SAMPLE_S32LE, AUDIO_FORMAT_PCM_32_BIT },
|
||||||
|
{ PA_SAMPLE_S24LE, AUDIO_FORMAT_PCM_8_24_BIT }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string_conversion {
|
||||||
|
uint32_t value;
|
||||||
|
const char *str;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(STRING_ENTRY)
|
||||||
|
#error STRING_ENTRY already defined somewhere, fix this lib.
|
||||||
|
#endif
|
||||||
|
#define STRING_ENTRY(str) { str, #str }
|
||||||
|
/* Output devices */
|
||||||
|
static struct string_conversion string_conversion_table_output_device[] = {
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_EARPIECE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_SPEAKER),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_AUX_DIGITAL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_ACCESSORY),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_DEVICE),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_DEFAULT),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_A2DP),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_SCO),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_USB),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct string_conversion string_conversion_table_output_device_fancy[] = {
|
||||||
|
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
|
||||||
|
{ AUDIO_DEVICE_OUT_SPEAKER, "output-speaker" },
|
||||||
|
{ AUDIO_DEVICE_OUT_WIRED_HEADSET, "output-wired_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "output-sco_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "output-sco_carkit" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "output-a2dp" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "output-a2dp_headphones" },
|
||||||
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "output-a2dp_speaker" },
|
||||||
|
{ AUDIO_DEVICE_OUT_AUX_DIGITAL, "output-aux_digital" },
|
||||||
|
{ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "output-analog_dock_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "output-digital_dock_headset" },
|
||||||
|
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
|
||||||
|
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
|
||||||
|
{ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "output-remote_submix" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Input devices */
|
||||||
|
#ifdef MAKO
|
||||||
|
static struct string_conversion string_conversion_table_input_device[] = {
|
||||||
|
{ 0x10000, "AUDIO_DEVICE_IN_COMMUNICATION" },
|
||||||
|
{ 0x20000, "AUDIO_DEVICE_IN_AMBIENT" },
|
||||||
|
{ 0x40000, "AUDIO_DEVICE_IN_BUILTIN_MIC" },
|
||||||
|
{ 0x80000, "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" },
|
||||||
|
{ 0x100000, "AUDIO_DEVICE_IN_WIRED_HEADSET" },
|
||||||
|
{ 0x200000, "AUDIO_DEVICE_IN_AUX_DIGITAL" },
|
||||||
|
{ 0x400000, "AUDIO_DEVICE_IN_VOICE_CALL" },
|
||||||
|
{ 0x800000, "AUDIO_DEVICE_IN_BACK_MIC" },
|
||||||
|
{ 0x80000000, "AUDIO_DEVICE_IN_DEFAULT" },
|
||||||
|
{ 0x80000000, "AUDIO_DEVICE_IN_REMOTE_SUBMIX" }, // What's this really??
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct string_conversion string_conversion_table_input_device_fancy[] = {
|
||||||
|
{ 0x10000, "input-communication" },
|
||||||
|
{ 0x20000, "input-ambient" },
|
||||||
|
{ 0x40000, "input-builtin_mic" },
|
||||||
|
{ 0x80000, "input-bluetooth_sco_headset" },
|
||||||
|
{ 0x100000, "input-wired_headset" },
|
||||||
|
{ 0x200000, "input-aux_digital" },
|
||||||
|
{ 0x400000, "input-voice_call" },
|
||||||
|
{ 0x800000, "input-back_mic" },
|
||||||
|
{ 0x80000000, "input-remote_submix" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static struct string_conversion string_conversion_table_input_device[] = {
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_COMMUNICATION),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_AMBIENT),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_BUILTIN_MIC),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_WIRED_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_AUX_DIGITAL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_VOICE_CALL),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_BACK_MIC),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_USB_ACCESSORY),
|
||||||
|
STRING_ENTRY(AUDIO_DEVICE_IN_USB_DEVICE),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct string_conversion string_conversion_table_input_device_fancy[] = {
|
||||||
|
{ AUDIO_DEVICE_IN_COMMUNICATION, "input-communication" },
|
||||||
|
{ AUDIO_DEVICE_IN_AMBIENT, "input-ambient" },
|
||||||
|
{ AUDIO_DEVICE_IN_BUILTIN_MIC, "input-builtin_mic" },
|
||||||
|
{ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "input-bluetooth_sco_headset" },
|
||||||
|
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
|
||||||
|
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
|
||||||
|
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
|
||||||
|
{ AUDIO_DEVICE_IN_BACK_MIC, "input-back_mic" },
|
||||||
|
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "input-remote_submix" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Flags */
|
||||||
|
static struct string_conversion string_conversion_table_flag[] = {
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_NONE),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DIRECT),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_PRIMARY),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_FAST),
|
||||||
|
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Channels */
|
||||||
|
static struct string_conversion string_conversion_table_output_channels[] = {
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_STEREO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_QUAD),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_SURROUND),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_5POINT1),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
static struct string_conversion string_conversion_table_input_channels[] = {
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK_PROCESSED),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_PRESSURE),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_X_AXIS),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_Y_AXIS),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_Z_AXIS),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_UPLINK),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_DNLINK),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_MONO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_STEREO),
|
||||||
|
STRING_ENTRY(AUDIO_CHANNEL_IN_ALL),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Formats */
|
||||||
|
static struct string_conversion string_conversion_table_format[] = {
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_DEFAULT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_MP3),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AMR_NB),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AMR_WB),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_AAC),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V1),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V2),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_VORBIS),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_MAIN_MASK),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_SUB_MASK),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_16_BIT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_8_BIT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_32_BIT),
|
||||||
|
STRING_ENTRY(AUDIO_FORMAT_PCM_8_24_BIT),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
#undef STRING_ENTRY
|
||||||
|
|
||||||
|
#endif
|
||||||
1028
src/droid/droid-util.c
Normal file
1028
src/droid/droid-util.c
Normal file
File diff suppressed because it is too large
Load diff
227
src/droid/droid-util.h
Normal file
227
src/droid/droid-util.h
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
#ifndef foodroidutilfoo
|
||||||
|
#define foodroidutilfoo
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <pulsecore/core-util.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
|
||||||
|
#include <hardware/audio.h>
|
||||||
|
#include <hardware_legacy/audio_policy_conf.h>
|
||||||
|
|
||||||
|
#define PROP_DROID_DEVICES "droid.devices"
|
||||||
|
#define PROP_DROID_FLAGS "droid.flags"
|
||||||
|
#define PROP_DROID_HW_MODULE "droid.hw_module"
|
||||||
|
|
||||||
|
typedef struct pa_droid_hw_module pa_droid_hw_module;
|
||||||
|
typedef void (*common_set_parameters_cb_t)(pa_droid_hw_module *module, const char *str);
|
||||||
|
|
||||||
|
typedef struct pa_droid_config_audio pa_droid_config_audio;
|
||||||
|
typedef struct pa_droid_config_hw_module pa_droid_config_hw_module;
|
||||||
|
|
||||||
|
struct pa_droid_hw_module {
|
||||||
|
void *userdata;
|
||||||
|
|
||||||
|
pa_droid_config_audio *config;
|
||||||
|
const pa_droid_config_hw_module *enabled_module;
|
||||||
|
|
||||||
|
struct hw_module_t *hwmod;
|
||||||
|
audio_hw_device_t *device;
|
||||||
|
|
||||||
|
const char *module_id;
|
||||||
|
|
||||||
|
uint32_t stream_out_id;
|
||||||
|
uint32_t stream_in_id;
|
||||||
|
|
||||||
|
/* General functions */
|
||||||
|
common_set_parameters_cb_t set_parameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AUDIO_MAX_SAMPLING_RATES (32)
|
||||||
|
#define AUDIO_MAX_HW_MODULES (8)
|
||||||
|
#define AUDIO_MAX_INPUTS (8)
|
||||||
|
#define AUDIO_MAX_OUTPUTS (8)
|
||||||
|
|
||||||
|
typedef struct pa_droid_config_global {
|
||||||
|
audio_devices_t attached_output_devices;
|
||||||
|
audio_devices_t default_output_device;
|
||||||
|
audio_devices_t attached_input_devices;
|
||||||
|
} pa_droid_config_global;
|
||||||
|
|
||||||
|
typedef struct pa_droid_config_output {
|
||||||
|
const pa_droid_config_hw_module *module;
|
||||||
|
|
||||||
|
char name[AUDIO_HARDWARE_MODULE_ID_MAX_LEN];
|
||||||
|
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
|
||||||
|
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
|
||||||
|
audio_format_t formats;
|
||||||
|
audio_devices_t devices;
|
||||||
|
audio_output_flags_t flags;
|
||||||
|
} pa_droid_config_output;
|
||||||
|
|
||||||
|
typedef struct pa_droid_config_input {
|
||||||
|
const pa_droid_config_hw_module *module;
|
||||||
|
|
||||||
|
char name[AUDIO_HARDWARE_MODULE_ID_MAX_LEN];
|
||||||
|
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
|
||||||
|
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
|
||||||
|
audio_format_t formats;
|
||||||
|
audio_devices_t devices;
|
||||||
|
} pa_droid_config_input;
|
||||||
|
|
||||||
|
struct pa_droid_config_hw_module {
|
||||||
|
const pa_droid_config_audio *config;
|
||||||
|
|
||||||
|
char name[AUDIO_HARDWARE_MODULE_ID_MAX_LEN];
|
||||||
|
pa_droid_config_output outputs[AUDIO_MAX_OUTPUTS];
|
||||||
|
uint32_t outputs_size;
|
||||||
|
pa_droid_config_input inputs[AUDIO_MAX_INPUTS];
|
||||||
|
uint32_t inputs_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pa_droid_config_audio {
|
||||||
|
pa_droid_config_global global_config;
|
||||||
|
pa_droid_config_hw_module hw_modules[AUDIO_MAX_HW_MODULES];
|
||||||
|
uint32_t hw_modules_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Profiles */
|
||||||
|
|
||||||
|
typedef struct pa_droid_profile_set pa_droid_profile_set;
|
||||||
|
typedef struct pa_droid_mapping pa_droid_mapping;
|
||||||
|
|
||||||
|
typedef struct pa_droid_port_data {
|
||||||
|
audio_devices_t device;
|
||||||
|
} pa_droid_port_data;
|
||||||
|
|
||||||
|
typedef struct pa_droid_port {
|
||||||
|
pa_droid_mapping *mapping;
|
||||||
|
|
||||||
|
audio_devices_t device;
|
||||||
|
char *name;
|
||||||
|
char *description;
|
||||||
|
unsigned priority;
|
||||||
|
} pa_droid_port;
|
||||||
|
|
||||||
|
struct pa_droid_mapping {
|
||||||
|
pa_droid_profile_set *profile_set;
|
||||||
|
|
||||||
|
const pa_droid_config_output *output;
|
||||||
|
const pa_droid_config_input *input;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
char *description;
|
||||||
|
unsigned priority;
|
||||||
|
pa_proplist *proplist;
|
||||||
|
|
||||||
|
/* Mapping doesn't own the ports */
|
||||||
|
pa_idxset *ports;
|
||||||
|
|
||||||
|
pa_direction_t direction;
|
||||||
|
|
||||||
|
pa_sink *sink;
|
||||||
|
pa_source *source;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct pa_droid_profile {
|
||||||
|
pa_droid_profile_set *profile_set;
|
||||||
|
|
||||||
|
const pa_droid_config_hw_module *module;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
char *description;
|
||||||
|
unsigned priority;
|
||||||
|
|
||||||
|
/* Profile doesn't own the mappings */
|
||||||
|
pa_droid_mapping *output;
|
||||||
|
pa_droid_mapping *input;
|
||||||
|
|
||||||
|
} pa_droid_profile;
|
||||||
|
|
||||||
|
struct pa_droid_profile_set {
|
||||||
|
const pa_droid_config_audio *config;
|
||||||
|
|
||||||
|
pa_hashmap *all_ports;
|
||||||
|
pa_hashmap *output_mappings;
|
||||||
|
pa_hashmap *input_mappings;
|
||||||
|
pa_hashmap *profiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Open hardware module */
|
||||||
|
pa_droid_hw_module *pa_droid_hw_module_open(pa_droid_config_audio *config, const char *module_id, void *userdata);
|
||||||
|
void pa_droid_hw_module_close(pa_droid_hw_module *hw);
|
||||||
|
|
||||||
|
/* Conversion helpers */
|
||||||
|
typedef enum {
|
||||||
|
CONV_FROM_PA,
|
||||||
|
CONV_FROM_HAL
|
||||||
|
} pa_conversion_field_t;
|
||||||
|
|
||||||
|
pa_bool_t pa_convert_output_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||||
|
pa_bool_t pa_convert_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||||
|
pa_bool_t pa_convert_format(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||||
|
|
||||||
|
pa_bool_t pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str);
|
||||||
|
pa_bool_t pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t *to_value);
|
||||||
|
pa_bool_t pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str);
|
||||||
|
pa_bool_t pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t *to_value);
|
||||||
|
|
||||||
|
pa_bool_t pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str);
|
||||||
|
pa_bool_t pa_string_convert_flag_str_to_num(const char *str, audio_output_flags_t *to_value);
|
||||||
|
|
||||||
|
char *pa_list_string_output_device(audio_devices_t devices);
|
||||||
|
char *pa_list_string_input_device(audio_devices_t devices);
|
||||||
|
char *pa_list_string_flags(audio_output_flags_t flags);
|
||||||
|
|
||||||
|
/* Config parser */
|
||||||
|
pa_bool_t pa_parse_droid_audio_config(const char *filename, pa_droid_config_audio *config);
|
||||||
|
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma);
|
||||||
|
|
||||||
|
const pa_droid_config_output *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char *name);
|
||||||
|
const pa_droid_config_input *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char *name);
|
||||||
|
const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id);
|
||||||
|
|
||||||
|
|
||||||
|
/* Profiles */
|
||||||
|
pa_droid_profile_set *pa_droid_profile_set_new(const pa_droid_config_hw_module *module);
|
||||||
|
void pa_droid_profile_set_free(pa_droid_profile_set *ps);
|
||||||
|
|
||||||
|
pa_droid_profile *pa_droid_profile_new(pa_droid_profile_set *ps, const pa_droid_config_output *output, const pa_droid_config_input *input);
|
||||||
|
void pa_droid_profile_free(pa_droid_profile *p);
|
||||||
|
|
||||||
|
pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, pa_direction_t direction, const void *data);
|
||||||
|
void pa_droid_mapping_free(pa_droid_mapping *am);
|
||||||
|
|
||||||
|
/* Add ports from sinks/sources */
|
||||||
|
void pa_droid_add_ports(pa_hashmap **p, pa_droid_mapping *am, pa_card *card);
|
||||||
|
/* Add ports from card */
|
||||||
|
void pa_droid_add_card_ports(pa_card_profile *cp, pa_hashmap *ports, pa_droid_mapping *am, pa_core *core);
|
||||||
|
|
||||||
|
/* Pretty port names */
|
||||||
|
pa_bool_t pa_droid_output_port_name(audio_devices_t value, const char **to_str);
|
||||||
|
pa_bool_t pa_droid_input_port_name(audio_devices_t value, const char **to_str);
|
||||||
|
|
||||||
|
#endif
|
||||||
42
src/droid/module-droid-card-symdef.h
Normal file
42
src/droid/module-droid-card-symdef.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
#ifndef foomoduledroidcardsymdeffoo
|
||||||
|
#define foomoduledroidcardsymdeffoo
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
|
||||||
|
#define pa__init module_droid_card_LTX_pa__init
|
||||||
|
#define pa__done module_droid_card_LTX_pa__done
|
||||||
|
#define pa__get_author module_droid_card_LTX_pa__get_author
|
||||||
|
#define pa__get_description module_droid_card_LTX_pa__get_description
|
||||||
|
#define pa__get_usage module_droid_card_LTX_pa__get_usage
|
||||||
|
#define pa__get_version module_droid_card_LTX_pa__get_version
|
||||||
|
|
||||||
|
int pa__init(struct pa_module*m);
|
||||||
|
void pa__done(struct pa_module*m);
|
||||||
|
|
||||||
|
const char* pa__get_author(void);
|
||||||
|
const char* pa__get_description(void);
|
||||||
|
const char* pa__get_usage(void);
|
||||||
|
const char* pa__get_version(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
516
src/droid/module-droid-card.c
Normal file
516
src/droid/module-droid-card.c
Normal file
|
|
@ -0,0 +1,516 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/rtclock.h>
|
||||||
|
#include <pulse/timeval.h>
|
||||||
|
#include <pulse/volume.h>
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/memchunk.h>
|
||||||
|
#include <pulsecore/sink.h>
|
||||||
|
#include <pulsecore/source.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/core-rtclock.h>
|
||||||
|
#include <pulsecore/core-util.h>
|
||||||
|
#include <pulsecore/sample-util.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
#include <pulsecore/thread.h>
|
||||||
|
#include <pulsecore/thread-mq.h>
|
||||||
|
#include <pulsecore/rtpoll.h>
|
||||||
|
#include <pulsecore/time-smoother.h>
|
||||||
|
#include <pulsecore/card.h>
|
||||||
|
#include <pulsecore/device-port.h>
|
||||||
|
#include <pulsecore/idxset.h>
|
||||||
|
|
||||||
|
#include <hardware/audio.h>
|
||||||
|
#include <system/audio.h>
|
||||||
|
|
||||||
|
//#include <droid/hardware/audio_policy.h>
|
||||||
|
//#include <droid/system/audio_policy.h>
|
||||||
|
|
||||||
|
#include "droid-util.h"
|
||||||
|
#include "droid-sink.h"
|
||||||
|
#include "droid-source.h"
|
||||||
|
|
||||||
|
#include "module-droid-card-symdef.h"
|
||||||
|
|
||||||
|
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||||
|
PA_MODULE_DESCRIPTION("Droid card");
|
||||||
|
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||||
|
PA_MODULE_USAGE(
|
||||||
|
"card_name=<name for the card> "
|
||||||
|
"sink_name=<name for the sink> "
|
||||||
|
"source_name=<name for the source> "
|
||||||
|
"namereg_fail=<when false attempt to synthesise new names if they are already taken> "
|
||||||
|
"rate=<sample rate> "
|
||||||
|
"output_flags=<flags for sink> "
|
||||||
|
"module_id=<which droid hw module to load, default primary> "
|
||||||
|
"deferred_volume=<synchronize software and hardware volume changes to avoid momentary jumps?> "
|
||||||
|
"config=<location for droid audio configuration>"
|
||||||
|
);
|
||||||
|
|
||||||
|
static const char* const valid_modargs[] = {
|
||||||
|
"card_name",
|
||||||
|
"sink_name",
|
||||||
|
"source_name",
|
||||||
|
"namereg_fail",
|
||||||
|
"format",
|
||||||
|
"rate",
|
||||||
|
"output_flags",
|
||||||
|
"module_id",
|
||||||
|
"deferred_volume",
|
||||||
|
"config",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_MODULE_ID "primary"
|
||||||
|
#define DEFAULT_AUDIO_POLICY_CONF "/system/etc/audio_policy.conf"
|
||||||
|
#define VOICE_CALL_PROFILE_NAME "voicecall"
|
||||||
|
|
||||||
|
struct userdata {
|
||||||
|
pa_core *core;
|
||||||
|
pa_module *module;
|
||||||
|
|
||||||
|
pa_thread *thread;
|
||||||
|
pa_thread_mq thread_mq;
|
||||||
|
pa_rtpoll *rtpoll;
|
||||||
|
|
||||||
|
pa_droid_profile_set *profile_set;
|
||||||
|
|
||||||
|
pa_droid_config_audio *config;
|
||||||
|
pa_droid_hw_module *hw_module;
|
||||||
|
|
||||||
|
struct call_profile_data {
|
||||||
|
pa_droid_profile *profile;
|
||||||
|
pa_droid_profile *old_profile;
|
||||||
|
} call_profile;
|
||||||
|
|
||||||
|
pa_modargs *modargs;
|
||||||
|
pa_card *card;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct profile_data {
|
||||||
|
pa_droid_profile *profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void add_disabled_profile(pa_hashmap *profiles) {
|
||||||
|
pa_card_profile *cp;
|
||||||
|
struct profile_data *d;
|
||||||
|
|
||||||
|
cp = pa_card_profile_new("off", _("Off"), sizeof(struct profile_data));
|
||||||
|
|
||||||
|
d = PA_CARD_PROFILE_DATA(cp);
|
||||||
|
d->profile = NULL;
|
||||||
|
|
||||||
|
pa_hashmap_put(profiles, cp->name, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special profile for calls */
|
||||||
|
static void add_call_profile(struct userdata *u, pa_hashmap *profiles) {
|
||||||
|
pa_droid_profile *ap;
|
||||||
|
pa_card_profile *cp;
|
||||||
|
struct profile_data *d;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->profile_set);
|
||||||
|
|
||||||
|
pa_log_debug("New profile: %s", VOICE_CALL_PROFILE_NAME);
|
||||||
|
|
||||||
|
ap = pa_xnew0(pa_droid_profile, 1);
|
||||||
|
ap->profile_set = u->profile_set;
|
||||||
|
ap->name = pa_sprintf_malloc(VOICE_CALL_PROFILE_NAME);
|
||||||
|
ap->description = pa_sprintf_malloc("Call mode");
|
||||||
|
ap->priority = 50;
|
||||||
|
|
||||||
|
u->call_profile.profile = ap;
|
||||||
|
|
||||||
|
pa_hashmap_put(u->profile_set->profiles, ap->name, ap);
|
||||||
|
|
||||||
|
cp = pa_card_profile_new(ap->name, ap->description, sizeof(struct profile_data));
|
||||||
|
d = PA_CARD_PROFILE_DATA(cp);
|
||||||
|
d->profile = ap;
|
||||||
|
|
||||||
|
pa_hashmap_put(profiles, cp->name, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_parameters_cb(pa_droid_hw_module *module, const char *str) {
|
||||||
|
pa_assert(module);
|
||||||
|
pa_assert(str);
|
||||||
|
|
||||||
|
if (module->device)
|
||||||
|
module->device->set_parameters(module->device, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_card_name(pa_modargs *ma, pa_card_new_data *data, const char *module_id) {
|
||||||
|
const char *tmp;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
pa_assert(ma);
|
||||||
|
pa_assert(data);
|
||||||
|
pa_assert(module_id);
|
||||||
|
|
||||||
|
if ((tmp = pa_modargs_get_value(ma, "card_name", NULL))) {
|
||||||
|
pa_card_new_data_set_name(data, tmp);
|
||||||
|
data->namereg_fail = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = pa_sprintf_malloc("droid_card.%s", module_id);
|
||||||
|
pa_card_new_data_set_name(data, name);
|
||||||
|
pa_xfree(name);
|
||||||
|
data->namereg_fail = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_profile(struct userdata *u, pa_hashmap *h, pa_hashmap *ports, pa_droid_profile *ap) {
|
||||||
|
pa_card_profile *cp;
|
||||||
|
struct profile_data *d;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(h);
|
||||||
|
pa_assert(ports);
|
||||||
|
pa_assert(ap);
|
||||||
|
|
||||||
|
pa_log_debug("Card profile %s", ap->name);
|
||||||
|
|
||||||
|
cp = pa_card_profile_new(ap->name, ap->description, sizeof(struct profile_data));
|
||||||
|
cp->priority = ap->priority;
|
||||||
|
|
||||||
|
cp->n_sinks = 1;
|
||||||
|
pa_droid_add_card_ports(cp, ports, ap->output, u->core);
|
||||||
|
cp->max_sink_channels = popcount(ap->output->output->channel_masks);
|
||||||
|
if (ap->input) {
|
||||||
|
pa_droid_add_card_ports(cp, ports, ap->input, u->core);
|
||||||
|
cp->n_sources = 1;
|
||||||
|
cp->max_source_channels = popcount(ap->input->input->channel_masks);
|
||||||
|
}
|
||||||
|
|
||||||
|
d = PA_CARD_PROFILE_DATA(cp);
|
||||||
|
d->profile = ap;
|
||||||
|
|
||||||
|
pa_hashmap_put(h, cp->name, cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) {
|
||||||
|
void *state;
|
||||||
|
pa_droid_profile *ap;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(h);
|
||||||
|
|
||||||
|
PA_HASHMAP_FOREACH(ap, u->profile_set->profiles, state) {
|
||||||
|
add_profile(u, h, ports, ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_profile(struct userdata *u) {
|
||||||
|
pa_droid_mapping *am;
|
||||||
|
struct profile_data *d;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
pa_log_debug("Init profile.");
|
||||||
|
|
||||||
|
d = PA_CARD_PROFILE_DATA(u->card->active_profile);
|
||||||
|
|
||||||
|
if (d->profile && d->profile->output) {
|
||||||
|
am = d->profile->output;
|
||||||
|
am->sink = pa_droid_sink_new(u->module, u->modargs, __FILE__, u->hw_module, 0, am, u->card);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->profile && d->profile->input) {
|
||||||
|
am = d->profile->input;
|
||||||
|
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, u->hw_module, am, u->card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_call_mode(struct userdata *u, audio_mode_t mode) {
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->hw_module);
|
||||||
|
pa_assert(u->hw_module->device);
|
||||||
|
|
||||||
|
pa_log_debug("Set mode to %s.", mode == AUDIO_MODE_IN_CALL ? "AUDIO_MODE_IN_CALL" : "AUDIO_MODE_NORMAL");
|
||||||
|
|
||||||
|
if (u->hw_module->device->set_mode(u->hw_module->device, mode) < 0) {
|
||||||
|
pa_log("Failed to set mode.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
||||||
|
struct userdata *u;
|
||||||
|
pa_droid_mapping *am;
|
||||||
|
struct profile_data *nd, *od;
|
||||||
|
pa_queue *sink_inputs = NULL, *source_outputs = NULL;
|
||||||
|
|
||||||
|
pa_assert(c);
|
||||||
|
pa_assert(new_profile);
|
||||||
|
pa_assert_se(u = c->userdata);
|
||||||
|
|
||||||
|
nd = PA_CARD_PROFILE_DATA(new_profile);
|
||||||
|
od = PA_CARD_PROFILE_DATA(c->active_profile);
|
||||||
|
|
||||||
|
if (nd->profile == u->call_profile.profile) {
|
||||||
|
pa_assert(u->call_profile.old_profile == NULL);
|
||||||
|
|
||||||
|
set_call_mode(u, AUDIO_MODE_IN_CALL);
|
||||||
|
|
||||||
|
/* Transfer ownership of sinks and sources to
|
||||||
|
* call profile */
|
||||||
|
u->call_profile.old_profile = od->profile;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (od->profile == u->call_profile.profile) {
|
||||||
|
set_call_mode(u, AUDIO_MODE_NORMAL);
|
||||||
|
|
||||||
|
/* If new profile is the same as from which we switched to
|
||||||
|
* call profile, transfer ownership back to that profile.
|
||||||
|
* Otherwise destroy sinks & sources and switch to new profile. */
|
||||||
|
if (nd->profile == u->call_profile.old_profile) {
|
||||||
|
u->call_profile.old_profile = NULL;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
od->profile = u->call_profile.old_profile;
|
||||||
|
u->call_profile.old_profile = NULL;
|
||||||
|
|
||||||
|
/* Continue to sink-input transfer below */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there are connected sink inputs/source outputs in old profile's sinks/sources move
|
||||||
|
* them all to new sinks/sources. */
|
||||||
|
|
||||||
|
if (od->profile && od->profile->output) {
|
||||||
|
do {
|
||||||
|
am = od->profile->output;
|
||||||
|
|
||||||
|
if (!am->sink)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nd->profile && nd->profile->output && am == nd->profile->output)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sink_inputs = pa_sink_move_all_start(am->sink, sink_inputs);
|
||||||
|
pa_droid_sink_free(am->sink);
|
||||||
|
am->sink = NULL;
|
||||||
|
} while(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (od->profile && od->profile->input) {
|
||||||
|
do {
|
||||||
|
am = od->profile->input;
|
||||||
|
|
||||||
|
if (!am->source)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nd->profile && nd->profile->input && am == nd->profile->input)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
source_outputs = pa_source_move_all_start(am->source, source_outputs);
|
||||||
|
pa_droid_source_free(am->source);
|
||||||
|
am->source = NULL;
|
||||||
|
} while(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nd->profile && nd->profile->output) {
|
||||||
|
am = nd->profile->output;
|
||||||
|
|
||||||
|
if (!am->sink)
|
||||||
|
am->sink = pa_droid_sink_new(u->module, u->modargs, __FILE__, u->hw_module, 0, am, u->card);
|
||||||
|
|
||||||
|
if (sink_inputs && am->sink) {
|
||||||
|
pa_sink_move_all_finish(am->sink, sink_inputs, FALSE);
|
||||||
|
sink_inputs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nd->profile && nd->profile->input) {
|
||||||
|
am = nd->profile->input;
|
||||||
|
|
||||||
|
if (!am->source)
|
||||||
|
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, u->hw_module, am, u->card);
|
||||||
|
|
||||||
|
if (source_outputs && am->source) {
|
||||||
|
pa_source_move_all_finish(am->source, source_outputs, FALSE);
|
||||||
|
source_outputs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sink_inputs)
|
||||||
|
pa_sink_move_all_fail(sink_inputs);
|
||||||
|
|
||||||
|
if (source_outputs)
|
||||||
|
pa_source_move_all_fail(source_outputs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pa__init(pa_module *m) {
|
||||||
|
pa_modargs *ma = NULL;
|
||||||
|
pa_card_new_data data;
|
||||||
|
const char *module_id;
|
||||||
|
pa_bool_t namereg_fail = FALSE;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||||
|
pa_log("Failed to parse module argumets.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct userdata *u = pa_xnew0(struct userdata, 1);
|
||||||
|
u->core = m->core;
|
||||||
|
|
||||||
|
if (!(u->config = pa_droid_config_load(ma)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||||
|
|
||||||
|
if (!(u->hw_module = pa_droid_hw_module_open(u->config, module_id, u)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
u->hw_module->set_parameters = set_parameters_cb;
|
||||||
|
|
||||||
|
u->profile_set = pa_droid_profile_set_new(u->hw_module->enabled_module);
|
||||||
|
|
||||||
|
pa_card_new_data_init(&data);
|
||||||
|
data.driver = __FILE__;
|
||||||
|
data.module = m;
|
||||||
|
|
||||||
|
set_card_name(ma, &data, u->hw_module->module_id);
|
||||||
|
|
||||||
|
/* We need to give pa_modargs_get_value_boolean() a pointer to a local
|
||||||
|
* variable instead of using &data.namereg_fail directly, because
|
||||||
|
* data.namereg_fail is a bitfield and taking the address of a bitfield
|
||||||
|
* variable is impossible. */
|
||||||
|
namereg_fail = data.namereg_fail;
|
||||||
|
if (pa_modargs_get_value_boolean(ma, "namereg_fail", &namereg_fail) < 0) {
|
||||||
|
pa_log("Failed to parse namereg_fail argument.");
|
||||||
|
pa_card_new_data_done(&data);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
data.namereg_fail = namereg_fail;
|
||||||
|
|
||||||
|
/* FIXME hashmap_new not needed with 4.0 */
|
||||||
|
data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
|
||||||
|
add_profiles(u, data.profiles, data.ports);
|
||||||
|
|
||||||
|
if (pa_hashmap_isempty(data.profiles)) {
|
||||||
|
pa_log("Failed to find a working profile.");
|
||||||
|
pa_card_new_data_done(&data);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_call_profile(u, data.profiles);
|
||||||
|
|
||||||
|
add_disabled_profile(data.profiles);
|
||||||
|
|
||||||
|
pa_proplist_sets(data.proplist, PROP_DROID_HW_MODULE, u->hw_module->module_id);
|
||||||
|
|
||||||
|
u->card = pa_card_new(m->core, &data);
|
||||||
|
pa_card_new_data_done(&data);
|
||||||
|
|
||||||
|
if (!u->card) {
|
||||||
|
pa_log("Couldn't create card.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->card->userdata = u;
|
||||||
|
u->card->set_profile = card_set_profile;
|
||||||
|
|
||||||
|
u->modargs = ma;
|
||||||
|
u->module = m;
|
||||||
|
|
||||||
|
m->userdata = u;
|
||||||
|
|
||||||
|
init_profile(u);
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (ma)
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa__done(m);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa__done(pa_module *m) {
|
||||||
|
struct userdata *u;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if ((u = m->userdata)) {
|
||||||
|
|
||||||
|
/* FIXME _remove_all in 4.x */
|
||||||
|
if (u->card && u->card->sinks) {
|
||||||
|
pa_sink *s;
|
||||||
|
|
||||||
|
while ((s = pa_idxset_steal_first(u->card->sinks, NULL)))
|
||||||
|
pa_droid_sink_free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u->card && u->card->sources) {
|
||||||
|
pa_source *s;
|
||||||
|
|
||||||
|
while ((s = pa_idxset_steal_first(u->card->sources, NULL)))
|
||||||
|
pa_droid_source_free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (u->card)
|
||||||
|
pa_card_free(u->card);
|
||||||
|
|
||||||
|
if (u->modargs)
|
||||||
|
pa_modargs_free(u->modargs);
|
||||||
|
|
||||||
|
if (u->profile_set)
|
||||||
|
pa_droid_profile_set_free(u->profile_set);
|
||||||
|
|
||||||
|
if (u->hw_module)
|
||||||
|
pa_droid_hw_module_close(u->hw_module);
|
||||||
|
|
||||||
|
if (u->config)
|
||||||
|
pa_xfree(u->config);
|
||||||
|
|
||||||
|
pa_xfree(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/droid/module-droid-sink-symdef.h
Normal file
42
src/droid/module-droid-sink-symdef.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
#ifndef foomoduledroidsinksymdeffoo
|
||||||
|
#define foomoduledroidsinksymdeffoo
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
|
||||||
|
#define pa__init module_droid_sink_LTX_pa__init
|
||||||
|
#define pa__done module_droid_sink_LTX_pa__done
|
||||||
|
#define pa__get_author module_droid_sink_LTX_pa__get_author
|
||||||
|
#define pa__get_description module_droid_sink_LTX_pa__get_description
|
||||||
|
#define pa__get_usage module_droid_sink_LTX_pa__get_usage
|
||||||
|
#define pa__get_version module_droid_sink_LTX_pa__get_version
|
||||||
|
|
||||||
|
int pa__init(struct pa_module*m);
|
||||||
|
void pa__done(struct pa_module*m);
|
||||||
|
|
||||||
|
const char* pa__get_author(void);
|
||||||
|
const char* pa__get_description(void);
|
||||||
|
const char* pa__get_usage(void);
|
||||||
|
const char* pa__get_version(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
94
src/droid/module-droid-sink.c
Normal file
94
src/droid/module-droid-sink.c
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/sink.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
|
||||||
|
#include "droid-util.h"
|
||||||
|
#include "droid-sink.h"
|
||||||
|
|
||||||
|
#include "module-droid-sink-symdef.h"
|
||||||
|
|
||||||
|
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||||
|
PA_MODULE_DESCRIPTION("Droid sink");
|
||||||
|
PA_MODULE_USAGE("master_sink=<sink to connect to> "
|
||||||
|
"sink_name=<name of created sink>");
|
||||||
|
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||||
|
|
||||||
|
static const char* const valid_modargs[] = {
|
||||||
|
"rate",
|
||||||
|
"flags",
|
||||||
|
"devices",
|
||||||
|
"sink_name",
|
||||||
|
"module_id",
|
||||||
|
"deferred_volume",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void pa__done(pa_module *m) {
|
||||||
|
pa_sink *sink;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if ((sink = m->userdata))
|
||||||
|
pa_droid_sink_free(sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pa__init(pa_module *m) {
|
||||||
|
pa_modargs *ma = NULL;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||||
|
pa_log("Failed to parse module argumets.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(m->userdata = pa_droid_sink_new(m, ma, __FILE__, NULL, 0, NULL, NULL)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (ma)
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa__done(m);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
42
src/droid/module-droid-source-symdef.h
Normal file
42
src/droid/module-droid-source-symdef.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
#ifndef foomoduledroidsourcesymdeffoo
|
||||||
|
#define foomoduledroidsourcesymdeffoo
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
|
||||||
|
#define pa__init module_droid_source_LTX_pa__init
|
||||||
|
#define pa__done module_droid_source_LTX_pa__done
|
||||||
|
#define pa__get_author module_droid_source_LTX_pa__get_author
|
||||||
|
#define pa__get_description module_droid_source_LTX_pa__get_description
|
||||||
|
#define pa__get_usage module_droid_source_LTX_pa__get_usage
|
||||||
|
#define pa__get_version module_droid_source_LTX_pa__get_version
|
||||||
|
|
||||||
|
int pa__init(struct pa_module*m);
|
||||||
|
void pa__done(struct pa_module*m);
|
||||||
|
|
||||||
|
const char* pa__get_author(void);
|
||||||
|
const char* pa__get_description(void);
|
||||||
|
const char* pa__get_usage(void);
|
||||||
|
const char* pa__get_version(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
94
src/droid/module-droid-source.c
Normal file
94
src/droid/module-droid-source.c
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Jolla Ltd.
|
||||||
|
*
|
||||||
|
* Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
|
||||||
|
*
|
||||||
|
* These PulseAudio Modules are 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
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core.h>
|
||||||
|
#include <pulsecore/i18n.h>
|
||||||
|
#include <pulsecore/module.h>
|
||||||
|
#include <pulsecore/source.h>
|
||||||
|
#include <pulsecore/modargs.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/macro.h>
|
||||||
|
|
||||||
|
#include "droid-util.h"
|
||||||
|
#include "droid-source.h"
|
||||||
|
|
||||||
|
#include "module-droid-source-symdef.h"
|
||||||
|
|
||||||
|
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||||
|
PA_MODULE_DESCRIPTION("Droid source");
|
||||||
|
PA_MODULE_USAGE("master_source=<source to connect to> "
|
||||||
|
"source_name=<name of created source>");
|
||||||
|
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||||
|
|
||||||
|
static const char* const valid_modargs[] = {
|
||||||
|
"rate",
|
||||||
|
"flags",
|
||||||
|
"devices",
|
||||||
|
"source_name",
|
||||||
|
"module_id",
|
||||||
|
"deferred_volume",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void pa__done(pa_module *m) {
|
||||||
|
pa_source *source;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if ((source = m->userdata))
|
||||||
|
pa_droid_source_free(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pa__init(pa_module *m) {
|
||||||
|
pa_modargs *ma = NULL;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||||
|
pa_log("Failed to parse module argumets.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(m->userdata = pa_droid_source_new(m, ma, __FILE__, NULL, NULL, NULL)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (ma)
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa__done(m);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue